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:我怎样才能得到两点之间的距离?的主要内容,如果未能解决你的问题,请参考以下文章