【问题标题】:Conversion of miles to latitude and longitude degrees using geopy使用 geopy 将英里转换为纬度和经度
【发布时间】:2010-12-01 14:09:52
【问题描述】:

背景

我想添加一个模型管理器函数,该函数根据与坐标的接近程度过滤查询集。我发现这个blog posting 的代码正是我想要的。

代码

下面的 sn-p 似乎使用了 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 函数已被删除/移动,我正在尝试重写此节。但是,我不懂计算——勉强通过了几何学,我的研究让我感到困惑,而不是真正帮助了我。

有人可以帮忙吗?我将不胜感激。

【问题讨论】:

    标签: python geometry geolocation geography geopy


    【解决方案1】:

    如果其他人现在正在看这个,因为我尝试使用 geopy 并且只是碰到它,上面的 rough_distance sn-p 的现代等价物是:

    import geopy
    rough_distance = geopy.units.degrees(arcminutes=geopy.units.nautical(miles=1))
    

    【讨论】:

      【解决方案2】:

      看起来distance(以英里为单位)正在转换为海里,每个海里等于一弧分,每个海里是弧度的 1/60。然后将该值加倍,然后从给定的纬度和经度中添加和减去。这四个值可用于在坐标周围形成一个边界框。

      您可以在Wikipedia 上查找任何需要的转换系数。还有一篇题为Horizontal position representation 的相关文章讨论了经度和纬度定位替代方案的利弊,这些替代方案避免了它们的一些复杂性。换句话说,关于在计算中用另一种水平位置表示替换纬度和经度所涉及的考虑因素。

      【讨论】:

      • 太棒了!维基百科文章的这一部分非常有帮助:en.wikipedia.org/wiki/Minute_of_arc#Cartography
      • 在查看了最新的 geopy-0.94 源代码后,看起来 sn-p 中的代码使用的唯一缺少的是 geopy.distance.arc_degrees(arcminutes=xxx) 函数,您应该能够轻松替换它.有趣的是,distance.py 代码中的 cmets 表明它已经在内部使用 WGS-84 椭球,因此可能不需要 pyproj 和 PROJ.4(尽管它可能对您的应用程序有用)。
      【解决方案3】:

      地球不是一个球体,只是大致如此。如果您需要更准确的计算,请使用pyproj。然后您可以根据参考椭球体(例如 WGS84)计算位置。

      【讨论】:

        【解决方案4】:

        martineau 的回答是正确的,就 sn-p 的实际作用而言,但重要的是要注意,1 分钟的弧线代表不同的距离,具体取决于位置。在赤道,查询覆盖了包含直径为distance 的圆的最小轴对齐边界框,但在赤道以外,边界框不完全包含该圆。

        【讨论】:

        • 谢谢。我猜代码试图非常粗略地限制它。这也是您的评价,还是您对如何更精确有什么建议?
        【解决方案5】:

        来自博客的这段代码是草率的:

          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 度子午线(即没有锯齿形的国际日期变更线)穿过,结果就是一派胡言;您需要检测到这种情况并应用 2 部分查询(子午线的每一侧一个部分)。

        有关问题 (b) 和 (c) 的解决方案,请参阅this article

        【讨论】:

        • 非常广泛的答案+1。谢谢!现在正在研究您的观点,可能很快就会有一些其他问题。
        • @John Machin:所以,总结一下你的观点,代码可能会在赤道附近找到太远的披萨店,而在任何一个极点附近都找不到它们。不知何故,我怀疑这些都不是 OP 应用程序的大问题。 ;-)
        • @martineau:错了。在赤道产生的边界框是应有的两倍高和两倍宽。这是所需工作量的 4 倍。 “两次”是第一个愚蠢。第二个是一旦你离开赤道,正确的盒子就不是方形的,所以在例如西雅图(纬度:47 度)它只做了 2 * 1.37 == 2.73 倍的工作。现在想想如果有人注意到并修复了明显的(?)第一个愚蠢——10英里距离的+/- 0.1447度的边界框,而在西雅图,它应该是+/- 0.2122度的经度,而你错过了点。
        • @martineau:总结:两个错误不代表正确。我们对 OP 的申请一无所知,也不了解那些不加批判地阅读并相信已接受答案的人的申请。
        • @John Machin:这只是一个喜剧性的解脱。的确,我不知道可能阅读这些帖子的每个人的 OP 或其他应用程序的目的,但我并不担心,因为我们周围有像你这样的人来帮助我们解决问题。为了记录,当我说“可能在赤道附近发现披萨店太远”时,我是在暗示边界框在赤道附近太大了。
        【解决方案6】:

        如果地球上的坐标已知,您可以使用 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
        

        一些注意事项:

        • 在民意调查或本初子午线附近需要对比例点进行特殊处理
        • 根据您希望半径的大小,您可以选择更合适的 SCALE_VAL

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-10-20
          • 1970-01-01
          • 2020-09-02
          • 2013-09-09
          • 1970-01-01
          • 1970-01-01
          • 2021-05-21
          相关资源
          最近更新 更多