Berechnung der Entfernung zwischen zwei Punkten anhand des Längen- und Breitengrads?

92

Hier ist mein Versuch, es ist nur ein Ausschnitt aus meinem Code:

final double RADIUS = 6371.01;
double temp = Math.cos(Math.toRadians(latA))
            * Math.cos(Math.toRadians(latB))
            * Math.cos(Math.toRadians((latB) - (latA)))
            + Math.sin(Math.toRadians(latA))
            * Math.sin(Math.toRadians(latB));
    return temp * RADIUS * Math.PI / 180;

Ich benutze diese Formeln, um den Breiten- und Längengrad zu ermitteln:

x = Deg + (Min + Sec / 60) / 60)
m4design
quelle

Antworten:

215

Der von Dommer oben angegebene Java-Code liefert leicht falsche Ergebnisse, aber die kleinen Fehler summieren sich, wenn Sie beispielsweise einen GPS-Track verarbeiten. Hier ist eine Implementierung der Haversine-Methode in Java, die auch Höhenunterschiede zwischen zwei Punkten berücksichtigt.

/**
 * Calculate distance between two points in latitude and longitude taking
 * into account height difference. If you are not interested in height
 * difference pass 0.0. Uses Haversine method as its base.
 * 
 * lat1, lon1 Start point lat2, lon2 End point el1 Start altitude in meters
 * el2 End altitude in meters
 * @returns Distance in Meters
 */
public static double distance(double lat1, double lat2, double lon1,
        double lon2, double el1, double el2) {

    final int R = 6371; // Radius of the earth

    double latDistance = Math.toRadians(lat2 - lat1);
    double lonDistance = Math.toRadians(lon2 - lon1);
    double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
            + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
            * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    double distance = R * c * 1000; // convert to meters

    double height = el1 - el2;

    distance = Math.pow(distance, 2) + Math.pow(height, 2);

    return Math.sqrt(distance);
}
David George
quelle
7
Warum nicht Math.toRadians () statt deg2rad ()? Es wäre wirklich in sich geschlossen.
Aron Lorincz
2
@Bala - Mein schlechtes, es ist im Kommentar zum Code auf meinem Computer, aber hier fehlt. Entfernung in Metern.
David George
4
@ ÁronNemmondommegavezetéknevem Ich habe die Methode aktualisiert, um Ihren sehr guten Vorschlag zu verwenden.
David George
2
Einige Kommentare hier: stackoverflow.com/questions/28510115/…
David George
Eine besondere Relevanz für Variablennamen aund c? Sind das die Seiten eines rechtwinkligen Dreiecks mit traditionellen Etiketten a, bund c?
AlainD
75

Hier ist eine Java-Funktion, die den Abstand zwischen zwei Lat / Long-Punkten berechnet (siehe unten), für den Fall, dass er wieder verschwindet.

    private double distance(double lat1, double lon1, double lat2, double lon2, char unit) {
      double theta = lon1 - lon2;
      double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
      dist = Math.acos(dist);
      dist = rad2deg(dist);
      dist = dist * 60 * 1.1515;
      if (unit == 'K') {
        dist = dist * 1.609344;
      } else if (unit == 'N') {
        dist = dist * 0.8684;
        }
      return (dist);
    }
    
    /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    /*::  This function converts decimal degrees to radians             :*/
    /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    private double deg2rad(double deg) {
      return (deg * Math.PI / 180.0);
    }
    
    /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    /*::  This function converts radians to decimal degrees             :*/
    /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    private double rad2deg(double rad) {
      return (rad * 180.0 / Math.PI);
    }
    
    System.out.println(distance(32.9697, -96.80322, 29.46786, -98.53506, 'M') + " Miles\n");
    System.out.println(distance(32.9697, -96.80322, 29.46786, -98.53506, 'K') + " Kilometers\n");
    System.out.println(distance(32.9697, -96.80322, 29.46786, -98.53506, 'N') + " Nautical Miles\n");
Dommer
quelle
1
Google Map zeigt 200 km für 12.915700, 77.632046, 11.665154, 78.145657, wobei der obige Code 149,82 km anzeigt. Etwas stimmt immer noch nicht.
Samy
1
@Samy die obige Funktion gibt dir geraden Abstand.
Rahul_Pawar
1
Mein Königreich für Entwickler, um ihre Variablen mit den Einheiten zu kennzeichnen . double dist => double distInMiles (oder ähnliches) (Ich klopfe nicht an die Person, die diese Antwort gepostet hat, ich stimme zu ....... sondern an den ursprünglichen Implementierer des Codes)
granadaCoder
12

Hinweis: Diese Lösung funktioniert nur für kurze Entfernungen.

Ich habe versucht, die von dommer veröffentlichte Formel für eine Anwendung zu verwenden, und festgestellt, dass sie für große Entfernungen gut funktioniert, aber in meinen Daten habe ich alle sehr kurzen Entfernungen verwendet, und die von dommer veröffentlichte Formel hat sich sehr schlecht bewährt. Ich brauchte Geschwindigkeit und die komplexeren Geo-Berechnungen funktionierten gut, waren aber zu langsam. Für den Fall, dass Sie Geschwindigkeit benötigen und alle Berechnungen, die Sie durchführen, kurz sind (vielleicht <100 m oder so). Ich fand diese kleine Annäherung großartig. Es wird davon ausgegangen, dass die Welt flach ist. Verwenden Sie sie also nicht für große Entfernungen. Sie approximiert die Entfernung eines einzelnen Breiten- und Längengrads bei der angegebenen Breite und gibt die pythagoreische Entfernung in Metern zurück.

public class FlatEarthDist {
    //returns distance in meters
    public static double distance(double lat1, double lng1, 
                                      double lat2, double lng2){
     double a = (lat1-lat2)*FlatEarthDist.distPerLat(lat1);
     double b = (lng1-lng2)*FlatEarthDist.distPerLng(lat1);
     return Math.sqrt(a*a+b*b);
    }

    private static double distPerLng(double lat){
      return 0.0003121092*Math.pow(lat, 4)
             +0.0101182384*Math.pow(lat, 3)
                 -17.2385140059*lat*lat
             +5.5485277537*lat+111301.967182595;
    }

    private static double distPerLat(double lat){
            return -0.000000487305676*Math.pow(lat, 4)
                -0.0033668574*Math.pow(lat, 3)
                +0.4601181791*lat*lat
                -1.4558127346*lat+110579.25662316;
    }
}
zahmde
quelle
11

Zukünftige Leser, die über diesen SOF-Artikel stolpern.

Offensichtlich wurde die Frage im Jahr 2010 und jetzt im Jahr 2019 gestellt. Aber sie taucht früh in einer Internetsuche auf. Die ursprüngliche Frage schließt die Verwendung von Drittanbieter-Bibliotheken nicht aus (als ich diese Antwort schrieb).

public double calculateDistanceInMeters(double lat1, double long1, double lat2,
                                     double long2) {


    double dist = org.apache.lucene.util.SloppyMath.haversinMeters(lat1, long1, lat2, long2);
    return dist;
}

und

<dependency>
  <groupId>org.apache.lucene</groupId>
  <artifactId>lucene-spatial</artifactId>
  <version>8.2.0</version>
</dependency>

https://mvnrepository.com/artifact/org.apache.lucene/lucene-spatial/8.2.0

Bitte lesen Sie die Dokumentation zu "SloppyMath", bevor Sie eintauchen!

https://lucene.apache.org/core/8_2_0/core/org/apache/lucene/util/SloppyMath.html

granadaCoder
quelle
4

Hier ist eine Seite mit Javascript-Beispielen für verschiedene sphärische Berechnungen. Der allererste auf der Seite sollte Ihnen das geben, was Sie brauchen.

http://www.movable-type.co.uk/scripts/latlong.html

Hier ist der Javascript-Code

var R = 6371; // km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad(); 
var a = Math.sin(dLat/2) * Math.sin(dLat/2) + 
        Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
        Math.sin(dLon/2) * Math.sin(dLon/2); 
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
var d = R * c;

Wo 'd' den Abstand halten wird.

Chris Taylor
quelle
Kann "a" jemals negativ sein?
Xi Wei
1
package distanceAlgorithm;

public class CalDistance {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
    CalDistance obj=new CalDistance();
    /*obj.distance(38.898556, -77.037852, 38.897147, -77.043934);*/
        System.out.println(obj.distance(38.898556, -77.037852, 38.897147, -77.043934, "M") + " Miles\n");
        System.out.println(obj.distance(38.898556, -77.037852, 38.897147, -77.043934, "K") + " Kilometers\n");
        System.out.println(obj.distance(32.9697, -96.80322, 29.46786, -98.53506, "N") + " Nautical Miles\n");       
    }   
    public double distance(double lat1, double lon1, double lat2, double lon2, String sr) {


          double theta = lon1 - lon2;
          double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
          dist = Math.acos(dist);
          dist = rad2deg(dist);
          dist = dist * 60 * 1.1515;
          if (sr.equals("K")) {
            dist = dist * 1.609344;
          } else if (sr.equals("N")) {
            dist = dist * 0.8684;
            }
          return (dist);
        }
    public double deg2rad(double deg) {
          return (deg * Math.PI / 180.0);
        }
    public double rad2deg(double rad) {
          return (rad * 180.0 / Math.PI);
        }


    }
MAnoj Sarnaik
quelle
1

Es wurden viele gute Antworten gegeben, aber ich habe einige Leistungsmängel festgestellt. Lassen Sie mich daher eine Version anbieten, die die Leistung berücksichtigt. Jede Konstante wird vorberechnet und x, y-Variablen werden eingeführt, um zu vermeiden, dass derselbe Wert zweimal berechnet wird. Ich hoffe es hilft

    private static final double r2d = 180.0D / 3.141592653589793D;
    private static final double d2r = 3.141592653589793D / 180.0D;
    private static final double d2km = 111189.57696D * r2d;
    public static double meters(double lt1, double ln1, double lt2, double ln2) {
        final double x = lt1 * d2r;
        final double y = lt2 * d2r;
        return Math.acos( Math.sin(x) * Math.sin(y) + Math.cos(x) * Math.cos(y) * Math.cos(d2r * (ln1 - ln2))) * d2km;
    }
Stan Sokolov
quelle
0

Leicht verbesserte Antwort von @David George:

public static double distance(double lat1, double lat2, double lon1,
                              double lon2, double el1, double el2) {

    final int R = 6371; // Radius of the earth

    double latDistance = Math.toRadians(lat2 - lat1);
    double lonDistance = Math.toRadians(lon2 - lon1);
    double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
            + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
            * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    double distance = R * c * 1000; // convert to meters

    double height = el1 - el2;

    distance = Math.pow(distance, 2) + Math.pow(height, 2);

    return Math.sqrt(distance);
}

public static double distanceBetweenLocations(Location l1, Location l2) {
    if(l1.hasAltitude() && l2.hasAltitude()) {
        return distance(l1.getLatitude(), l2.getLatitude(), l1.getLongitude(), l2.getLongitude(), l1.getAltitude(), l2.getAltitude());
    }
    return l1.distanceTo(l2);
}

Die Entfernungsfunktion ist dieselbe, aber ich habe eine kleine Wrapper-Funktion erstellt, die 2 Standortobjekte akzeptiert. Aus diesem Grund verwende ich die Entfernungsfunktion nur, wenn beide Standorte tatsächlich eine Höhe haben, da dies manchmal nicht der Fall ist. Und es kann zu seltsamen Ergebnissen führen (wenn der Standort nicht weiß, dass seine Höhe 0 zurückgegeben wird). In diesem Fall greife ich auf die klassische Funktion distanceTo zurück .

Makalele
quelle
-1

Dieser Wikipedia- Artikel enthält die Formeln und ein Beispiel. Der Text ist in deutscher Sprache, aber die Berechnungen sprechen für sich.

Zellus
quelle