Joh*_*fis 5 python gis django postgis geodjango
序幕:
这是在SO中经常出现的一个问题:
我想撰写一个关于SO文档的示例,但是geodjango本章从未停止过,并且自从文档于2017年8月8日关闭以来,我将遵循这个广受赞誉并讨论了元答案的建议,并将我的示例写为自我回答发布。
当然,我也很高兴看到任何其他方法!!
题:
假设模型:
class MyModel(models.Model):
name = models.CharField()
coordinates = models.PointField()
Run Code Online (Sandbox Code Playgroud)
我将点存储在coordinate变量中作为lan, lng, alt点的位置:
MyModel.objects.create(
name='point_name',
coordinates='SRID=3857;POINT Z (100.00 10.00 150)')
Run Code Online (Sandbox Code Playgroud)
我正在尝试计算两个这样的点之间的3D距离:
p1 = MyModel.objects.get(name='point_1').coordinates
p2 = MyModel.objects.get(name='point_2').coordinates
d = Distance(m=p1.distance(p2))
Run Code Online (Sandbox Code Playgroud)
现在d=X以米为单位。
如果仅更改其中一个点的高度,则:
例如:
p1.coordinates = 'SRID=3857;POINT Z (100.00 10.00 200)'
Run Code Online (Sandbox Code Playgroud)
从150以前,计算:
d = Distance(m=p1.distance(p2))
Run Code Online (Sandbox Code Playgroud)
d=X再次返回,就像忽略高程一样。
如何计算两点之间的3D距离?
从该GEOSGeometry.distance方法的文档中阅读:
返回此几何体上最近点与给定几何体(另一个 GEOSGeometry 对象)之间的距离。
笔记
GEOS 距离计算是线性的——换句话说,即使 SRID 指定了地理坐标系,GEOS 也不执行球面计算。
因此,我们需要实现一种方法来计算 2 点之间更准确的 2D 距离,然后我们可以尝试应用这些点之间的高度 (Z) 差。
1.大圆二维距离计算:
计算球体表面两点之间距离的最常用方法(因为地球很简单但通常建模)是Haversine公式:
虽然从大圆距离维基页面我们读到:
尽管此公式对于球体上的大多数距离都是准确的,但对于对映点(在球体的相对两端)的特殊(且有些不寻常)情况,它也存在舍入误差。对于所有距离都准确的公式是以下Vincenty 公式的特例,用于长轴和短轴相等的椭球。
我们可以创建自己的Haversine 或Vincenty 公式实现(如Haversine 所示:Python 中的Haversine 公式(两个GPS 点之间的轴承和距离)),或者我们可以使用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)
Run Code Online (Sandbox Code Playgroud)geopy.distance.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
Run Code Online (Sandbox Code Playgroud)2. 在混合中添加高度:
如上所述,上述每个计算都会产生 2 点之间的大圆距离。该距离也称为“乌鸦飞翔”,假设“乌鸦”从 A 点飞到 B 点时高度不变,并且尽可能笔直地飞行。
通过将前面一种方法的结果与 A 点和 B 点之间的高度差(delta)相结合,我们可以更好地估计“步行/驾驶”(“乌鸦走路”??)距离距离计算的欧几里得公式:
acw_dist = sqrt(great_circle(p1, p2).m**2, (p1.z - p2.z)**2)
Run Code Online (Sandbox Code Playgroud)
以前的解决方案容易出错,尤其是点之间的实际距离越长。
我把它留在这里是为了评论继续的原因。
GeoDjangoDistance计算两点之间的二维距离并且不考虑高度差异。
为了获得 3D 计算,我们需要创建一个距离函数,该函数将在计算中考虑高度差异:
理论:
的latitude,longitude并且altitude是极坐标,我们需要把它们翻译成直角坐标系(x,y,z)以应用欧氏公式对他们并计算它们的3D距离。
假设:
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)
Run Code Online (Sandbox Code Playgroud)
你将分别拥有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)
Run Code Online (Sandbox Code Playgroud)