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

时间:2018-09-06 10:39:59

标签: ruby random coordinates polar-coordinates

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

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

  • 一个范围内:精确的半径减去一个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://stackoverflow.com/a/43202522/2832282中,我能够以某种方式在给定的半径内生成一个点:(此功能似乎运行得很好)

# Thanks to https://stackoverflow.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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

直接将Severin's coderandom_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
相关问题