我想添加一个模型管理器函数,该函数根据坐标的接近度过滤查询集。我发现这个blog posting的代码正是我想要的。
下面的代码段似乎使用了已删除的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函数,我正在尝试重写这个节。但是,我不理解计算 - 几乎没有通过几何学,我的研究比实际帮助我更加困惑我。
有人可以帮忙吗?我将不胜感激。
答案 0 :(得分:1)
看起来英里的distance
被转换为海里,每个海里等于一分钟的弧度,每个弧度是弧度的1/60。然后将该值加倍,然后从给定的纬度和经度中加上和减去。这四个值可用于在坐标周围形成边界框。
您可以在Wikipedia上查找任何所需的转换因子。还有一篇名为Horizontal position representation的相关文章讨论了经度和纬度定位的替代方案的优缺点,避免了它们的一些复杂性。换句话说,关于在计算中用另一个水平位置表示替换纬度和经度所涉及的考虑因素。
答案 1 :(得分:1)
地球不是一个球体,只是大致如此。如果您需要更准确的计算,请使用pyproj。然后,您可以根据参考椭球(例如WGS84)计算位置。
答案 2 :(得分:1)
distance
的圆的最小轴对齐边界框,但在赤道附近,边界框并未完全包含该圆。
答案 3 :(得分:1)
博客中的代码很草率:
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英里(即sqrt(5 * 2 + 5 * 2))的答案。
请注意,您显示的代码似乎是半径加倍。这意味着你可以在14.1英里之外获得积分。
(b)正如@TokenMacGuy所说,远离赤道,它变得更糟。如此计算的边界框不包括您感兴趣的所有点 - 除非您通过加倍半径而过度使用。
(c)如果感兴趣的圈子包括北极或南极,则计算非常不精确,需要调整。如果感兴趣的圆圈被180度子午线(即没有曲折的国际日期线)穿过,则结果是无意义的;你需要检测这种情况并应用一个由两部分组成的查询(子午线的每一侧都有一个部分)。
有关问题(b)和(c)的解决方案,请参阅this article。
答案 4 :(得分:1)
如果其他人现在正在考虑这个问题,因为我尝试使用geopy并且只是对抗它,现在相当于上面的rough_distance片段是:
import geopy
rough_distance = geopy.units.degrees(arcminutes=geopy.units.nautical(miles=1))
答案 5 :(得分:0)
如果地球上的坐标已知,您可以使用 geopy 来很好地估计该点的十进制度数到英里(或任何距离单位)比例:
SCALE_VAL = 0.1
lat_scale_point = (cur_lat + SCALE_VAL, cur_long)
long_scale_point = (cur_lat, cur_long + SCALE_VAL)
cur_point = (cur_lat, cur_long)
lat_point_miles = distance.distance(cur_point, lat_scale_point).miles
long_point_miles = distance.distance(cur_point, long_scale_point).miles
# Assumes that 'radius_miles` is the range around the point you want to look for
lat_rough_distance = (radius_miles / lat_point_miles) * SCALE_VAL
long_rough_distance = (radius_miles / long_point_miles) * SCALE_VAL
一些注意事项: