与GeoDjango的3d距离计算

时间:2017-04-18 14:09:57

标签: python django gis postgis geodjango

我正在使用

  • python 2.7.12
  • django 1.10.6
  • postgreSQL 9.5.6
  • postGIS 2.2.2

第一个问题

我需要使用GeoDjango来计算两点之间的距离。当我检查documentation时,它说 GeoQuerySet.distance()已弃用,而是使用 django.contrib.gis.db中的距离() .models.functions

以下代码可以正常工作:

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

p1 = Instrument.objects.get(pk=151071000).coordinates
p2 = Instrument.objects.filter(pk=151071008)

for i in p2.annotate(distance=Distance('coordinates', p1)):
    print i.distance
    print i.distance.__class__

输出:

461.10913945 m
<class 'django.contrib.gis.measure.Distance'>

我的模特:

class Instrument(models.Model):
    ...
    coordinates = gis_models.PointField(null=True, blank=True, dim=3)

但我只有两点,所以当我尝试使用Distance()而没有 annotate()时,它会返回类 django.contrib.gis.db.models.functions.Distance的实例() django.contrib.gis.measure.Distance()

p1 = Instrument.objects.get(pk=151071000).coordinates
p2 = Instrument.objects.get(pk=151071008).coordinates
print Distance(p1, p2)

输出:

Distance(Value(SRID=4326;POINT Z (-76.48623600000001 44.260223 0)), GeomValue(SRID=4326;POINT Z (-76.490923 44.262658 0)))

如何获得与使用 annotate()相同的结果?

第二个问题

我必须计算考虑深度/高度的3d距离。但是当我尝试这样做时,我得到与2d相同的结果。下面我在第一个对象中将高程更改为200:

p1 = Instrument.objects.get(pk=151071000)
p1.coordinates = 'SRID=4326;POINT Z (-76.48623600000001 44.260223 200)'
p2 = Instrument.objects.filter(pk=151071008)

for i in p2.annotate(distance=Distance('coordinates', p1.coordinates)):
    print i.distance

输出:

461.10913945 m

2 个答案:

答案 0 :(得分:1)

让我们解决问题:

  1. Distance课程文档中,我们可以阅读以下内容:

      

    接受两个地理字段或表达式,并返回它们之间的距离,作为距离对象

    因此Distance(p1, p2)会返回Distance object 如果你这样做:

    p1 = Instrument.objects.get(pk=151071000).coordinates
    p2 = Instrument.objects.get(pk=151071008).coordinates
    d = Distance(m=p1.distance(p2))
    print d.m
    

    您将以米为单位进行测量。

    我会坚持使用annotate解决方案,这似乎更加坚固! (见解答)

  2. Distance计算两点之间的2D距离。为了获得3D计算,您需要自己创建一个。
    您可以从这个问题中查看我的方法:Calculating distance between two points using latitude longitude and altitude (elevation)

      
        
    • 设polar_point_1 =(long_1,lat_1,alt_1)和polar_point_2 =   (long_2,lat_2,alt_2)

    •   
    • 利用此功能将每个点转换为笛卡尔等效值   式:

      x = alt * cos(lat) * sin(long)
      y = alt * sin(lat)
      z = alt * cos(lat) * cos(long)
      
           

      您将分别获得p_1 =(x_1,y_1,z_1)和p_2 =(x_2,y_2,z_2)点。

    •   
    • 最后使用欧几里德公式:

      dist = sqrt((x_2-x_1)**2 + (y_2-y_1)**2 + (z_2-z_1)**2)
      
    •   

答案 1 :(得分:0)

** python 3.7,Django 2.2.10

我写了一些有用的功能来帮助我处理应用程序中的经/纬度坐标

"ß".compareIgnoreCase("SS")

其中measurement_unit可以是以下任意一项:

from django.contrib.gis.geos import Point
from django.contrib.gis.measure import Distance


def get_point(lat, lon):
    try:
        lat = float(lat)
        lon = float(lon)
        if lat and lon:
            return Point(x=float(round(lon, 6)), y=float(round(lat, 6)), srid=4326)
        else:
            return None
    except Exception:
        return None


def get_point_to_point_distance(point_one, point_two, measurement_unit="mile"):
    return Distance(**{measurement_unit: point_one.distance(point_two)})