Abstand zwischen zwei Längen- und Breitengraden berechnen? (Haversine Formel)


906

Wie berechne ich den Abstand zwischen zwei durch Längen- und Breitengrad angegebenen Punkten?

Zur Verdeutlichung möchte ich die Entfernung in Kilometern; Die Punkte verwenden das WGS84-System und ich möchte die relativen Genauigkeiten der verfügbaren Ansätze verstehen.


Für eine bessere Genauigkeit - siehe stackoverflow.com/questions/1420045/…
Lior Kogan

3
Beachten Sie, dass Sie eine Haversine-Formel nicht auf ein Rotationsellipsoid wie WGS 84 anwenden können. Sie können diese Methode nur auf eine Kugel mit einem Radius anwenden.
Mike T

3
Die meisten Antworten hier verwenden einfache sphärische Trigonometrie, daher sind die Ergebnisse im Vergleich zu den im GPS-System verwendeten WGS84-Ellipsoidabständen ziemlich grob. Einige der Antworten beziehen sich auf Vincentys 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. In GeographicLib finden Sie eine hochwertige Bibliothek mit Implementierungen in verschiedenen Sprachen.
PM 2Ring

@MikeT - wahr, obwohl viele der Antworten hier über kleine Entfernungen nützlich erscheinen : Wenn Sie Lat / Long von WGS 84 nehmen und Haversine anwenden, als wären dies Punkte auf einer Kugel, erhalten Sie keine Antworten, deren Fehler nur auf zurückzuführen sind der Abflachungsfaktor der Erde, also vielleicht innerhalb von 1% einer genaueren Formel? Mit der Einschränkung, dass dies kleine Entfernungen sind, etwa innerhalb einer einzelnen Stadt.
ToolmakerSteve

1
Für diese Plattenformen: Mono / .NET 4.5 / .NET Core / Windows Phone 8.x / Universelle Windows-Plattform / Xamarin iOS / Xamarin Android siehe stackoverflow.com/a/54296314/2736742
A. Morel

Antworten:


1146

Dieser Link kann für Sie hilfreich sein, da er die Verwendung der Haversine-Formel zur Berechnung der Entfernung beschreibt.

Auszug:

Dieses Skript [in Javascript] berechnet Großkreisabstände zwischen den beiden Punkten - das heißt den kürzesten Abstand über der Erdoberfläche - unter Verwendung der 'Haversine'-Formel.

function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2) {
  var R = 6371; // Radius of the earth in km
  var dLat = deg2rad(lat2-lat1);  // deg2rad below
  var dLon = deg2rad(lon2-lon1); 
  var a = 
    Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * 
    Math.sin(dLon/2) * Math.sin(dLon/2)
    ; 
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
  var d = R * c; // Distance in km
  return d;
}

function deg2rad(deg) {
  return deg * (Math.PI/180)
}

51
Berücksichtigt diese Berechnung / Methode, dass die Erde ein Sphäroid ist (keine perfekte Kugel)? In der ursprünglichen Frage wurde nach dem Abstand zwischen Punkten auf einem WGS84-Globus gefragt. Ich bin mir nicht sicher, wie viel Fehler sich bei Verwendung einer perfekten Kugel einschleicht, aber ich vermute, dass es ziemlich viel sein kann, je nachdem, wo sich die Punkte auf dem Globus befinden. Daher ist die Unterscheidung zu berücksichtigen.
Redcalx

15
Die Haversine-Formel berücksichtigt nicht, dass die Erde ein Sphäroid ist, daher wird aufgrund dieser Tatsache ein Fehler eingeführt. Es kann nicht garantiert werden, dass es besser als 0,5% ist. Dies kann jedoch eine akzeptable Fehlerquote sein oder auch nicht.
Brandon

24
Gibt es einen Grund, Math.atan2(Math.sqrt(a), Math.sqrt(1-a))stattdessen Math.asin(Math.sqrt(h))die Formel zu verwenden , die die direkte Implementierung der Formel ist, die der Wikipedia-Artikel verwendet? Ist es effizienter und / oder numerisch stabiler?
Musiphil

16
@UsmanMutawakil Nun, die 38 Meilen, die Sie bekommen, sind Entfernung auf der Straße. Dieser Algorithmus berechnet einen geraden Abstand auf der Erdoberfläche. Google Maps verfügt über ein Entfernungswerkzeug (unten links, "Labs"), das dasselbe tut. Verwenden Sie dieses zum Vergleichen.
Pascal

4
@ Forte_201092: Weil das nicht notwendig ist - wie (sin(x))²equals(sin(-x))²
Jean Hominal

359

Ich musste viele Entfernungen zwischen den Punkten für mein Projekt berechnen, also habe ich versucht, den Code zu optimieren, den ich hier gefunden habe. Im Durchschnitt läuft meine neue Implementierung in verschiedenen Browsern zweimal schneller als die am besten bewertete Antwort.

function distance(lat1, lon1, lat2, lon2) {
  var p = 0.017453292519943295;    // Math.PI / 180
  var c = Math.cos;
  var a = 0.5 - c((lat2 - lat1) * p)/2 + 
          c(lat1 * p) * c(lat2 * p) * 
          (1 - c((lon2 - lon1) * p))/2;

  return 12742 * Math.asin(Math.sqrt(a)); // 2 * R; R = 6371 km
}

Sie können mit meinem jsPerf spielen und die Ergebnisse hier sehen .

Vor kurzem musste ich dasselbe in Python tun, daher hier eine Python-Implementierung :

from math import cos, asin, sqrt, pi

def distance(lat1, lon1, lat2, lon2):
    p = pi/180
    a = 0.5 - cos((lat2-lat1)*p)/2 + cos(lat1*p) * cos(lat2*p) * (1-cos((lon2-lon1)*p))/2
    return 12742 * asin(sqrt(a)) #2*R*asin...

Und der Vollständigkeit halber: Haversine im Wiki.


13
@AngularM und es ist sehr wahrscheinlich, dass Google die Entfernung berechnet, wenn Sie einige Straßen und keine gerade Linie nehmen.
Salvador Dali

3
Google berechnet die Fahrstrecke, dies berechnet "in Luftlinie"
Hobbyist

4
@Ouadie und wird es die Geschwindigkeit verbessern? Höchstwahrscheinlich nein, aber ich werde am Ende eine Menge "Ihre Sachen funktionieren nicht" für Leute haben, die sie in alten Browsern kopieren
Salvador Dali

4
na ja aber wofür // 2 * R; R = 6371 kmsteht das? und die aktuelle Methode liefert Antwort in km oder Meilen? braucht eine bessere Dokumentation. Vielen Dank
Khalil Khalaf

20
@KhalilKhalaf machst du Witze oder versuchst du hier zu trollen? km steht für Kilometer. Wofür steht R Ihrer Meinung nach (besonders wenn wir von einem Shpere sprechen)? Erraten Sie, in welchen Einheiten die Antwort lautet, wenn Sie den km bereits sehen. Welche Art von Dokumentation suchen Sie hier: Es gibt dort buchstäblich 4 Zeilen.
Salvador Dali

69

Hier ist eine C # -Implementierung:

static class DistanceAlgorithm
{
    const double PIx = 3.141592653589793;
    const double RADIUS = 6378.16;

    /// <summary>
    /// Convert degrees to Radians
    /// </summary>
    /// <param name="x">Degrees</param>
    /// <returns>The equivalent in radians</returns>
    public static double Radians(double x)
    {
        return x * PIx / 180;
    }

    /// <summary>
    /// Calculate the distance between two places.
    /// </summary>
    /// <param name="lon1"></param>
    /// <param name="lat1"></param>
    /// <param name="lon2"></param>
    /// <param name="lat2"></param>
    /// <returns></returns>
    public static double DistanceBetweenPlaces(
        double lon1,
        double lat1,
        double lon2,
        double lat2)
    {
        double dlon = Radians(lon2 - lon1);
        double dlat = Radians(lat2 - lat1);

        double a = (Math.Sin(dlat / 2) * Math.Sin(dlat / 2)) + Math.Cos(Radians(lat1)) * Math.Cos(Radians(lat2)) * (Math.Sin(dlon / 2) * Math.Sin(dlon / 2));
        double angle = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
        return angle * RADIUS;
    }

}

14
Sie verwenden den äquatorialen Radius, aber Sie sollten den mittleren Radius verwenden, der 6371 km beträgt
Philippe Leybaert

7
Sollte das nicht sein double dlon = Radians(lon2 - lon1);unddouble dlat = Radians(lat2 - lat1);
Chris Marisic

Ich stimme Chris Marisic zu. Ich habe den Originalcode verwendet und die Berechnungen waren falsch. Ich habe den Aufruf hinzugefügt, die Deltas in Bogenmaß umzuwandeln, und es funktioniert jetzt ordnungsgemäß. Ich habe eine Bearbeitung eingereicht und warte darauf, dass sie einer Peer-Review unterzogen wird.
Bryan Bedard

Ich habe eine weitere Bearbeitung eingereicht, da lat1 & lat2 ebenfalls in Bogenmaß konvertiert werden müssen. Ich habe auch die Formel für die Zuordnung zu a überarbeitet, um sie an die hier gefundene Formel und den Code anzupassen
Bryan Bedard

Muss der RADIUSWert wie in den anderen Antworten 6371 sein?
Chris Hayes

66

Hier ist eine Java-Implementierung der Haversine-Formel.

public final static double AVERAGE_RADIUS_OF_EARTH_KM = 6371;
public int calculateDistanceInKilometer(double userLat, double userLng,
  double venueLat, double venueLng) {

    double latDistance = Math.toRadians(userLat - venueLat);
    double lngDistance = Math.toRadians(userLng - venueLng);

    double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
      + Math.cos(Math.toRadians(userLat)) * Math.cos(Math.toRadians(venueLat))
      * Math.sin(lngDistance / 2) * Math.sin(lngDistance / 2);

    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

    return (int) (Math.round(AVERAGE_RADIUS_OF_EARTH_KM * c));
}

Beachten Sie, dass wir hier die Antwort auf den nächsten km runden.


2
Wenn wir den Abstand zwischen zwei Punkten in Metern berechnen wollten, was wäre der genauere Weg? Zur Verwendung 6371000als der Radius der Erde? (Der durchschnittliche Erdradius beträgt 6371000 Meter) oder Kilometer in Meter von Ihrer Funktion umrechnen?
Micro

Wenn Sie Meilen wollen, 0.621371
multiplizieren

42

Vielen Dank für all das. Ich habe den folgenden Code in meiner Objective-C iPhone-App verwendet:

const double PIx = 3.141592653589793;
const double RADIO = 6371; // Mean radius of Earth in Km

double convertToRadians(double val) {

   return val * PIx / 180;
}

-(double)kilometresBetweenPlace1:(CLLocationCoordinate2D) place1 andPlace2:(CLLocationCoordinate2D) place2 {

        double dlon = convertToRadians(place2.longitude - place1.longitude);
        double dlat = convertToRadians(place2.latitude - place1.latitude);

        double a = ( pow(sin(dlat / 2), 2) + cos(convertToRadians(place1.latitude))) * cos(convertToRadians(place2.latitude)) * pow(sin(dlon / 2), 2);
        double angle = 2 * asin(sqrt(a));

        return angle * RADIO;
}

Breite und Länge sind dezimal. Ich habe min () nicht für den Aufruf von asin () verwendet, da die Entfernungen, die ich verwende, so klein sind, dass sie es nicht erfordern.

Es gab falsche Antworten, bis ich die Werte im Bogenmaß übergab - jetzt sind es fast die gleichen wie die Werte, die von Apples Karten-App erhalten wurden :-)

Zusätzliches Update:

Wenn Sie iOS4 oder höher verwenden, bietet Apple einige Methoden an, um die gleiche Funktionalität zu erzielen:

-(double)kilometresBetweenPlace1:(CLLocationCoordinate2D) place1 andPlace2:(CLLocationCoordinate2D) place2 {

    MKMapPoint  start, finish;


    start = MKMapPointForCoordinate(place1);
    finish = MKMapPointForCoordinate(place2);

    return MKMetersBetweenMapPoints(start, finish) / 1000;
}

1
iOS SDK hat eine eigene Implementierung: developer.apple.com/library/ios/documentation/CoreLocation/… :
tuler

Ich denke, die Klammer pow(sin(dlat / 2), 2) + cos(convertToRadians(place1.latitude))ist falsch. Entfernen Sie diese, und das Ergebnis stimmt mit dem überein, was ich erhalte, wenn ich andere Implementierungen auf dieser Seite verwende oder die Haversine-Formel von Wikipedia von Grund auf neu implementiere .
Zanedp

Unter Verwendung der Koordinaten (40.7127837, -74.0059413) für NYC und (34.052234, -118.243685) für LA mit der ()ungefähren Summe erhalte ich 3869,75. Ohne sie bekomme ich 3935.75, was ziemlich genau das ist, was eine Websuche ergibt.
Zanedp

40

Dies ist eine einfache PHP-Funktion, die eine sehr vernünftige Annäherung liefert (unter +/- 1% Fehlerquote).

<?php
function distance($lat1, $lon1, $lat2, $lon2) {

    $pi80 = M_PI / 180;
    $lat1 *= $pi80;
    $lon1 *= $pi80;
    $lat2 *= $pi80;
    $lon2 *= $pi80;

    $r = 6372.797; // mean radius of Earth in km
    $dlat = $lat2 - $lat1;
    $dlon = $lon2 - $lon1;
    $a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlon / 2) * sin($dlon / 2);
    $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
    $km = $r * $c;

    //echo '<br/>'.$km;
    return $km;
}
?>

Wie gesagt; Die Erde ist keine Kugel. Es ist wie ein alter Baseball, mit dem Mark McGwire trainieren wollte - er ist voller Dellen und Beulen. Die einfacheren Berechnungen (wie diese) behandeln es wie eine Kugel.

Verschiedene Methoden können mehr oder weniger genau sein, je nachdem, wo Sie sich auf diesem unregelmäßigen Ovoid befinden UND wie weit Ihre Punkte voneinander entfernt sind (je näher sie sind, desto kleiner ist die absolute Fehlergrenze). Je genauer Ihre Erwartungen sind, desto komplexer ist die Mathematik.

Für weitere Informationen: Wikipedia geografische Entfernung


4
Das funktioniert perfekt! Ich habe gerade $ distance_miles = $ km * 0.621371 hinzugefügt. und das ist alles, was ich für die ungefähre Entfernung in Meilen brauchte! Danke Tony.

31

Ich poste hier mein Arbeitsbeispiel.

Listen Sie alle Punkte in der Tabelle mit einem Abstand zwischen einem bestimmten Punkt auf (wir verwenden einen zufälligen Punkt - lat: 45.20327, long: 23.7806), der weniger als 50 km lang ist, mit Längen- und Breitengrad in MySQL (die Tabellenfelder sind coord_lat und coord_long):

Listen Sie alle mit einem Abstand <50 in Kilometern auf (als Erdradius 6371 km betrachtet):

SELECT denumire, (6371 * acos( cos( radians(45.20327) ) * cos( radians( coord_lat ) ) * cos( radians( 23.7806 ) - radians(coord_long) ) + sin( radians(45.20327) ) * sin( radians(coord_lat) ) )) AS distanta 
FROM obiective 
WHERE coord_lat<>'' 
    AND coord_long<>'' 
HAVING distanta<50 
ORDER BY distanta desc

Das obige Beispiel wurde in MySQL 5.0.95 und 5.5.16 (Linux) getestet.


Ich denke, ein guter Ansatz könnte darin bestehen, die Ergebnisse mit einer Annäherung vorzufiltern, sodass die schwere Formel nur in einigen Fällen angewendet wird. Besonders nützlich, wenn Sie andere Bedingungen haben. Ich benutze dies für den ersten ungefähr: stackoverflow.com/questions/1253499/…
Pato

28

In den anderen Antworten eine Implementierung in wird vermisst.

Die Berechnung des Abstands zwischen zwei Punkten ist mit der distmFunktion aus dem geospherePaket ganz einfach :

distm(p1, p2, fun = distHaversine)

wo:

p1 = longitude/latitude for point(s)
p2 = longitude/latitude for point(s)
# type of distance calculation
fun = distCosine / distHaversine / distVincentySphere / distVincentyEllipsoid 

Da die Erde nicht perfekt kugelförmig ist, ist die Vincenty-Formel für Ellipsoide wahrscheinlich der beste Weg, um Entfernungen zu berechnen. Also in dem geospherePaket, das Sie dann verwenden:

distm(p1, p2, fun = distVincentyEllipsoid)

Natürlich müssen Sie nicht unbedingt das geospherePaket verwenden, sondern können die Entfernung in der Basis auch Rmit einer Funktion berechnen :

hav.dist <- function(long1, lat1, long2, lat2) {
  R <- 6371
  diff.long <- (long2 - long1)
  diff.lat <- (lat2 - lat1)
  a <- sin(diff.lat/2)^2 + cos(lat1) * cos(lat2) * sin(diff.long/2)^2
  b <- 2 * asin(pmin(1, sqrt(a))) 
  d = R * b
  return(d)
}

Um sicherzugehen, dass mir klar ist, was Sie gesagt haben: Der Code, den Sie am Ende des Beitrags angeben: Ist das eine Implementierung der Vincenty-Formel? Soweit Sie wissen, sollte es die gleiche Antwort geben wie Vincenty in der Geosphäre anzurufen? [Ich habe keine Geosphäre oder andere Bibliothek; Ich suche nur nach Code, der in eine plattformübergreifende App aufgenommen werden kann. Ich würde natürlich einige Testfälle gegen einen bekanntermaßen guten Taschenrechner verifizieren.]
ToolmakerSteve

1
@ ToolmakerSteve die Funktion am Ende meiner Antwort ist eine Implementierung der Haversine-Methode
Jaap

Hallo @Jaap, könnte ich fragen, was ist die Maßeinheit für die Formel? Ist es in Metern?
Jackson

11

Der Haversine ist definitiv eine gute Formel für wahrscheinlich die meisten Fälle, andere Antworten enthalten ihn bereits, so dass ich den Platz nicht einnehmen werde. Es ist jedoch wichtig zu beachten, dass unabhängig von der verwendeten Formel (ja, nicht nur eine). Aufgrund des enormen Genauigkeitsbereichs sowie der erforderlichen Rechenzeit. Die Wahl der Formel erfordert etwas mehr Gedanken als eine einfache Antwort.

Dieser Beitrag von einer Person bei der NASA ist der beste, den ich bei der Erörterung der Optionen gefunden habe

http://www.cs.nyu.edu/visual/home/proj/tiger/gisfaq.html

Zum Beispiel, wenn Sie nur Zeilen nach Entfernung in einem Radius von 100 Meilen sortieren. Die Flat-Earth-Formel ist viel schneller als der Haversine.

HalfPi = 1.5707963;
R = 3956; /* the radius gives you the measurement unit*/

a = HalfPi - latoriginrad;
b = HalfPi - latdestrad;
u = a * a + b * b;
v = - 2 * a * b * cos(longdestrad - longoriginrad);
c = sqrt(abs(u + v));
return R * c;

Beachten Sie, dass es nur einen Kosinus und eine Quadratwurzel gibt. Vs 9 von ihnen auf der Haversine-Formel.


Das ist eine schöne Möglichkeit. Beachten Sie jedoch, dass die empfohlene maximale Entfernung in der Diskussion 12 Meilen und nicht 100 beträgt. Trotzdem können Fehler je nach Position des Globus bis zu 30 Meter (100 Fuß) dauern.
Eric Wu

7

Sie können den Build in CLLocationDistance verwenden, um dies zu berechnen:

CLLocation *location1 = [[CLLocation alloc] initWithLatitude:latitude1 longitude:longitude1];
CLLocation *location2 = [[CLLocation alloc] initWithLatitude:latitude2 longitude:longitude2];
[self distanceInMetersFromLocation:location1 toLocation:location2]

- (int)distanceInMetersFromLocation:(CLLocation*)location1 toLocation:(CLLocation*)location2 {
    CLLocationDistance distanceInMeters = [location1 distanceFromLocation:location2];
    return distanceInMeters;
}

In Ihrem Fall, wenn Sie Kilometer wollen, teilen Sie einfach durch 1000.


7

Ich mag es nicht, noch eine Antwort hinzuzufügen, aber die Google Maps API v.3 hat sphärische Geometrie (und mehr). Nachdem Sie Ihren WGS84 in Dezimalgrade konvertiert haben, können Sie Folgendes tun:

<script src="http://maps.google.com/maps/api/js?sensor=false&libraries=geometry" type="text/javascript"></script>  

distance = google.maps.geometry.spherical.computeDistanceBetween(
    new google.maps.LatLng(fromLat, fromLng), 
    new google.maps.LatLng(toLat, toLng));

Kein Wort darüber, wie genau die Berechnungen von Google sind oder welches Modell verwendet wird (obwohl es eher "sphärisch" als "geoid" heißt. Übrigens unterscheidet sich die "gerade Linie" offensichtlich von der Entfernung, wenn man auf dem fährt Erdoberfläche, die jeder anzunehmen scheint.


Entfernung ist in Metern. Alternativ kann man computeLength () verwenden
electrobabe

7

Python-Implementierung Origin ist das Zentrum der angrenzenden Vereinigten Staaten.

from haversine import haversine
origin = (39.50, 98.35)
paris = (48.8567, 2.3508)
haversine(origin, paris, miles=True)

Um die Antwort in Kilometern zu erhalten, setzen Sie einfach Meilen = falsch.


1
Sie importieren ein nicht standardmäßiges Paket, das die ganze Arbeit erledigt. Ich weiß nicht, ob das so nützlich ist.
Teepeemm

Das Paket befindet sich im PyPI, Python Package Index, als Python 3-Paket zusammen mit Numpy und Scikit-Learn. Ich bin mir nicht sicher, warum man an Pakete gebunden ist. Sie neigen dazu, sehr nützlich zu sein. Als Open Source könnte man auch die enthaltenen Methoden untersuchen. Ich denke, viele würden dieses Paket nützlich finden, so dass ich den Beitrag trotz der Ablehnung verlassen werde. Prost. :)
Invoketheshell

7

Es könnte eine einfachere und korrektere Lösung geben: Der Erdumfang am Äquator beträgt 40.000 km, im Greenwich-Zyklus (oder einem beliebigen Längengrad) etwa 37.000 km. Somit:

pythagoras = function (lat1, lon1, lat2, lon2) {
   function sqr(x) {return x * x;}
   function cosDeg(x) {return Math.cos(x * Math.PI / 180.0);}

   var earthCyclePerimeter = 40000000.0 * cosDeg((lat1 + lat2) / 2.0);
   var dx = (lon1 - lon2) * earthCyclePerimeter / 360.0;
   var dy = 37000000.0 * (lat1 - lat2) / 360.0;

   return Math.sqrt(sqr(dx) + sqr(dy));
};

Ich bin damit einverstanden, dass es fein abgestimmt werden sollte, da ich selbst sagte, dass es ein Ellipsoid ist, so dass der Radius, der mit dem Kosinus multipliziert werden soll, variiert. Aber es ist etwas genauer. Im Vergleich zu Google Maps konnte der Fehler erheblich reduziert werden.


Ist diese Funktion Rücklaufstrecke in km?
Wikki

Es ist nur so, weil der Äquator und die Längenzyklen in km sind. Teilen Sie für Meilen einfach 40000 und 37000 durch 1,6. Wenn Sie sich geeky fühlen, können Sie es in Ris umwandeln, multiplizieren mit ungefähr 7 oder in Parasang, dividieren durch 2.2 ;-)
Meymann

Dies scheint die beste Antwort zu sein, die hier angeboten wird. Ich möchte es verwenden, frage mich aber nur, ob es eine Möglichkeit gibt, die Richtigkeit dieses Algorithmus zu überprüfen. Ich habe f (50,5,58,3) getestet. Es gibt 832 km, während movable-type.co.uk/scripts/latlong.html unter Verwendung der 'Haversine'-Formel 899 km ergibt. Gibt es so einen großen Unterschied?
Chong Lip Phang

Darüber hinaus denke ich, dass der vom obigen Code zurückgegebene Wert in m und nicht in km angegeben ist.
Chong Lip Phang

@ChongLipPhang - VORSICHT: Der Satz von Pythagoras ist nur eine vernünftige Annäherung für kleine Gebiete , da dieser Satz davon ausgeht, dass die Erde flach ist. Beginnen Sie im Extremfall am Äquator und bewegen Sie sich um 90 Grad nach Osten und 90 Grad nach Norden. Das Endergebnis ist natürlich der Nordpol und entspricht einer Bewegung von 0 Grad nach Osten und 90 Grad nach Norden. Wenn Sie also sqrt (sqr (dx) + sqr (dy)) ausführen, ist dies im ersten Fall nicht möglich. ~ sqrt (10 km sqr + 10 km sqrt) ~ = 14,4 km vs korrekte Entfernung ~ 10 km.
ToolmakerSteve

7

Alle obigen Antworten setzen voraus, dass die Erde eine Kugel ist. Eine genauere Annäherung wäre jedoch die eines abgeflachten Sphäroids.

a= 6378.137#equitorial radius in km
b= 6356.752#polar radius in km

def Distance(lat1, lons1, lat2, lons2):
    lat1=math.radians(lat1)
    lons1=math.radians(lons1)
    R1=(((((a**2)*math.cos(lat1))**2)+(((b**2)*math.sin(lat1))**2))/((a*math.cos(lat1))**2+(b*math.sin(lat1))**2))**0.5 #radius of earth at lat1
    x1=R*math.cos(lat1)*math.cos(lons1)
    y1=R*math.cos(lat1)*math.sin(lons1)
    z1=R*math.sin(lat1)

    lat2=math.radians(lat2)
    lons2=math.radians(lons2)
    R1=(((((a**2)*math.cos(lat2))**2)+(((b**2)*math.sin(lat2))**2))/((a*math.cos(lat2))**2+(b*math.sin(lat2))**2))**0.5 #radius of earth at lat2
    x2=R*math.cos(lat2)*math.cos(lons2)
    y2=R*math.cos(lat2)*math.sin(lons2)
    z2=R*math.sin(lat2)

    return ((x1-x2)**2+(y1-y2)**2+(z1-z2)**2)**0.5

6

Hier ist die SQL-Implementierung zur Berechnung der Entfernung in km:

SELECT UserId, ( 3959 * acos( cos( radians( your latitude here ) ) * cos( radians(latitude) ) * 
cos( radians(longitude) - radians( your longitude here ) ) + sin( radians( your latitude here ) ) * 
sin( radians(latitude) ) ) ) AS distance FROM user HAVING
distance < 5  ORDER BY distance LIMIT 0 , 5;

Für weitere Details in der Implementierung durch Programmieren der Sprache können Sie einfach das hier angegebene PHP-Skript durchgehen


5

Hier ist eine maschinengeschriebene Implementierung der Haversine-Formel

static getDistanceFromLatLonInKm(lat1: number, lon1: number, lat2: number, lon2: number): number {
    var deg2Rad = deg => {
        return deg * Math.PI / 180;
    }

    var r = 6371; // Radius of the earth in km
    var dLat = deg2Rad(lat2 - lat1);   
    var dLon = deg2Rad(lon2 - lon1);
    var a =
        Math.sin(dLat / 2) * Math.sin(dLat / 2) +
        Math.cos(deg2Rad(lat1)) * Math.cos(deg2Rad(lat2)) *
        Math.sin(dLon / 2) * Math.sin(dLon / 2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    var d = r * c; // Distance in km
    return d;
}

5

Wie bereits erwähnt, sollte eine genaue Berechnung berücksichtigen, dass die Erde keine perfekte Kugel ist. Hier einige Vergleiche der verschiedenen hier angebotenen Algorithmen:

geoDistance(50,5,58,3)
Haversine: 899 km
Maymenn: 833 km
Keerthana: 897 km
google.maps.geometry.spherical.computeDistanceBetween(): 900 km

geoDistance(50,5,-58,-3)
Haversine: 12030 km
Maymenn: 11135 km
Keerthana: 10310 km
google.maps.geometry.spherical.computeDistanceBetween(): 12044 km

geoDistance(.05,.005,.058,.003)
Haversine: 0.9169 km
Maymenn: 0.851723 km
Keerthana: 0.917964 km
google.maps.geometry.spherical.computeDistanceBetween(): 0.917964 km

geoDistance(.05,80,.058,80.3)
Haversine: 33.37 km
Maymenn: 33.34 km
Keerthana: 33.40767 km
google.maps.geometry.spherical.computeDistanceBetween(): 33.40770 km

Auf kleinen Entfernungen scheint der Algorithmus von Keerthana mit dem von Google Maps übereinzustimmen. Google Maps scheint keinem einfachen Algorithmus zu folgen, was darauf hindeutet, dass dies hier die genaueste Methode ist.

Wie auch immer, hier ist eine Javascript-Implementierung des Keerthana-Algorithmus:

function geoDistance(lat1, lng1, lat2, lng2){
    const a = 6378.137; // equitorial radius in km
    const b = 6356.752; // polar radius in km

    var sq = x => (x*x);
    var sqr = x => Math.sqrt(x);
    var cos = x => Math.cos(x);
    var sin = x => Math.sin(x);
    var radius = lat => sqr((sq(a*a*cos(lat))+sq(b*b*sin(lat)))/(sq(a*cos(lat))+sq(b*sin(lat))));

    lat1 = lat1 * Math.PI / 180;
    lng1 = lng1 * Math.PI / 180;
    lat2 = lat2 * Math.PI / 180;
    lng2 = lng2 * Math.PI / 180;

    var R1 = radius(lat1);
    var x1 = R1*cos(lat1)*cos(lng1);
    var y1 = R1*cos(lat1)*sin(lng1);
    var z1 = R1*sin(lat1);

    var R2 = radius(lat2);
    var x2 = R2*cos(lat2)*cos(lng2);
    var y2 = R2*cos(lat2)*sin(lng2);
    var z2 = R2*sin(lat2);

    return sqr(sq(x1-x2)+sq(y1-y2)+sq(z1-z2));
}

4

Dieses Skript [in PHP] berechnet die Abstände zwischen den beiden Punkten.

public static function getDistanceOfTwoPoints($source, $dest, $unit='K') {
        $lat1 = $source[0];
        $lon1 = $source[1];
        $lat2 = $dest[0];
        $lon2 = $dest[1];

        $theta = $lon1 - $lon2;
        $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
        $dist = acos($dist);
        $dist = rad2deg($dist);
        $miles = $dist * 60 * 1.1515;
        $unit = strtoupper($unit);

        if ($unit == "K") {
            return ($miles * 1.609344);
        }
        else if ($unit == "M")
        {
            return ($miles * 1.609344 * 1000);
        }
        else if ($unit == "N") {
            return ($miles * 0.8684);
        } 
        else {
            return $miles;
        }
    }

4

Java-Implementierung nach Haversine-Formel

double calculateDistance(double latPoint1, double lngPoint1, 
                         double latPoint2, double lngPoint2) {
    if(latPoint1 == latPoint2 && lngPoint1 == lngPoint2) {
        return 0d;
    }

    final double EARTH_RADIUS = 6371.0; //km value;

    //converting to radians
    latPoint1 = Math.toRadians(latPoint1);
    lngPoint1 = Math.toRadians(lngPoint1);
    latPoint2 = Math.toRadians(latPoint2);
    lngPoint2 = Math.toRadians(lngPoint2);

    double distance = Math.pow(Math.sin((latPoint2 - latPoint1) / 2.0), 2) 
            + Math.cos(latPoint1) * Math.cos(latPoint2)
            * Math.pow(Math.sin((lngPoint2 - lngPoint1) / 2.0), 2);
    distance = 2.0 * EARTH_RADIUS * Math.asin(Math.sqrt(distance));

    return distance; //km value
}

3

Um den Abstand zwischen zwei Punkten auf einer Kugel zu berechnen, müssen Sie die Großkreisberechnung durchführen .

Es gibt eine Reihe von C / C ++ - Bibliotheken, die bei der Kartenprojektion in MapTools helfen, wenn Sie Ihre Entfernungen auf eine ebene Fläche projizieren müssen. Dazu benötigen Sie die Projektionszeichenfolge der verschiedenen Koordinatensysteme.

Sie können MapWindow auch als nützliches Werkzeug zur Visualisierung der Punkte finden. Auch als Open Source ist es eine nützliche Anleitung zur Verwendung der proj.dll-Bibliothek, die anscheinend die zentrale Open Source-Projektionsbibliothek ist.


3

Hier ist die akzeptierte Antwortimplementierung, die auf Java portiert wurde, falls jemand sie benötigt.

package com.project529.garage.util;


/**
 * Mean radius.
 */
private static double EARTH_RADIUS = 6371;

/**
 * Returns the distance between two sets of latitudes and longitudes in meters.
 * <p/>
 * Based from the following JavaScript SO answer:
 * http://stackoverflow.com/questions/27928/calculate-distance-between-two-latitude-longitude-points-haversine-formula,
 * which is based on https://en.wikipedia.org/wiki/Haversine_formula (error rate: ~0.55%).
 */
public double getDistanceBetween(double lat1, double lon1, double lat2, double lon2) {
    double dLat = toRadians(lat2 - lat1);
    double dLon = toRadians(lon2 - lon1);

    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
            Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
                    Math.sin(dLon / 2) * Math.sin(dLon / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    double d = EARTH_RADIUS * c;

    return d;
}

public double toRadians(double degrees) {
    return degrees * (Math.PI / 180);
}

2

Hier ist die Implementierung VB.NET. Diese Implementierung gibt Ihnen das Ergebnis in KM oder Meilen basierend auf einem von Ihnen übergebenen Enum-Wert.

Public Enum DistanceType
    Miles
    KiloMeters
End Enum

Public Structure Position
    Public Latitude As Double
    Public Longitude As Double
End Structure

Public Class Haversine

    Public Function Distance(Pos1 As Position,
                             Pos2 As Position,
                             DistType As DistanceType) As Double

        Dim R As Double = If((DistType = DistanceType.Miles), 3960, 6371)

        Dim dLat As Double = Me.toRadian(Pos2.Latitude - Pos1.Latitude)

        Dim dLon As Double = Me.toRadian(Pos2.Longitude - Pos1.Longitude)

        Dim a As Double = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) + Math.Cos(Me.toRadian(Pos1.Latitude)) * Math.Cos(Me.toRadian(Pos2.Latitude)) * Math.Sin(dLon / 2) * Math.Sin(dLon / 2)

        Dim c As Double = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)))

        Dim result As Double = R * c

        Return result

    End Function

    Private Function toRadian(val As Double) As Double

        Return (Math.PI / 180) * val

    End Function

End Class

Haben Sie bei der Berechnung von "a" versehentlich zweimal Math.Sin ( dLat ..) geschrieben?
Marco Ottina

2

Ich habe die Berechnung durch Vereinfachung der Formel verkürzt.

Hier ist es in Ruby:

include Math
earth_radius_mi = 3959
radians = lambda { |deg| deg * PI / 180 }
coord_radians = lambda { |c| { :lat => radians[c[:lat]], :lng => radians[c[:lng]] } }

# from/to = { :lat => (latitude_in_degrees), :lng => (longitude_in_degrees) }
def haversine_distance(from, to)
  from, to = coord_radians[from], coord_radians[to]
  cosines_product = cos(to[:lat]) * cos(from[:lat]) * cos(from[:lng] - to[:lng])
  sines_product = sin(to[:lat]) * sin(from[:lat])
  return earth_radius_mi * acos(cosines_product + sines_product)
end

2
function getDistanceFromLatLonInKm(lat1,lon1,lat2,lon2,units) {
  var R = 6371; // Radius of the earth in km
  var dLat = deg2rad(lat2-lat1);  // deg2rad below
  var dLon = deg2rad(lon2-lon1); 
  var a = 
    Math.sin(dLat/2) * Math.sin(dLat/2) +
    Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * 
    Math.sin(dLon/2) * Math.sin(dLon/2)
    ; 
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
  var d = R * c; 
  var miles = d / 1.609344; 

if ( units == 'km' ) {  
return d; 
 } else {
return miles;
}}

Chucks Lösung, auch kilometerweit gültig.


2

Hier ist meine Java-Implementierung zur Berechnung der Entfernung über Dezimalgrade nach einiger Suche. Ich habe den mittleren Radius der Welt (aus Wikipedia) in km verwendet. Wenn Sie Ergebnismeilen wünschen, verwenden Sie den Weltradius in Meilen.

public static double distanceLatLong2(double lat1, double lng1, double lat2, double lng2) 
{
  double earthRadius = 6371.0d; // KM: use mile here if you want mile result

  double dLat = toRadian(lat2 - lat1);
  double dLng = toRadian(lng2 - lng1);

  double a = Math.pow(Math.sin(dLat/2), 2)  + 
          Math.cos(toRadian(lat1)) * Math.cos(toRadian(lat2)) * 
          Math.pow(Math.sin(dLng/2), 2);

  double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

  return earthRadius * c; // returns result kilometers
}

public static double toRadian(double degrees) 
{
  return (degrees * Math.PI) / 180.0d;
}

2

Verwenden Sie in MySQL die folgende Funktion, um die Parameter wie folgt zu übergeben POINT(LONG,LAT)

CREATE FUNCTION `distance`(a POINT, b POINT)
 RETURNS double
    DETERMINISTIC
BEGIN

RETURN

GLength( LineString(( PointFromWKB(a)), (PointFromWKB(b)))) * 100000; -- To Make the distance in meters

END;

2
function getDistanceFromLatLonInKm(position1, position2) {
    "use strict";
    var deg2rad = function (deg) { return deg * (Math.PI / 180); },
        R = 6371,
        dLat = deg2rad(position2.lat - position1.lat),
        dLng = deg2rad(position2.lng - position1.lng),
        a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
            + Math.cos(deg2rad(position1.lat))
            * Math.cos(deg2rad(position1.lat))
            * Math.sin(dLng / 2) * Math.sin(dLng / 2),
        c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    return R * c;
}

console.log(getDistanceFromLatLonInKm(
    {lat: 48.7931459, lng: 1.9483572},
    {lat: 48.827167, lng: 2.2459745}
));

2

Hier ist ein Beispiel in Postgres SQL (in km, für Meilen-Version, ersetzen Sie 1.609344 durch 0.8684-Version)

CREATE OR REPLACE FUNCTION public.geodistance(alat float, alng float, blat  

float, blng  float)
  RETURNS float AS
$BODY$
DECLARE
    v_distance float;
BEGIN

    v_distance = asin( sqrt(
            sin(radians(blat-alat)/2)^2 
                + (
                    (sin(radians(blng-alng)/2)^2) *
                    cos(radians(alat)) *
                    cos(radians(blat))
                )
          )
        ) * cast('7926.3352' as float) * cast('1.609344' as float) ;


    RETURN v_distance;
END 
$BODY$
language plpgsql VOLATILE SECURITY DEFINER;
alter function geodistance(alat float, alng float, blat float, blng float)
owner to postgres;

2

Hier ist ein weiterer in Ruby konvertierter Code:

include Math
#Note: from/to = [lat, long]

def get_distance_in_km(from, to)
  radians = lambda { |deg| deg * Math.PI / 180 }
  radius = 6371 # Radius of the earth in kilometer
  dLat = radians[to[0]-from[0]]
  dLon = radians[to[1]-from[1]]

  cosines_product = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(radians[from[0]]) * Math.cos(radians[to[1]]) * Math.sin(dLon/2) * Math.sin(dLon/2)

  c = 2 * Math.atan2(Math.sqrt(cosines_product), Math.sqrt(1-cosines_product)) 
  return radius * c # Distance in kilometer
end

1

Hier finden Sie ein gutes Beispiel für die Berechnung der Entfernung mit PHP http://www.geodatasource.com/developers/php :

 function distance($lat1, $lon1, $lat2, $lon2, $unit) {

     $theta = $lon1 - $lon2;
     $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
     $dist = acos($dist);
     $dist = rad2deg($dist);
     $miles = $dist * 60 * 1.1515;
     $unit = strtoupper($unit);

     if ($unit == "K") {
         return ($miles * 1.609344);
     } else if ($unit == "N") {
          return ($miles * 0.8684);
     } else {
          return $miles;
     }
 }
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.