我需要为我的搜索引擎生成一个规范来测试,当我指定一个原点和一个半径时,超出源源结果的结果不会包含在响应中,而包含给定半径内的半径(以千米为单位)。
给定原点和半径,我想测试两个“极端”情况,我创建两个测试数据点,
例如,如果我的半径是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
如果你需要代码在径向带中生成均匀的随机点,这里是(未经测试!)
# @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
可以直接将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