Da dies die beliebteste Diskussion zum Thema ist, werde ich hier meine Erfahrung aus Ende 2019-Anfang 2020 hinzufügen. Um den vorhandenen Antworten hinzuzufügen - mein Fokus lag darauf, eine genaue UND schnelle (d.h. vektorisierte) Lösung zu finden.
Beginnen wir mit dem, was hier hauptsächlich von Antworten verwendet wird - der Haversine-Ansatz. Es ist trivial zu vektorisieren, siehe Beispiel in Python unten:
def haversine(lat1, lon1, lat2, lon2):
"""
Berechnet den Großkreisabstand zwischen zwei Punkten auf der Erde
(angegeben in Dezimalgrad)
Alle Argumente müssen die gleiche Länge haben.
Die Entfernungen sind in Metern angegeben.
Ref:
https://stackoverflow.com/questions/29545704/fast-haversine-approximation-python-pandas
https://ipython.readthedocs.io/en/stable/interactive/magics.html
"""
Radius = 6.371e6
lon1, lat1, lon2, lat2 = map(np.radians, [lon1, lat1, lon2, lat2])
dlon = lon2 - lon1
dlat = lat2 - lat1
a = np.sin(dlat/2.0)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2.0)**2
c = 2 * np.arcsin(np.sqrt(a))
s12 = Radius * c
# Anfangs-Azimut in Grad
y = np.sin(lon2-lon1) * np.cos(lat2)
x = np.cos(lat1)*np.sin(lat2) - np.sin(lat1)*np.cos(lat2)*np.cos(dlon)
azi1 = np.arctan2(y, x)*180./math.pi
return {'s12':s12, 'azi1': azi1}
In Bezug auf die Genauigkeit ist es am wenigsten genau. Wikipedia gibt eine relative Abweichung von durchschnittlich 0,5% ohne Quellen an. Meine Experimente zeigen weniger Abweichung. Hier ist ein Vergleich anhand von 100.000 zufälligen Punkten mit meiner Bibliothek, die auf Millimeterebene genau sein sollte:
np.random.seed(42)
lats1 = np.random.uniform(-90,90,100000)
lons1 = np.random.uniform(-180,180,100000)
lats2 = np.random.uniform(-90,90,100000)
lons2 = np.random.uniform(-180,180,100000)
r1 = inverse(lats1, lons1, lats2, lons2)
r2 = haversine(lats1, lons1, lats2, lons2)
print("Maximaler absoluter Fehler: {:4.2f}m".format(np.max(r1['s12']-r2['s12'])))
print("Durchschnittlicher absoluter Fehler: {:4.2f}m".format(np.mean(r1['s12']-r2['s12'])))
print("Maximaler relativer Fehler: {:4.2f}%".format(np.max((r2['s12']/r1['s12']-1)*100)))
print("Durchschnittlicher relativer Fehler: {:4.2f}%".format(np.mean((r2['s12']/r1['s12']-1)*100)))
Ausgabe:
Maximaler absoluter Fehler: 26671,47m
Durchschnittlicher absoluter Fehler: -2499,84m
Maximaler relativer Fehler: 0,55%
Durchschnittlicher relativer Fehler: -0,02%
Im Durchschnitt also eine Abweichung von 2,5km bei 100.000 zufälligen Koordinatenpaaren, was für die meisten Fälle akzeptabel sein könnte.
Die nächste Option ist die Vincenty-Formeln, die genau bis zu Millimetern sind, abhängig von Konvergenzkriterien und auch vektorisierbar sind. Es gibt jedoch ein Problem mit der Konvergenz in der Nähe von antipodalen Punkten. Sie können die Konvergenz an diesen Punkten erhöhen, indem Sie die Konvergenzkriterien lockern, aber die Genauigkeit sinkt auf 0,25% und mehr. Außerhalb antipodaler Punkte wird Vincenty Ergebnisse liefern, die im Durchschnitt eine relative Fehlerabweichung von weniger als 1.e-6 aufweisen.
Geographiclib, hier erwähnt, ist wirklich der aktuelle Goldstandard. Es hat mehrere Implementierungen und ist ziemlich schnell, insbesondere wenn Sie die C++-Version verwenden.
Wenn Sie also vorhaben, Python für mehr als 10.000 Punkte zu verwenden, würde ich vorschlagen, meine vektorisierte Implementierung in Betracht zu ziehen. Ich habe eine geovectorslib-Bibliothek mit einer vektorisierten Vincenty-Routine für meine eigenen Bedürfnisse erstellt, die Geographiclib als Ausweichlösung für nahe antipodale Punkte verwendet. Hier ist der Vergleich mit Geographiclib für 100k Punkte. Wie Sie sehen können, bietet es eine Verbesserung um bis zu 20x für invers und 100x für direkt Methoden für 100k Punkte und der Unterschied wird mit der Anzahl der Punkte wachsen. In Bezug auf die Genauigkeit wird sie etwa 1.e-5 rtol von Georgraphiclib betragen.
Direkte Methode für 100.000 Punkte
94,9 ms ± 25 ms pro Schleife (Mittelwert ± Std.-Abweichung von 7 Durchläufen, 1 Schleife pro Durchlauf)
9,79 s ± 1,4 s pro Schleife (Mittelwert ± Std.-Abweichung von 7 Durchläufen, 1 Schleife pro Durchlauf)
Inverse Methode für 100.000 Punkte
1,5 s ± 504 ms pro Schleife (Mittelwert ± Std.-Abweichung von 7 Durchläufen, 1 Schleife pro Durchlauf)
24,2 s ± 3,91 s pro Schleife (Mittelwert ± Std.-Abweichung von 7 Durchläufen, 1 Schleife pro Durchlauf)
0 Stimmen
Für eine bessere Genauigkeit - siehe stackoverflow.com/questions/1420045/…
4 Stimmen
Beachten Sie, dass Sie die Haversine-Formel nicht auf einem Rotationsellipsoid wie WGS 84 anwenden können. Sie können diese Methode nur auf einer Kugel mit einem Radius anwenden.
8 Stimmen
Die meisten Antworten hier verwenden einfache sphärische Trigonometrie, daher sind die Ergebnisse im Vergleich zu den WGS84-Ellipsoidentfernungen, die im GPS-System verwendet werden, ziemlich grob. Einige der Antworten beziehen sich zwar auf die Vincenty-Formel für Ellipsoide, aber dieser Algorithmus wurde für die Verwendung auf Schreibtischrechnern aus den 1960er Jahren entwickelt und weist Stabilitäts- und Genauigkeitsprobleme auf; wir haben jetzt bessere Hardware und Software. Bitte sehen Sie GeographicLib für eine hochwertige Bibliothek mit Implementierungen in verschiedenen Sprachen.
0 Stimmen
@MikeT - das stimmt, obwohl viele der Antworten hier nützlich zu sein scheinen über kleine Entfernungen: Wenn Sie Breiten- / Längengrad von WGS 84 nehmen und Haversine wie wenn es Punkte auf einer Kugel anwenden, erhalten Sie Antworten, deren Fehler nur auf den Erdabplattungsfaktor zurückzuführen sind, vielleicht also innerhalb von 1% einer genaueren Formel? Mit der Einschränkung, dass es sich um kleine Entfernungen handelt, sagen wir innerhalb einer einzigen Stadt.
1 Stimmen
Für diese Plattformen: Mono/.NET 4.5/.NET Core/Windows Phone 8.x/Universal Windows Platform/Xamarin iOS/Xamarin Android siehe stackoverflow.com/a/54296314/2736742
0 Stimmen
Siehe auch diese großartige Python-Antwort: Schnelle Haversine-Approximation (Python/Pandas)