如何在GeoDjango中计算两点之间的3D距离(包括海拔高度) [英] How to calculate 3D distance (including altitude) between two points in GeoDjango
问题描述
序言:
这是在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):
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:
理论:
latitude
,longitude
和altitude
是极性坐标,我们需要将它们转换为笛卡尔坐标(x
,y
,z
)以便对它们应用欧几里得公式并计算其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屋!