Python中的Haversine公式(两个GPS点之间的轴承和距离)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4913349/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Haversine Formula in Python (Bearing and Distance between two GPS points)
提问by avitex
Problem
问题
I would like to know how to get the distance and bearing between 2 GPS points. I have researched on the haversine formula. Someone told me that I could also find the bearing using the same data.
我想知道如何获得2 个 GPS 点之间的距离和方位。我研究过半正弦公式。有人告诉我,我也可以使用相同的数据找到轴承。
Edit
编辑
Everything is working fine but the bearing doesn't quite work right yet. The bearing outputs negative but should be between 0 - 360 degrees.
The set data should make the horizontal bearing 96.02166666666666and is:
一切正常,但轴承还不能正常工作。轴承输出为负,但应在 0 - 360 度之间。设定数据应作水平方位角96.02166666666666,为:
Start point: 53.32055555555556 , -1.7297222222222221
Bearing: 96.02166666666666
Distance: 2 km
Destination point: 53.31861111111111, -1.6997222222222223
Final bearing: 96.04555555555555
Here is my new code:
这是我的新代码:
from math import *
Aaltitude = 2000
Oppsite = 20000
lat1 = 53.32055555555556
lat2 = 53.31861111111111
lon1 = -1.7297222222222221
lon2 = -1.6997222222222223
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * atan2(sqrt(a), sqrt(1-a))
Base = 6371 * c
Bearing =atan2(cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1), sin(lon2-lon1)*cos(lat2))
Bearing = degrees(Bearing)
print ""
print ""
print "--------------------"
print "Horizontal Distance:"
print Base
print "--------------------"
print "Bearing:"
print Bearing
print "--------------------"
Base2 = Base * 1000
distance = Base * 2 + Oppsite * 2 / 2
Caltitude = Oppsite - Aaltitude
a = Oppsite/Base
b = atan(a)
c = degrees(b)
distance = distance / 1000
print "The degree of vertical angle is:"
print c
print "--------------------"
print "The distance between the Balloon GPS and the Antenna GPS is:"
print distance
print "--------------------"
采纳答案by Michael Dunn
Here's a Python version:
这是一个 Python 版本:
from math import radians, cos, sin, asin, sqrt
def haversine(lon1, lat1, lon2, lat2):
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees)
"""
# convert decimal degrees to radians
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
# haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
r = 6371 # Radius of earth in kilometers. Use 3956 for miles
return c * r
回答by OBu
You can solve the negative bearing problem by adding 360°. Unfortunately, this might result in bearings larger than 360° for positive bearings. This is a good candidate for the modulo operator, so all in all you should add the line
您可以通过添加 360° 来解决负方位问题。不幸的是,这可能导致正向轴承的轴承大于 360°。这是模运算符的一个很好的候选者,所以总而言之,您应该添加该行
Bearing = (Bearing + 360) % 360
at the end of your method.
在你的方法结束时。
回答by Jon Anderson
The bearing calculation is incorrect, you need to swap the inputs to atan2.
轴承计算不正确,您需要将输入交换为 atan2。
bearing = atan2(sin(long2-long1)*cos(lat2), cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(long2-long1))
bearing = degrees(bearing)
bearing = (bearing + 360) % 360
This will give you the correct bearing.
这将为您提供正确的方位。
回答by Vamshi G
You can try the following:
您可以尝试以下操作:
from haversine import haversine
haversine((45.7597, 4.8422),(48.8567, 2.3508), unit='mi')
243.71209416020253
回答by gisdude
The Y in atan2 is, by default, the first parameter. Here is the documentation. You will need to switch your inputs to get the correct bearing angle.
默认情况下,atan2 中的 Y 是第一个参数。这是文档。您需要切换输入以获得正确的方位角。
bearing = atan2(sin(lon2-lon1)*cos(lat2), cos(lat1)*sin(lat2)in(lat1)*cos(lat2)*cos(lon2-lon1))
bearing = degrees(bearing)
bearing = (bearing + 360) % 360
回答by pavankumar kavvuri
Refer to this link :https://gis.stackexchange.com/questions/84885/whats-the-difference-between-vincenty-and-great-circle-distance-calculations
请参阅此链接:https: //gis.stackexchange.com/questions/84885/whats-the-difference-between-vincenty-and-great-circle-distance-calculations
this actually gives two ways of getting distance. They are Haversine and Vincentys. From my research I came to know that Vincentys is relatively accurate. Also use import statement to make the implementation.
这实际上提供了两种获得距离的方法。他们是Haversine 和Vincentys。从我的研究中我开始知道 Vincentys 是相对准确的。也使用import语句来实现。
回答by Oleksiy Muzalyev
Here are two functions to calculate distance and bearing, which are based on the code in previous messages and https://gist.github.com/jeromer/2005586(added tuple type for geographical points in lat, lon format for both functions for clarity). I tested both functions and they seem to work right.
这里有两个计算距离和方位的函数,它们基于之前消息中的代码和https://gist.github.com/jeromer/2005586(为了清晰起见,这两个函数都添加了纬度、经度格式的地理点元组类型)。我测试了这两个功能,它们似乎工作正常。
#coding:UTF-8
from math import radians, cos, sin, asin, sqrt, atan2, degrees
def haversine(pointA, pointB):
if (type(pointA) != tuple) or (type(pointB) != tuple):
raise TypeError("Only tuples are supported as arguments")
lat1 = pointA[0]
lon1 = pointA[1]
lat2 = pointB[0]
lon2 = pointB[1]
# convert decimal degrees to radians
lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])
# haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
r = 6371 # Radius of earth in kilometers. Use 3956 for miles
return c * r
def initial_bearing(pointA, pointB):
if (type(pointA) != tuple) or (type(pointB) != tuple):
raise TypeError("Only tuples are supported as arguments")
lat1 = radians(pointA[0])
lat2 = radians(pointB[0])
diffLong = radians(pointB[1] - pointA[1])
x = sin(diffLong) * cos(lat2)
y = cos(lat1) * sin(lat2) - (sin(lat1)
* cos(lat2) * cos(diffLong))
initial_bearing = atan2(x, y)
# Now we have the initial bearing but math.atan2 return values
# from -180° to + 180° which is not what we want for a compass bearing
# The solution is to normalize the initial bearing as shown below
initial_bearing = degrees(initial_bearing)
compass_bearing = (initial_bearing + 360) % 360
return compass_bearing
pA = (46.2038,6.1530)
pB = (46.449, 30.690)
print haversine(pA, pB)
print initial_bearing(pA, pB)
回答by Clay
Most of these answers are "rounding" the radius of the earth. If you check these against other distance calculators (such as geopy), these functions will be off.
这些答案中的大多数都是“四舍五入”地球半径。如果您对照其他距离计算器(例如 geopy)检查这些,这些功能将被关闭。
This works well:
这很有效:
from math import radians, cos, sin, asin, sqrt
def haversine(lat1, lon1, lat2, lon2):
R = 3959.87433 # this is in miles. For Earth radius in kilometers use 6372.8 km
dLat = radians(lat2 - lat1)
dLon = radians(lon2 - lon1)
lat1 = radians(lat1)
lat2 = radians(lat2)
a = sin(dLat/2)**2 + cos(lat1)*cos(lat2)*sin(dLon/2)**2
c = 2*asin(sqrt(a))
return R * c
# Usage
lon1 = -103.548851
lat1 = 32.0004311
lon2 = -103.6041946
lat2 = 33.374939
print(haversine(lat1, lon1, lat2, lon2))
回答by Shubham Singh Yadav
Here's a numpy vectorized implementation of the Haversine Formula given by @Michael Dunn, gives a 10-50 times improvement over large vectors.
这是@Michael Dunn 给出的 Haversine 公式的 numpy 向量化实现,比大向量提高了 10-50 倍。
from numpy import radians, cos, sin, arcsin, sqrt
def haversine(lon1, lat1, lon2, lat2):
"""
Calculate the great circle distance between two points
on the earth (specified in decimal degrees)
"""
#Convert decimal degrees to Radians:
lon1 = np.radians(lon1.values)
lat1 = np.radians(lat1.values)
lon2 = np.radians(lon2.values)
lat2 = np.radians(lat2.values)
#Implementing Haversine Formula:
dlon = np.subtract(lon2, lon1)
dlat = np.subtract(lat2, lat1)
a = np.add(np.power(np.sin(np.divide(dlat, 2)), 2),
np.multiply(np.cos(lat1),
np.multiply(np.cos(lat2),
np.power(np.sin(np.divide(dlon, 2)), 2))))
c = np.multiply(2, np.arcsin(np.sqrt(a)))
r = 6371
return c*r
回答by Sergey Malyutin
There is also a vectorized implementation, which allows to use 4 numpy arrays instead of scalar values for coordinates:
还有一个矢量化实现,它允许使用 4 个 numpy 数组而不是坐标的标量值:
def distance(s_lat, s_lng, e_lat, e_lng):
# approximate radius of earth in km
R = 6373.0
s_lat = s_lat*np.pi/180.0
s_lng = np.deg2rad(s_lng)
e_lat = np.deg2rad(e_lat)
e_lng = np.deg2rad(e_lng)
d = np.sin((e_lat - s_lat)/2)**2 + np.cos(s_lat)*np.cos(e_lat) * np.sin((e_lng - s_lng)/2)**2
return 2 * R * np.arcsin(np.sqrt(d))

