这是我想出的公式(在StackOverFlow的人们的帮助下):
(-1和1之间的随机数)*半径+(旧经度)=新经度旧经度半径
(-1和1之间的随机数)*半径+(旧纬度)=旧纬度半径内的新纬度
事情是奇怪的东西我的实现中发生的情况是因为所有随机位置都离我的位置中心太近,看来该公式不能覆盖整个半径。
我的公式有什么问题的任何想法吗?
经过编辑以显示当前的Java实现:
public static Location getLocation(Location location, int radius) {
Random random = new Random();
// Convert radius from meters to degrees
double radiusInDegrees = radius / METERS_IN_DEGREES;
double x0 = location.getLongitude() * 1E6;
double y0 = location.getLatitude() * 1E6;
double u = random.nextInt(1001) / 1000;
double v = random.nextInt(1001) / 1000;
double w = radiusInDegrees * Math.sqrt(u);
double t = 2 * Math.PI * v;
double x = w * Math.cos(t);
double y = w * Math.sin(t);
// Adjust the x-coordinate for the shrinking of the east-west distances
double new_x = x / Math.cos(y0);
// Set the adjusted location
Location newLocation = new Location("Loc in radius");
newLocation.setLongitude(new_x + x0);
newLocation.setLatitude(y + y0);
return newLocation;
}
我不确定自己在做什么错,因为新位置是在海中。
有什么主意吗?
#1 楼
这很棘手,原因有二:首先,将点限制为圆形而不是正方形。其次,要考虑到距离计算中的失真。许多GIS都具有自动透明地处理这两种并发症的功能。但是,此处的标记表明可能需要一种独立于GIS的算法描述。在一个位置(x0,y0)周围,首先在区间[0,1)中生成两个独立的统一随机值u和v。 (这几乎是每个随机数生成器都为您提供的功能。)计算
w = r * sqrt(u)
t = 2 * Pi * v
x = w * cos(t)
y = w * sin(t)
所需的随机点位于位置(x + x0,y + y0)。 />
使用地理(纬度,经度)坐标时,x0(经度)和y0(纬度)将以度为单位,而r最有可能以米(或英尺,英里或其他单位)为单位线性测量)。首先,将半径r转换为度数,就好像您位于赤道附近一样。在这里,大约有一个111,300米。
其次,在按照步骤(1)生成x和y之后,调整x坐标以缩小东西向距离:
x' = x / cos(y0)
所需的随机点位于位置(x'+ x0,y + y0)。这是一个大概的过程。对于不延伸到地球两极的小半径(小于几百公里),通常如此精确,即使在每个中心周围生成数以万计的随机点(x0,y0),也无法检测到任何误差。
评论
很棒的解释,这就是我需要知道的。现在我要实施它。谢谢
–针皮
2012年5月22日7:06
我编辑了问题以显示该公式的一些Java实现
–针皮
2012年5月22日晚上8:27
注意:“一个角度大约有111,300米”,逗号用作千位分隔符。 radiusInDegrees =半径/ 111300
–RMalke
2014年5月7日,0:51
对于纬度,长坐标,您不应该这样做x'= x / cos(y0 * Pi / 180)
– Aaron Stainback
16-3-26在2:43
介意@whuber,这很有意义。我猜想用另一种方式看待它,可以想象生成一个半径为20的55个随机半径。假设每个随机半径是均匀的,并且精确等于0到20,所以0、2、4,...,20因此,将有5个半径为5的点,半径为2的5,依此类推。5个半径为2的点(在半径2的圆周围)看起来比5个具有半径的点更接近之20
–azizj1
17-10-27在20:12
#2 楼
正确的实现是:public static void getLocation(double x0, double y0, int radius) {
Random random = new Random();
// Convert radius from meters to degrees
double radiusInDegrees = radius / 111000f;
double u = random.nextDouble();
double v = random.nextDouble();
double w = radiusInDegrees * Math.sqrt(u);
double t = 2 * Math.PI * v;
double x = w * Math.cos(t);
double y = w * Math.sin(t);
// Adjust the x-coordinate for the shrinking of the east-west distances
double new_x = x / Math.cos(Math.toRadians(y0));
double foundLongitude = new_x + x0;
double foundLatitude = y + y0;
System.out.println("Longitude: " + foundLongitude + " Latitude: " + foundLatitude );
}
我删除了对外部库的依赖,以使其更易于访问。
评论
提议的OP编辑根据此stackoverflow Q&A,在Java Math.cos()中,期望输入的弧度。
–MikeJRamsey56
16 Dec 12'在20:39
@atok:在删除它们之前,您实际上使用了哪些外部库?
– Benedikt Waldvogel
20年1月28日在7:30
#3 楼
针对Javascript实现:var r = 100/111300 // = 100 meters
, y0 = original_lat
, x0 = original_lng
, u = Math.random()
, v = Math.random()
, w = r * Math.sqrt(u)
, t = 2 * Math.PI * v
, x = w * Math.cos(t)
, y1 = w * Math.sin(t)
, x1 = x / Math.cos(y0)
newY = y0 + y1
newX = x0 + x1
#4 楼
接受的答案和派生对我不起作用。结果非常不准确。javascript中正确的实现: -我发现点分布在一个椭圆形中,其宽度是高度的1.5倍(在巴拿马)和高度的8倍(在瑞典北部)。如果我从@whuber的答案中删除了x坐标调整,则椭圆会以其他方式失真,比其宽度高8倍。
我的答案中的代码是基于此处的算法的br />下面您会看到两个jsfiddles,它们显示了拉伸椭圆的问题
正确的算法
变形的算法
评论
您对问题的描述表明您的实现不正确。
– hu
16年12月13日在22:17
您可能是正确的。您是否愿意看一下我制作的jsfiddles并告诉我哪里出错了。
–朱利安·曼(Julian Mann)
17年1月4日在15:34
我与上述atok的Java答案进行了比较,并在whuberPointAtDistance()中对失真算法的jsfiddle进行了更改:x1 =(w * Math.cos(t))/ Math.cos(y0 *(Math.PI / 180) )。
–马特
18年1月14日在23:34
尽管我进行了更正,但朱利安的要旨仍然使我获得了更为准确的结果。将我的更正添加到whuberPointAtDistance()并使用错误报告在要点中运行它们,它在所有三种情况下均显示0.05%的错误(明显高于替代方法)。
–马特
18 Mar 6 '18 at 4:13
#5 楼
在Python中# Testing simlation of generating random points
from __future__ import division
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import host_subplot
import mpl_toolkits.axisartist as AA
def create_random_point(x0,y0,distance):
"""
Utility method for simulation of the points
"""
r = distance/ 111300
u = np.random.uniform(0,1)
v = np.random.uniform(0,1)
w = r * np.sqrt(u)
t = 2 * np.pi * v
x = w * np.cos(t)
x1 = x / np.cos(y0)
y = w * np.sin(t)
return (x0+x1, y0 +y)
fig = plt.figure()
ax = host_subplot(111, axes_class=AA.Axes)
#ax.set_ylim(76,78)
#ax.set_xlim(13,13.1)
ax.set_autoscale_on(True)
latitude1,longitude1 = 13.04738626,77.61946793
ax.plot(latitude1,longitude1,'ro')
for i in range(1,20):
x,y = create_random_point(latitude1,longitude1 ,500 )
ax.plot(x,y,'bo')
dist = haversine(x,y,latitude1,longitude1)
print "Distance between points is " ,dist # a value approxiamtely less than 500 meters
plt.show()
输出
点之间的距离是0.288044147914
点之间的距离是0.409557451806
点之间的距离是0.368260305716
点间距离为0.340720560546
点间距离为0.453773334731
点间距离为0.460608754561
点间距离为0.497188825576
点间距离为0.603178188859
点之间的距离为0.628898384307
点之间的距离为0.416297587754
点之间的距离为0.503691568896
点之间的距离为0.175153349209
点之间的距离为0.195149463735
点之间的距离为0.424094009858
点间距离为0.286807741494
点间距离为0.558049206307
点间距离为0.498612171417
点间距离为0.047344718215
点间距离为0.484232497086
#6 楼
Swift的实现从geoencoder获取经纬度并将其传递给此函数
func generateRandomLocation(lat: CLLocationDegrees, lng: CLLocationDegrees){
let radius : Double = 100000 // this is in meters so 100 KM
let radiusInDegrees: Double = radius / 111000
let u : Double = Double(arc4random_uniform(100)) / 100.0
let v : Double = Double(arc4random_uniform(100)) / 100.0
let w : Double = radiusInDegrees * u.squareRoot()
let t : Double = 2 * Double.pi * v
let x : Double = w * cos(t)
let y : Double = w * sin(t)
// Adjust the x-coordinate for the shrinking of the east-west distances
//in cos converting degree to radian
let new_x : Double = x / cos(lat * .pi / 180 )
processedLat = new_x + lat
processedLng = y + lng
print("The Lat are :- ")
print(processedLat)
print("The Lng are :- ")
print(processedLng)
}
在上面的示例中,我得到了纬度和地理编码国家名称的经度,每次国家名称都给出相同的纬度和经度,也就是国家中部,因此我需要随机性。
#7 楼
您可以在此处检查计算结果。向下滚动到“目标点给定距离和起始点的方位”部分。甚至在底部有一个简单的JavaScript公式即可实现此目的。您仍然需要生成一个以弧度为单位的随机轴承$ \ theta $(从北向顺时针方向测量),尽管这应该很简单。这些公式假设使用球形地球(尽管它是椭圆形的),因为它产生的误差高达0.3%,因此足够好。#8 楼
PHP实现
function randomNearByCoord(array $coord, int $radiusKm, int $precision = 4): array
{
$radiusRad = $radiusKm/111.3;
$y0 = $coord['lat'];
$x0 = $coord['lon'];
$u = \lcg_value();
$v = \lcg_value();
$w = $radiusRad * \sqrt($u);
$t = 2 * M_PI * $v;
$x = $w * \cos($t);
$y1 = $w * \sin($t);
$x1 = $x / \cos(\deg2rad($y0));
$newY = \round($y0 + $y1, $precision);
$newX = \round($x0 + $x1, $precision);
return ['lat' => $newY, 'lon' => $newX];
}
$center = ['lat' => 51.5146, 'lon' => -0.1361];
$newCoord = randomNearByCoord($center, 5);
var_dump($newCoord);
#9 楼
private void drawPolyline(double lat,double lng){
double Pi=Math.PI;
double lt=lat;
double ln=lng;
//Earth’s radius, sphere
double R=6378137;
double dn = 50;
double de = 50;
//Coordinate offsets in radians
double dLat = dn/R;
double dLon = de/(R*Math.cos(Pi*lat/180));
//OffsetPosition, decimal degrees
double lat2 = lt + dLat * 180/Pi;
double lon2 = ln + dLon * 180/Pi ;
//12.987859, 80.231038
//12.987954, 80.231252
double lat3 = lt - dLat * 180/Pi;
double lon3 = ln - dLon * 180/Pi ;
LatLng origin=new LatLng(lt, lon3);
LatLng dest=new LatLng(lt, lon2);
Polyline line = googleMap.addPolyline(new PolylineOptions()
.add(origin, dest)
.width(6)
.color(Color.RED));
评论
您能否扩展一下如何解决OP问题并简要说明您的代码?
–马丁
2014年8月22日13:38
评论
您如何执行此公式?您可以显示这部分代码吗?可能是伪随机数生成器中的问题吗?就最后一个问题而言,这样的过程会遇到这样的问题,因为(i)距离被错误地转换为纬度或经度,并且(ii)坐标系的度量失真没有被考虑或被错误地考虑了。使用投影坐标系而不是地理坐标系通常可以解决这两个问题。这样做会暴露出公式的基本属性,这可能是您可能想要的,也可能不是您想要的:它会在一个位置周围的矩形内而不是圆形内生成位置。
谢谢亚历克斯,Java代码发布在stackoverflow上:stackoverflow.com/questions/10682743/…
重新编辑代码:(i)random.nextInt(1001)/ 1000将在大约0.1%的时间内返回大于1的值。为什么不使用random.nextDouble或random.nextFloat? (ii)将x0和y0乘以1E6是相当神秘的;它似乎不会产生正确的结果。
没错,我使用nextDouble编辑了方法,摆脱了1E6。现在,所有随机生成的位置都具有与我的位置相同的坐标。感谢您的帮助,看来我很快就会解决