如何在GeoDjango中计算两点之间的3D距离(包括海拔高度) [英] How to calculate 3D distance (including altitude) between two points in GeoDjango

查看:384
本文介绍了如何在GeoDjango中计算两点之间的3D距离(包括海拔高度)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

序言:

这是在SO中经常出现的问题:

This is a question arising often in SO:

  • 3d distance calculations with GeoDjango
  • Calculating distance between two points using latitude longitude and altitude (elevation)
  • Distance between two 3D point in geodjango (postgis)

我想撰写一个关于SO文档的示例,但是geodjango一章从未动摇,并且由于文档于2017年8月8日关闭,我将遵循

I wanted to compose an example on SO Documentation but the geodjango chapter never took off and since the Documentation got shut down on August 8, 2017, I will follow the suggestion of this widely upvoted and discussed meta answer and write my example as a self-answered post.

当然,我也很高兴看到任何其他方法!

Of course, I would be more than happy to see any different approach as well!!

问题:

假设模型:

class MyModel(models.Model):
    name = models.CharField()
    coordinates = models.PointField()

将点存储在coordinate变量中作为lan, lng, alt点的位置:

Where I store the point in the coordinate variable as a lan, lng, alt point:

MyModel.objects.create(
    name='point_name', 
    coordinates='SRID=3857;POINT Z (100.00 10.00 150)')

我正在尝试计算两个这样的点之间的3D距离:

I am trying to calculate the 3D distance between two such points:

p1 = MyModel.objects.get(name='point_1').coordinates
p2 = MyModel.objects.get(name='point_2').coordinates

d = Distance(m=p1.distance(p2))

现在d=X以米为单位.

如果我仅更改所关注点之一的高度:

If I change only the altitude of one of the points in question:

例如:

p1.coordinates = 'SRID=3857;POINT Z (100.00 10.00 200)'

根据之前的150条计算:

from 150 previously, the calculation:

d = Distance(m=p1.distance(p2))

再次返回d=X,就像忽略高程一样.
如何计算两点之间的3D距离?

returns d=X again, like the elevation is ignored.
How can I calculate the 3D distance between my points?

推荐答案

GEOSGeometry.distance 方法:

返回此几何图形上最接近的点与给定几何图形(另一个GEOSGeometry对象)之间的距离.

Returns the distance between the closest points on this geometry and the given geom (another GEOSGeometry object).

注意

GEOS距离计算是线性的 –换句话说,即使SRID指定了地理坐标系,GEOS也不执行球形计算.

GEOS distance calculations are linear – in other words, GEOS does not perform a spherical calculation even if the SRID specifies a geographic coordinate system.

因此,我们需要实现一种方法来计算2个点之间的更精确的2D距离,然后我们可以尝试应用这些点之间的高度(Z)差.

Therefore we need to implement a method to calculate a more accurate 2D distance between 2 points and then we can try to apply the altitude (Z) difference between those points.

1.大圆环2D距离计算:

计算球体表面上两个点之间距离的最常见方法(因为地球是简单的,但通常是建模的)是

The most common way to calculate the distance between 2 points on the surface of a sphere (as the Earth is simplistically but usually modeled) is the Haversine formula:

haversine公式确定球体上两个点之间的大圆距离给定他们的经度和纬度.

The haversine formula determines the great-circle distance between two points on a sphere given their longitudes and latitudes.

尽管从大圆距离Wiki页面中,我们读到:

尽管此公式对于球体上的大多数距离都是准确的,但对于对偶点(在球体的相对两端)的特殊情况(也有些不寻常),它也会遭受舍入误差. Vincenty公式的以下特殊情况适用于所有距离长轴和短轴相等的椭圆形.

Although this formula is accurate for most distances on a sphere, it too suffers from rounding errors for the special (and somewhat unusual) case of antipodal points (on opposite ends of the sphere). A formula that is accurate for all distances is the following special case of the Vincenty formula for an ellipsoid with equal major and minor axes.

我们可以创建自己的Haversine或Vincenty公式实现(如Haversine所示:地理:

We can create our own implementation of the Haversine or the Vincenty formula (as shown here for Haversine: Haversine Formula in Python (Bearing and Distance between two GPS points)) or we can use one of the already implemented methods contained in geopy:

  • geopy.distance.great_circle (Haversine):

    from geopy.distance import great_circle
    newport_ri = (41.49008, -71.312796)
    cleveland_oh = (41.499498, -81.695391)

    # This call will result in 536.997990696 miles
    great_circle(newport_ri, cleveland_oh).miles) 

  • geopy.distance.vincenty ( Vincenty):

  • geopy.distance.vincenty (Vincenty):

        from geopy.distance import vincenty
        newport_ri = (41.49008, -71.312796)
        cleveland_oh = (41.499498, -81.695391)
    
        # This call will result in 536.997990696 miles
        vincenty(newport_ri, cleveland_oh).miles
    

  • 2.在组合中添加海拔高度:

    如上所述,以上每个计算都得出2点之间的大圆距离.该距离也称为乌鸦飞翔",前提是乌鸦"飞翔时不会改变高度,并且从A点到B点尽可能笔直.

    As mentioned, each of the above calculations yields the great-circle distance between 2 points. That distance is also called "as the crow flies", assuming that the "crow" flies without changing altitude and as straight as possible from point A to point B.

    通过将先前方法之一的结果与A点和A点之间的高度差(delta)结合起来,我们可以更好地估计步行/行驶"(乌鸦走路" ??)距离B,在欧几里得公式中进行距离计算:

    We can have a better estimation of the "walking/driving" ("as the crow walks"??) distance by combining the result of one of the previous methods with the difference (delta) in altitude between point A and point B, inside the Euclidean Formula for distance calculation:

    acw_dist = sqrt(great_circle(p1, p2).m**2, (p1.z - p2.z)**2)
    


    先前的解决方案容易出错,尤其是点之间的真实距离越长.
    出于评论继续的原因,我将其留在这里.


    The previous solution is prone to errors especially the longer the real distance between the points is.
    I leave it here for comment continuation reasons.

    GeoDjango Distance计算两个点之间的2D距离,并且不考虑高度差.
    为了进行3D计算,我们需要创建一个距离函数,该距离函数将在计算中考虑海拔差异:

    GeoDjango Distance calculates the 2D distance between two points and doesn't take into consideration the altitude differences.
    In order to get the 3D calculation, we need to create a distance function that will consider altitude differences in the calculation:

    理论:

    latitudelongitudealtitude极性坐标,我们需要将它们转换为笛卡尔坐标(xyz)以便对它们应用欧几里得公式并计算其3D距离.

    The latitude, longitude and altitude are Polar coordinates and we need to translate them to Cartesian coordinates (x, y, z) in order to apply the Euclidean Formula on them and calculate their 3D distance.

    • 假设:
      polar_point_1 = (long_1, lat_1, alt_1)

      polar_point_2 = (long_2, lat_2, alt_2)

    • Assume:
      polar_point_1 = (long_1, lat_1, alt_1)
      and
      polar_point_2 = (long_2, lat_2, alt_2)

    通过使用以下公式将每个点转换为其直角坐标:

    Translate each point to it's Cartesian equivalent by utilizing this formula:

    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)点.

    最后使用欧几里得公式:

    Finally use the Euclidean formula:

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

    这篇关于如何在GeoDjango中计算两点之间的3D距离(包括海拔高度)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆