GeoDjango:我怎样才能得到两点之间的距离?

Posted

技术标签:

【中文标题】GeoDjango:我怎样才能得到两点之间的距离?【英文标题】:GeoDjango: How can I get the distance between two points? 【发布时间】:2015-11-12 13:56:26 【问题描述】:

我的Profile 模型有这个字段:

location = models.PointField(geography=True, dim=2, srid=4326)

我想使用 GeoDjango 计算这两个locations 之间的距离(考虑到地球是一个球体),以便我可以将这个距离存储在数据库中。

    如何使用 GeoDjango 计算这个距离? 结果的单位是什么? 是否有“最佳”方式来存储这些数据?漂浮?十进制?

我已经查看了以前的类似问题,但没有发现它们有用。没有答案能充分解释发生了什么或为什么会起作用。

我正在使用 Django 1.8 和 GeoDjango 所需库的最新版本。

谢谢!

【问题讨论】:

对不起,我不知道 GeoDjango,谷歌搜索了几分钟并没有让我找到明确的解决方案。但是您可能会发现GeographicLib 很有用。它使用非常好的算法来计算球体距离,比旧的 Vincenty 公式要好得多。 FWIW,GeographicLib 的作者,C. F. F. Karney,是***Geodesics on an ellipsoid 的主要贡献者。 你试过了吗? zach.se/geodesic-distance-between-points-in-geodjango 感谢 Abhyudit Jain,这导致了解决方案。感谢 PM 2Ring 的建议 - GeographicLib 目前看起来有点复杂,所以我选择了更简单的东西。 【参考方案1】:

根据Abhyudit Jain 的评论,我使用geopy 来计算距离。根据 e4c5 的建议,我将其添加为属性而不是存储它:

from django.contrib.gis.measure import Distance, D
from geopy.distance import distance

@property
def distance(self):
    return Distance(m=distance(self.user_a.profile.location, self.user_b.profile.location).meters)

Geopy 默认为 Vincenty’s formulae,误差高达 0.5%,并且包含许多我将来会使用的其他功能。

上面返回一个 GeoDjango Distance 对象,准备好在测量之间轻松转换。

感谢您的帮助!

【讨论】:

请注意,Django 的 Point() 类通常以 (lon, lat) 的顺序存储值,而 geopy 的 Point() 类的值存储为 (lat, lon)。当您使用 geopy 计算来自 GeoDjango 的两点之间的距离时,请务必使用 geopy 的lonlat() 函数:distance(lonlat(*my_django_pnt.tuple), lonlat(*my_django_pnt2.tuple)) 转换它们。否则距离将没有多大意义。【参考方案2】:

如何使用 GeoDjango 计算这个距离? 对于两个对象:

a.location.distance(b.location)

假设您有一个对象 a,它是您的配置文件模型的一个实例,并且您希望找到到每个其他配置文件的距离,您可以按照Geodjango reference 中的描述执行以下查询:

for profile in Profile.objects.distance(a.location):
    print profile.distance

如果您只想与距离小于 1 公里的物体进行比较:

for profile in Profile.objects.filter(location__dwithin=(a.location, D(km=1)).distance(a.location):
        print profile.distance

结果的单位是什么?

单位可以是任何你想要的。返回的是一个距离对象。然而,默认值是以米为单位的,这就是上面的打印语句将显示的内容。

是否有“最佳”方式来存储这些数据?漂浮?十进制?

最好的办法是不保存。通常,人们不会将可以通过简单查询计算的内容保存在数据库中。并且记录的数量将呈指数增长。例如,如果您的数据库中有 N 个配置文件,它将与 N-1 个其他配置文件具有一些距离属性。所以你最终在“缓存表”中有 N(N-1) 条记录

【讨论】:

a.location.distance(b.location) 给了我一个浮点数,例如0.11427743653348317。我猜这是一个角度?我似乎无法获得距离对象 距离函数假设点在简单的二维空间中(不在球体表面上)。例如,(300, 0)(0, 400) 之间的距离将为 500(三角形的斜边)。请注意,这些点在 srid 4326 中甚至都不可能出现。【参考方案3】:

要获得在GeoQuerySet 中计算的距离,您可以将annotate 与the GeoDjango Distance database function 结合起来(不要与the Distance measure 混淆)

from django.contrib.gis.db.models.functions import Distance

queryset = Profile.objects.annotate(
    distance=Distance('location', a.location)
)

带注释的距离将为Distance measure。这意味着您可以执行以下操作:

for profile in queryset:
    print(profile.distance.mi)  # or km, etc

要过滤特定半径内的配置文件,您可以将 filter 添加到 QuerySet。

from django.contrib.gis.db.models.functions import Distance as DistanceDBFunction
from django.contrib.gis.measure import Distance as DistanceMeasure

queryset = Profile.objects.annotate(
    distance=DistanceDBFunction('location', a.location)
).filter(
    distance__lt=DistanceMeasure(mi=1)
)

如果不需要标注的距离,可以直接使用the distance lookups。

from django.contrib.gis.measure import Distance

queryset = Profile.objects.filter(
    location__distance_lt=(a.location, Distance(mi=1))
)

注意:自 Django 1.9 起,其他答案中提到的 Profile.objects.distance(a.location) 已被弃用。

【讨论】:

以上是关于GeoDjango:我怎样才能得到两点之间的距离?的主要内容,如果未能解决你的问题,请参考以下文章

获取 s-s-rS 报告地图中两点之间的距离

allegro 16.2中怎样测量任意两点的距离

geodjango(postgis)中两个3D点之间的距离

ARCGis中怎样计算两点间的距离

地图上的两点怎样计算距离

怎样计算两个经纬度之间的距离 百度百科