给定当前点、距离和方位角获取经纬度
给定一个已有的经纬度点、距离(单位是公里)和方位角(以度数表示,转换为弧度),我想计算出新的经纬度。这个网站经常被提到,但我就是无法让公式正常工作。
从上面的链接中得到的公式是:
lat2 = asin(sin(lat1)*cos(d/R) + cos(lat1)*sin(d/R)*cos(θ))
lon2 = lon1 + atan2(sin(θ)*sin(d/R)*cos(lat1), cos(d/R)−sin(lat1)*sin(lat2))
上面的公式是用于MSExcel的,其中-
asin = arc sin()
d = distance (in any unit)
R = Radius of the earth (in the same unit as above)
and hence d/r = is the angular distance (in radians)
atan2(a,b) = arc tan(b/a)
θ is the bearing (in radians, clockwise from north);
这是我在Python中写的代码。
import math
R = 6378.1 #Radius of the Earth
brng = 1.57 #Bearing is 90 degrees converted to radians.
d = 15 #Distance in km
#lat2 52.20444 - the lat result I'm hoping for
#lon2 0.36056 - the long result I'm hoping for.
lat1 = 52.20472 * (math.pi * 180) #Current lat point converted to radians
lon1 = 0.14056 * (math.pi * 180) #Current long point converted to radians
lat2 = math.asin( math.sin(lat1)*math.cos(d/R) +
math.cos(lat1)*math.sin(d/R)*math.cos(brng))
lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1),
math.cos(d/R)-math.sin(lat1)*math.sin(lat2))
print(lat2)
print(lon2)
我得到的结果是
lat2 = 0.472492248844
lon2 = 79.4821662373
15 个回答
33
这个问题在地理学研究中被称为直接问题。
这个问题其实很常见,也是让人困惑的原因之一。大多数人都希望能得到一个简单明了的答案,但实际上并没有,因为提问的人往往没有提供足够的信息,主要是因为他们不知道:
- 地球并不是一个完美的球体,它在两极被压扁了。
- 因此,地球的半径并不是一个固定值,
R
。具体可以查看这里。 - 地球表面并不完全平滑(有高低起伏等)。
- 由于地壳板块的运动,一个地理点的经纬度位置每年可能会变化几毫米(至少)。
所以在不同的几何模型中,有很多不同的假设,这些假设会根据你需要的准确度而有所不同。因此,要回答这个问题,你需要考虑你希望结果的准确度。
一些例子:
- 我只想知道一个大概的位置,误差在几公里以内,适用于小于100公里的距离,纬度在
0-70度
之间(地球可以看作是平的)。 - 我想要一个在全球范围内都适用的答案,但准确度大约在几米左右。
- 我想要一个非常精确的位置,精确到原子级别的
纳米
([nm])。 - 我希望答案计算起来非常快且简单,不要消耗太多计算资源。
所以你可以选择使用多种算法。此外,每种编程语言都有自己的实现或“包”,而且不同模型和模型开发者的具体需求也会有所不同。在这里,除了javascript
,忽略其他语言是有益的,因为它的结构与伪代码非常相似,因此可以很容易地转换成其他语言,几乎不需要改动。
主要模型包括:
欧几里得/平面地球模型
:适用于大约10公里以内的非常短的距离。球面模型
:适用于大范围的经度距离,但纬度差异较小。一个常用模型是:- Haversine:在[公里]范围内,精度达到米级,代码非常简单。
椭球模型
:在任何经纬度和距离下都非常准确,但仍然是一个数值近似,具体取决于你需要的准确度。一些常用模型包括:- Lambert:在1000公里范围内,精度约为10米。
- Paul D.Thomas:Andoyer-Lambert近似法。
- Vincenty:精度达到毫米级,计算效率高。
- Kerney:精度达到纳米级。
参考资料:
- https://en.wikipedia.org/wiki/Reference_ellipsoid
- https://en.wikipedia.org/wiki/Haversine_formula
- https://en.wikipedia.org/wiki/Earth_ellipsoid
- https://en.wikipedia.org/wiki/Geodesics_on_an_ellipsoid
- https://en.wikipedia.org/wiki/Vincenty%27s_formulae
- https://geographiclib.sourceforge.io/scripts/geod-calc.html
41
geopy这个库支持这个功能:
import geopy
from geopy.distance import VincentyDistance
# given: lat1, lon1, b = bearing in degrees, d = distance in kilometers
origin = geopy.Point(lat1, lon1)
destination = VincentyDistance(kilometers=d).destination(origin, b)
lat2, lon2 = destination.latitude, destination.longitude
这个信息是通过这个链接找到的。
134
需要把答案从弧度转换回角度。下面是可以运行的代码:
from math import asin, atan2, cos, degrees, radians, sin
def get_point_at_distance(lat1, lon1, d, bearing, R=6371):
"""
lat: initial latitude, in degrees
lon: initial longitude, in degrees
d: target distance from initial
bearing: (true) heading in degrees
R: optional radius of sphere, defaults to mean radius of earth
Returns new lat/lon coordinate {d}km from initial, in degrees
"""
lat1 = radians(lat1)
lon1 = radians(lon1)
a = radians(bearing)
lat2 = asin(sin(lat1) * cos(d/R) + cos(lat1) * sin(d/R) * cos(a))
lon2 = lon1 + atan2(
sin(a) * sin(d/R) * cos(lat1),
cos(d/R) - sin(lat1) * sin(lat2)
)
return (degrees(lat2), degrees(lon2),)
lat = 52.20472
lon = 0.14056
distance = 15
bearing = 90
lat2, lon2 = get_point_at_distance(lat, lon, distance, bearing)
# lat2 52.20444 - the lat result I'm hoping for
# lon2 0.36056 - the long result I'm hoping for.
print(lat2, lon2)
# prints "52.20451523755824 0.36067845713550956"