使用geopy将英里转换为纬度和经度度数
背景
我想添加一个模型管理功能,用来根据距离坐标的远近来过滤查询结果。我找到了一篇博客文章,里面的代码正好实现了我想要的功能。
代码
下面的代码片段似乎使用了geopy的一些函数,但这些函数现在已经被移除。它大致上通过限制经纬度的范围来缩小查询结果。
# Prune down the set of all locations to something we can quickly check precisely
rough_distance = geopy.distance.arc_degrees(arcminutes=geopy.distance.nm(miles=distance)) * 2
queryset = queryset.filter(
latitude__range=(latitude - rough_distance, latitude + rough_distance),
longitude__range=(longitude - rough_distance, longitude + rough_distance)
)
问题
由于一些使用的geopy函数已经被移除或移动,我正在尝试重写这部分代码。不过,我对这些计算不太理解——我几乎没及格过几何,而且我的研究让我更加困惑,而不是帮助我。
有没有人能帮帮我?我会非常感激的。
6 个回答
这段代码来自一个博客,看起来有点乱:
def near(self, latitude=None, longitude=None, distance=None):
if not (latitude and longitude and distance):
return []
如果纬度是0(赤道)或者经度是0(格林威治子午线),代码会立即返回。其实应该是 if latitude is None or longitude is None .......
@TokenMacGuy的回答有改进,但:
(a) “边界框”的主要目的是为了避免SQL查询或者类似的查询去计算所有符合条件的点之间的距离。使用合适的索引,查询会执行得更快。这样做的代价是让客户端去(1)计算边界框的坐标(2)计算并检查查询返回的每个结果的准确距离。
如果省略了第2步,你会得到错误的结果,即使在赤道上也是如此。例如,“找出5英里范围内的所有披萨店”意味着你可能会得到距离达到7.07英里的答案(这是5的平方根乘以2加上5的平方根乘以2)。
注意,你展示的代码似乎是随意将半径加倍。这意味着你会得到距离14.1英里的点。
(b) 正如@TokenMacGuy所说,离赤道越远,问题就越严重。这样计算出的边界框并不包含你感兴趣的所有点——除非你真的把半径加倍了。
(c) 如果感兴趣的圆圈包括北极或南极,计算就会非常不准确,需要调整。如果感兴趣的圆圈穿过180度子午线(也就是国际日期线,不考虑锯齿状的部分),结果就会变得毫无意义;你需要检测这种情况,并进行两部分的查询(每部分针对子午线的两侧)。
关于问题(b)和(c)的解决方案,可以参考这篇文章。
如果现在还有其他人也在关注这个问题,我之前尝试使用 geopy 时遇到了一些困难。上面提到的粗略距离计算的现代替代方法是:
import geopy
rough_distance = geopy.units.degrees(arcminutes=geopy.units.nautical(miles=1))