J'ai essayé d'implémenter cette formule: http://andrew.hedges.name/experiments/haversine/ L'aplet fait du bien aux deux points que je teste:
Pourtant, mon code ne fonctionne pas.
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
La distance qu'il retourne est 5447.05546147 . Pourquoi?
Modifiez: Remarque: si vous avez simplement besoin d’un moyen simple et rapide de déterminer la distance entre deux points, je vous recommande vivement d’utiliser l’approche décrite dans réponse de Kurt ci-dessous au lieu de ré-implémenter Haversine - voir son post pour les raisons.
Cette réponse se concentre uniquement sur le bogue spécifique rencontré par l'OP.
C'est parce qu'en Python, toutes les fonctions trigonométriques tilisent des radians , pas des degrés.
Vous pouvez convertir les nombres manuellement en radians ou utiliser la fonction radians
du module mathématique:
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")
La distance renvoie maintenant la valeur correcte de 278.545589351
km.
Mise à jour: 04/2018: Notez que la distance de Vincenty est obsolète depuis la version de GeoPy 1.1 - vous devez utiliser geopy.distance.distance. () au lieu!
Les réponses ci-dessus sont basées sur le formule de Haversine , qui suppose que la Terre est une sphère, ce qui entraîne des erreurs pouvant atteindre environ 0,5% (selon help(geopy.distance)
). Vincenty distance utilise des modèles ellipsoïdaux plus précis, tels que WGS-84 , et est implémenté dans geopy . Par exemple,
import geopy.distance
coords_1 = (52.2296756, 21.0122287)
coords_2 = (52.406374, 16.9251681)
print geopy.distance.vincenty(coords_1, coords_2).km
imprimera la distance de 279.352901604
kilomètres en utilisant l’ellipsoïde par défaut WGS-84. (Vous pouvez également choisir .miles
ou l'une des autres unités de distance).
Pour les personnes (comme moi) venant ici via un moteur de recherche et cherchant une solution qui fonctionne immédiatement, je recommande l'installation de mpu
. Installez-le via pip install mpu --user
et utilisez-le comme ceci pour obtenir le distance 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.
Un autre package est gpxpy
.
Si vous ne voulez pas de dépendances, vous pouvez utiliser:
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 __== '__main__':
import doctest
doctest.testmod()
Je suis arrivé à une solution beaucoup plus simple et robuste qui utilise le paquet geodesic
de geopy
car vous l'utiliserez très probablement dans votre projet de toute façon, aucune installation de paquet supplémentaire n'est donc nécessaire.
Voici ma solution:
from geopy.distance import geodesic
Origin = (30.172705, 31.526725) # (latitude, longitude) don't confuse
dist = (30.288281, 31.732326)
print(geodesic(Origin, dist).meters) # 23576.805481751613
print(geodesic(Origin, dist).kilometers) # 23.576805481751613
print(geodesic(Origin, dist).miles) # 14.64994773134371
import numpy as np
def Haversine(lat1,lon1,lat2,lon2, **kwarg):
"""
This uses the ‘haversine’ formula to calculate the great-circle distance between two points – that is,
the shortest distance over the earth’s surface – giving an ‘as-the-crow-flies’ distance between the points
(ignoring any hills they fly over, of course!).
Haversine
formula: a = sin²(Δφ/2) + cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2)
c = 2 ⋅ atan2( √a, √(1−a) )
d = R ⋅ c
where φ is latitude, λ is longitude, R is earth’s radius (mean radius = 6,371km);
note that angles need to be in radians to pass to trig functions!
"""
R = 6371.0088
lat1,lon1,lat2,lon2 = map(np.radians, [lat1,lon1,lat2,lon2])
dlat = lat2 - lat1
dlon = lon2 - lon1
a = np.sin(dlat/2)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2) **2
c = 2 * np.arctan2(a**0.5, (1-a)**0.5)
d = R * c
return round(d,4)