在原点的给定半径范围内和外部生成随机坐标

Posted

技术标签:

【中文标题】在原点的给定半径范围内和外部生成随机坐标【英文标题】:Generate random coordinates outside and within a given radius from origin 【发布时间】:2018-09-06 10:39:59 【问题描述】:

我需要为我的搜索引擎生成一个规范来测试,当我指定原点和半径时,超出我的源原点结果的结果不包含在响应中,而在给定半径内的半径(以公里为单位)是包括在内。

鉴于原点和半径,我想测试两个“极端”情况,我创建两个测试数据点,

一个内:在精确半径上减去一个 epsilon(半径 - e 远离原点) 一个外侧:在精确半径加上一个 epsilon(半径 + e 远离原点)

例如,如果我的半径是 10 公里,我想生成一个距离源头 10.1 公里和 9.9 公里的点。

然后,我想运行许多测试,在地球上选择随机点(半径内或半径外),以检查我的搜索引擎是否能很好地处理所有极端情况

我正在检查代码实际上是否适用于 Geocoder.distance_between

before do
  # Ensure our example is correct
  expect(
    Geocoder::Calculations.distance_between(origin, point_outside_radius_of_origin)
  ).to be > radius_in_km

  expect(
    Geocoder::Calculations.distance_between(origin, point_within_radius_of_origin)
  ).to be < radius_in_km
end

例如下面的固定示例通过

使用巴黎的固定示例

let(:origin)  [48.856614, 2.3522219]  # Geocoder.coordinates('Paris')
let(:radius_in_km)  10 
let(:point_within_radius_of_origin)  [48.801148, 2.429443]  # Geocoder.coordinates('Maisons-Alfort')
let(:point_outside_radius_of_origin)  [48.790367, 2.455572]  # Geocoder.coordinates('Créteil')

所以我正在尝试实现从原点生成随机点的函数。

来自https://***.com/a/43202522/2832282,我以某种方式能够在给定半径内生成一个点:(此功能似乎完美运行)

# Thanks to https://***.com/a/43202522/2832282
#
# @param lon [Float]
# @param lat [Float]
# @param max_radius [FLoat] in km
#
# @return [Pair<Float>] [Lng, lat]
def random_point_within_radius_of_origin(lng:, lat:, max_radius:)
  dx, dy = Utility.random_point_in_disk(max_radius)
  random_lat = lat + dy / OneDegree
  random_lng = lng + dx / ( OneDegree * Math::cos(lat * Math::PI / 180) )
  [random_lng, random_lat]
end
# @param max_radius [Float] Distance in km
#
# @return [Pair<Float>]
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

我需要实现下面的函数以在给定磁盘之外生成一个从原点半径外的随机点(我并不关心是否均匀分布)。我想我可以生成一个假点并重试,直到达到目标为止。

请注意,如果您有一些代码在没有指定 max_radius 的情况下工作,那就更好了(我基本上只是想排除上述函数生成的坐标)

# @param lon [Float] Longitude of origin
# @param lat [Float] Latitude of origin
# @param max_radius [FLoat] Max radius from origin in km
# @param min_radius [FLoat] Min radius from origin in km
#
# @return [Pair<Float>] [Lng, lat] of some random point between min_radius and max_radius of origin
def random_point_within_radius_band_of_origin(lng:, lat:, max_radius:, min_radius:)
  # What this SO Question is about
end

【问题讨论】:

gis.stackexchange.com/a/5822 【参考方案1】:

如果您需要代码在径向带中生成均匀的随机点,这里是(未经测试!)

# @param min_radius [Float] Minimum radius, in km
# @param max_radius [Float] Maximum radius, in km
#
# @return [Pair<Float>]
def random_point_in_band(min_radius, max_radius)
  r     = min_radius + (max_radius - min_radius) *  Math.sqrt(rand)
  theta = 2.0 * Math::PI * rand
  [r * Math.cos(theta), r * Math.sin(theta)]
end

【讨论】:

我需要这个,但来自经度/纬度格式的原点[origin_longitude, origin_latitude] @CyrilDuchon-Doris 所以问题出在函数random_point_within_radius_of_origin,翻译部分?如果在random_point_within_radius_of_origin参数min_radius里面加上random_point_in_band里面调用,是行不通还是还有问题? 我编辑了我的答案。我的第一个函数random_point_within_radius_of_origin 很好,我需要实现random_point_within_radius_band_of_origin。基本上我需要了解如何将您的函数返回到我的原点。我不确定我是否可以使用与原始函数lat + dy / OneDegreelng + dx / ( OneDegree * Math::cos(lat * Math::PI / 180) ) 中相同的技巧。或者我可以吗? @CyrilDuchon-Doris 我不太熟悉从本地坐标到(lng,lat) 的映射。您可以尝试相同的技巧并仅绘制 1000 个采样点吗? @CyrilDuchon-Doris 真的,你有两个问题合二为一。首先是在径向带中对局部点进行采样。其次是将采样中心从 (0,0) 映射到某个全局位置 (lat,long)。我建议单独问第二个问题,因为它们没有太多共同点【参考方案2】:

直接将Severin's code 与random_point_within_radius_of_origin 中的代码组合在一起,以生成带内的随机点:

# @param min_radius [Float] Minimum radius, in km
# @param max_radius [Float] Maximum radius, in km
#
# @return [Pair<Float>]
def random_point_in_band(min_radius, max_radius)
  r     = min_radius + (max_radius - min_radius) *  Math.sqrt(rand)
  theta = 2.0 * Math::PI * rand
  [r * Math.cos(theta), r * Math.sin(theta)]
end

EarthRadius = 6371 # km
OneDegree = EarthRadius * 2 * Math::PI / 360 * 1000 # 1° latitude in meters

# @param lon [Float] Longitude of origin
# @param lat [Float] Latitude of origin
# @param max_radius [FLoat] Max radius from origin in km
# @param min_radius [FLoat] Min radius from origin in km
#
# @return [Pair<Float>] [Lng, lat] of some random point between min_radius and max_radius of origin
def random_point_within_radius_band_of_origin(lng:, lat:, max_radius:, min_radius:)
  dx, dy = random_point_in_band(min_radius, max_radius)
  random_lat = lat + dy / OneDegree
  random_lng = lng + dx / ( OneDegree * Math::cos(lat * Math::PI / 180) )
  [random_lng, random_lat]
end

【讨论】:

以上是关于在原点的给定半径范围内和外部生成随机坐标的主要内容,如果未能解决你的问题,请参考以下文章

Unity C# - 在一个点周围随机生成游戏对象

java随机生成坐标坐标

如何在另一个点的半径内生成随机纬度和经度?

如何用matlab生成一个随机的三维坐标

使用随机坐标重复 UIAnimation

如何在给定范围内生成随机数作为 Tensorflow 变量