我正在尝试生成位于半径为5公里的圆内的随机坐标(纬度,长度),其中心点位于某个坐标(x,y)处.我试图用红宝石编码,我正在使用该方法但不知何故,我得到的结果不在指定的5公里范围内.
def location(lat, lng, max_dist_meters)
max_radius = Math.sqrt((max_dist_meters ** 2) / 2.0)
lat_offset = rand(10 ** (Math.log10(max_radius / 1.11)-5))
lng_offset = rand(10 ** (Math.log10(max_radius / 1.11)-5))
lat += [1,-1].sample * lat_offset
lng += [1,-1].sample * lng_offset
lat = [[-90, lat].max, 90].min
lng = [[-180, lng].max, 180].min
[lat, lng]
end
Run Code Online (Sandbox Code Playgroud)
Eri*_*nil 11
max_radius = Math.sqrt((max_dist_meters ** 2) / 2.0)
Run Code Online (Sandbox Code Playgroud)
这只是max_dist_meters.abs / Math.sqrt(2)或max_dist_meters * 0.7071067811865475.
10 ** (Math.log10(max_radius / 1.11)-5)
Run Code Online (Sandbox Code Playgroud)
这可以写9.00901E-6 * max_radius,所以它6.370325E?6 * max_dist_meters.
rand(10 ** (Math.log10(max_radius / 1.11)-5))
Run Code Online (Sandbox Code Playgroud)
现在为有趣的部分:rand(x)就是rand()如果x介于-1和之间1.所以,如果max_dist_meters小于1/6.370325E?6 ~ 156977.86,你的所有3个第一行都是:
lat_offset = rand()
lng_offset = rand()
Run Code Online (Sandbox Code Playgroud)
因此,对于max_dist_meters = 5000,您的方法将返回一个随机点,该点可能是1°经度和1°纬度.最多,它将超过157公里.
更糟糕的是,如果x在156978和之间313955,您的代码相当于:
lat_offset = lng_offset = 0
Run Code Online (Sandbox Code Playgroud)
自Ruby 2.4起
[[-90, lat].max, 90].min
Run Code Online (Sandbox Code Playgroud)
要在半径磁盘上均匀分布随机点max_radius,您需要随机半径的非均匀分布:
def random_point_in_disk(max_radius)
r = max_radius * rand ** 0.5
theta = rand * 2 * Math::PI
[r * Math.cos(theta), r * Math.sin(theta)]
end
Run Code Online (Sandbox Code Playgroud)
这是一个有百万随机点的情节:
这是与@ Schwern代码相同的情节:
使用此方法后,您可以应用一些基本数学将米转换为纬度和经度.请记住,1°的纬度始终为111.2km,但1°的经度在赤道为111.2km,而在极地为0km:
def random_point_in_disk(max_radius)
r = max_radius * rand**0.5
theta = rand * 2 * Math::PI
[r * Math.cos(theta), r * Math.sin(theta)]
end
EarthRadius = 6371 # km
OneDegree = EarthRadius * 2 * Math::PI / 360 * 1000 # 1° latitude in meters
def random_location(lon, lat, max_radius)
dx, dy = random_point_in_disk(max_radius)
random_lat = lat + dy / OneDegree
random_lon = lon + dx / ( OneDegree * Math::cos(lat * Math::PI / 180) )
[random_lon, random_lat]
end
Run Code Online (Sandbox Code Playgroud)
对于这种计算,不需要安装800磅重的GIS大猩猩.
几点:
lon首先是因为x之前y.cos(lat)被认为是不变的所以max_radius不应该太大.几十公里不应该造成任何问题.球体上的圆盘形状变得很奇怪,半径很大.为了测试它,让我们在不同位置的200km磁盘上创建随机点:
10_000.times do
[-120, -60, 0, 60, 120].each do |lon|
[-85, -45, 0, 45, 85].each do |lat|
puts random_location(lon, lat, 200_000).join(' ')
end
end
end
Run Code Online (Sandbox Code Playgroud)
使用gnuplot,这是结果图:
好极了!我刚刚重新发明了天梭的指纹,已经晚了150年:
| 归档时间: |
|
| 查看次数: |
1607 次 |
| 最近记录: |