Calculer la distance entre deux points, en utilisant la latitude et la longitude?

94

Voici mon essai, c'est juste un extrait de mon 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;

J'utilise ces formules pour obtenir la latitude et la longitude:

x = Deg + (Min + Sec / 60) / 60)
m4design
la source

Réponses:

217

Le code Java donné par Dommer ci-dessus donne des résultats légèrement incorrects mais les petites erreurs s'additionnent si vous traitez, par exemple, une trace GPS. Voici une implémentation de la méthode Haversine en Java qui prend également en compte les différences de hauteur entre deux points.

/**
 * 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
la source
7
Pourquoi pas Math.toRadians () au lieu de deg2rad ()? Ce serait vraiment autonome.
Aron Lorincz
2
@Bala - Mon mauvais, c'est dans le commentaire sur le code sur mon ordinateur mais manquant ici. Distance en mètres.
David George
4
@ ÁronNemmondommegavezetéknevem J'ai mis à jour la méthode pour utiliser votre très bonne suggestion.
David George
2
Quelques commentaires ici: stackoverflow.com/questions/28510115/…
David George
Une pertinence particulière pour les noms de variables aet c? S'agit-il des côtés d'un triangle rectangle avec des étiquettes traditionnelles a, bet c?
AlainD
76

Voici une fonction Java qui calcule la distance entre deux points lat / long , affichée ci-dessous, juste au cas où elle disparaîtrait à nouveau.

    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");
dommageable
la source
1
Google Map montre 200 Kms pour 12.915700, 77.632046, 11.665154, 78.145657 où comme le code ci-dessus indique 149.82 Kms. Quelque chose ne va toujours pas.
Samy
1
@Samy la fonction ci-dessus vous donne la distance en ligne droite.
Rahul_Pawar
1
Mon royaume pour les développeurs d'étiqueter leurs variables avec les unités . double dist => double distInMiles (ou similaire) (je ne frappe pas la personne qui a posté cette réponse, je vote pour ....... mais plutôt l'implémenteur original du code)
granadaCoder
13

Remarque: cette solution ne fonctionne que pour les courtes distances.

J'ai essayé d'utiliser la formule publiée de dommer pour une application et j'ai trouvé qu'elle fonctionnait bien sur de longues distances, mais dans mes données, j'utilisais toutes les très courtes distances, et le message de dommer a très mal fonctionné. J'avais besoin de vitesse, et les calculs géographiques plus complexes fonctionnaient bien mais étaient trop lents. Donc, dans le cas où vous avez besoin de vitesse et que tous les calculs que vous faites sont courts (peut-être <100 m environ). J'ai trouvé que cette petite approximation fonctionnait très bien. il suppose que le monde est plat avec vous, alors ne l'utilisez pas sur de longues distances, il fonctionne en approximant la distance d'une seule latitude et longitude à la latitude donnée et en renvoyant la distance de Pythagore en mètres.

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
la source
13

Futurs lecteurs qui tombent sur cet article SOF.

Évidemment, la question a été posée en 2010 et c'est maintenant 2019. Mais elle revient tôt dans une recherche sur Internet. La question originale n'écarte pas l'utilisation de la bibliothèque tierce (lorsque j'ai écrit cette réponse).

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;
}

et

<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

Veuillez lire la documentation sur "SloppyMath" avant de plonger!

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

grenadeCoder
la source
5

Voici une page avec des exemples javascript pour différents calculs sphériques. Le tout premier sur la page devrait vous donner ce dont vous avez besoin.

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

Voici le code Javascript

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;

Où «d» tiendra la distance.

Chris Taylor
la source
«A» peut-il jamais être négatif?
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
la source
1

Beaucoup de bonnes réponses ont été fournies, mais j'ai trouvé quelques lacunes en termes de performances, alors laissez-moi vous proposer une version avec les performances à l'esprit. Chaque constante est précalculée et des variables x, y sont introduites pour éviter de calculer deux fois la même valeur. J'espère que ça aide

    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
la source
0

Réponse légèrement améliorée de @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);
}

La fonction de distance est la même, mais j'ai créé une petite fonction wrapper, qui prend 2 objets Location . Grâce à cela, je n'utilise la fonction de distance que si les deux emplacements ont réellement de l'altitude, car parfois ils n'en ont pas. Et cela peut conduire à des résultats étranges (si l'emplacement ne connaît pas son altitude 0 sera renvoyée). Dans ce cas, je reviens à la fonction distanceTo classique .

Makalele
la source
-1

Cet article de wikipedia fournit les formules et un exemple. Le texte est en allemand, mais les calculs parlent d'eux-mêmes.

zellus
la source