Получение расстояния между двумя точками на основе широты / долготы
Я попытался реализовать эту формулу:http://andrew.hedges.name/experiments/haversine/ В aplet для двух точек, которые я тестирую:
но мой код не работает.
from math import sin, cos, sqrt, atan2
R = 6373.0
lat1 = 52.2296756
lon1 = 21.0122287
lat2 = 52.406374
lon2 = 16.9251681
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))
distance = R * c
print "Result", distance
print "Should be", 278.546
расстояние, которое он возвращает,5447.05546147. Почему?
3 ответов
Это потому, что в Python, все тригонометрические функции использовать радианы, а не в градусах.
вы можете либо преобразовать числа вручную в радианы, либо использовать radians
функции модуля Math:
from math import sin, cos, sqrt, atan2, radians
# approximate radius of earth in km
R = 6373.0
lat1 = radians(52.2296756)
lon1 = radians(21.0122287)
lat2 = radians(52.406374)
lon2 = radians(16.9251681)
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))
distance = R * c
print("Result:", distance)
print("Should be:", 278.546, "km")
расстояние теперь возвращает правильное значение 278.545589351
km.
Edit: просто как Примечание, Если вы наткнулись на этот пост, потому что вы просто нужен быстрый и простой способ нахождения расстояния между два момента, я рекомендую вам использовать подход, рекомендованный в Курт ниже-см. свой пост для обоснования.
обновление: 04/2018: обратите внимание, что расстояние Vincenty устарело с версии GeoPy 1.13 - вы должны использовать geopy.расстояние.расстояние() вместо этого!
ответы выше основаны на формула Гаверсинуса, который предполагает, что Земля является сферой, что приводит к ошибкам до 0,5% (согласно help(geopy.distance)
). расстояние Vincenty использует более точные эллипсоидальные модели, такие как WGS-84, и реализовано в geopy. Например,
import geopy.distance
coords_1 = (52.2296756, 21.0122287)
coords_2 = (52.406374, 16.9251681)
print geopy.distance.vincenty(coords_1, coords_2).km
будет печатать расстоянии 279.352901604
километры с использованием эллипсоида WGS-84 по умолчанию. (Вы также можете выбрать .miles
или один из нескольких других единицах расстояния).
для людей (таких как я), приходящих сюда через поисковую систему и просто ищущих решение, которое работает из коробки, я рекомендую установить mpu
. Установите его через pip install mpu --user
и используйте его так, чтобы получить haversine расстояние:
import mpu
# Point one
lat1 = 52.2296756
lon1 = 21.0122287
# Point two
lat2 = 52.406374
lon2 = 16.9251681
# What you were looking for
dist = mpu.haversine_distance((lat1, lon1), (lat2, lon2))
print(dist) # gives 278.45817507541943.
альтернативный пакет gpxpy
.
если вы не хотите зависимостей, вы можете использовать:
import math
def distance(origin, destination):
"""
Calculate the Haversine distance.
Parameters
----------
origin : tuple of float
(lat, long)
destination : tuple of float
(lat, long)
Returns
-------
distance_in_km : float
Examples
--------
>>> origin = (48.1372, 11.5756) # Munich
>>> destination = (52.5186, 13.4083) # Berlin
>>> round(distance(origin, destination), 1)
504.2
"""
lat1, lon1 = origin
lat2, lon2 = destination
radius = 6371 # km
dlat = math.radians(lat2 - lat1)
dlon = math.radians(lon2 - lon1)
a = (math.sin(dlat / 2) * math.sin(dlat / 2) +
math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) *
math.sin(dlon / 2) * math.sin(dlon / 2))
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
d = radius * c
return d
if __name__ == '__main__':
import doctest
doctest.testmod()