使用 geopy 将英里转换为纬度和经度

发布于 2024-10-05 01:13:20 字数 836 浏览 0 评论 0原文

背景

我想添加一个模型管理器函数,该函数根据与坐标的接近度过滤查询集。我发现这篇博客文章的代码正是在做这些事情我想。

代码

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

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

Background

I want to add a model manager function that filters a queryset based on the proximity to coordinates. I found this blog posting with code that is doing precisely what I want.

Code

The snippet below seems to make use of geopy functions that have since been removed. It coarsely narrows down the queryset by limiting the range of latitude and longitude.

    # 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)
    )

Problem

Since some of the used geopy functions have been removed/moved, I'm trying to rewrite this stanza. However, I do not understand the calculations---barely passed geometry and my research has confused me more than actually helped me.

Can anyone help? I would greatly appreciate it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

徒留西风 2024-10-12 01:13:20

万一其他人现在正在看这个,因为我尝试使用 geopy 并且只是碰到它,上面的 rough_distance 片段的现代等效项是:

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

In case anybody else is looking at this now, since I tried to use geopy and just hit up against it, the modern equivalent of the rough_distance snippet above is:

import geopy
rough_distance = geopy.units.degrees(arcminutes=geopy.units.nautical(miles=1))
jJeQQOZ5 2024-10-12 01:13:20

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

您可以在维基百科上查找任何所需的换算系数。还有一篇相关文章,标题为水平位置表示,其中讨论了优点和经度和纬度定位替代方案的缺点是可以避免其某些复杂性。换句话说,关于在计算中用另一种水平位置表示替换纬度和经度所涉及的考虑因素。

It looks like distance in miles is being converted to nautical miles, which are each equal to a minute of arc, which are 1/60th of an arc degree each. That value is then doubled, and then added and subtracted from a given latitude and longitude. These four values can be used to form a bounding box around the coordinates.

You can lookup any needed conversion factors on Wikipedia. There's also a relevant article there titled Horizontal position representation which discusses pros and cons of alternatives to longitude and latitude positioning which avoid some of their complexities. In other words, about the considerations involved with replacing latitude and longitude with another horizontal position representation in calculations.

倦话 2024-10-12 01:13:20

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

The Earth is not a sphere, only approximately so. If you need a more accurate calculation, use pyproj. Then you can calculate the location based a reference ellipsoid (e.g. WGS84).

萌酱 2024-10-12 01:13:20

就该片段的实际作用而言,Martineau 的答案是正确的,但重要的是要注意,1 弧分代表不同位置的不同距离。在赤道处,查询覆盖包围直径为 distance 的圆的最小轴对齐边界框,但在赤道之外,边界框并不完全包含该圆。

martineau's answer is right on, in terms of what the snippet actually does, but it is important to note that 1 minute of arc represents very different distances depending on location. At the equator, the query covers the least axis aligned bounding box enclosing a circle of diameter distance, but off the equator, the bounding box does not completely contain that circle.

熟人话多 2024-10-12 01:13:20

博客中的这段代码很草率:

  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 code from the blog is sloppy:

  def near(self, latitude=None, longitude=None, distance=None):
    if not (latitude and longitude and distance):
      return []

If latitude == 0 (equator) or longitude == 0 (Greenwich meridian), it returns immediately. Should be if latitude is None or longitude is None .......

@TokenMacGuy's answer is an improvement, but:

(a) The whole idea of the "bounding box" is to avoid an SQL or similar query calculating a distance to all points that otherwise satisfy the query. With appropriate indexes, the query will execute much faster. It does this at the cost of leaving the client to (1) calculate the coordinates of the bounding box (2) calculate and check the precise distance for each result returned by the query.

If step 2 is omitted, you get errors, even at the equator. For example "find all pizza shops in a 5-mile radius" means you get answers up to 7.07 miles (that's sqrt(5*2 + 5*2)) away in the corners of the box.

Note that the code that you show seems to be arbitrarily doubling the radius. This would mean you get points 14.1 miles away.

(b) As @TokenMacGuy said, away from the equator, it gets worse. The bounding box so calculated does not include all points that you are interested in -- unless of course you are overkilling by doubling the radius.

(c) If the circle of interest includes either the North or South Pole, the calculation is horribly inexact, and needs adjusting. If the circle of interest is crossed by the 180-degree meridian (i.e. the International Date Line without the zigzags), the results are a nonsense; you need to detect this case and apply a 2-part query (one part for each side of the meridian).

For solutions for problems (b) and (c), see this article.

葮薆情 2024-10-12 01:13:20

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

If the coordinates on the earth are known, you can use geopy to get a good estimate of the decimal degrees to miles (or any distance units) scale at that point:

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

Some caveats:

  • Special-case handling for the the scale points is needed around polls or prime meridean
  • Depending on how large or small you want your radius to be, you could pick a more appropriate SCALE_VAL
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文