Question Calculer la distance entre deux points latitude-longitude? (Formule de Haversine)


Comment puis-je calculer la distance entre deux points spécifiés par la latitude et la longitude?

Pour plus de précisions, j'aimerais connaître la distance en kilomètres; les points utilisent le système WGS84 et j'aimerais comprendre les précisions relatives des approches disponibles.


704
2017-08-26 12:50


origine


Réponses:


Ce lien pourrait vous être utile, car elle détaille l'utilisation de La formule de Haversine pour calculer la distance.

Extrait:

Ce script [en Javascript] calcule les distances de grand cercle entre les deux points -   c'est-à-dire, la distance la plus courte sur la surface de la terre - en utilisant le   La formule 'Haversine'.

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

885
2017-08-26 12:55



J'avais besoin de calculer beaucoup de distances entre les points pour mon projet, alors je suis allé de l'avant et j'ai essayé d'optimiser le code, j'ai trouvé ici. En moyenne dans différents navigateurs ma nouvelle mise en œuvre fonctionne 2 fois plus vite que la réponse la plus mise à jour.

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
}

Vous pouvez jouer avec mon jsPerf et voir le résultats ici.

Récemment, j'ai dû faire la même chose en python, alors voici un Implémentation de Python:

from math import cos, asin, sqrt
def distance(lat1, lon1, lat2, lon2):
    p = 0.017453292519943295     #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...

Et pour être complet: Haversine sur wiki.


256
2018-02-07 08:52



Voici une implémentation C #:

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

57
2017-10-19 01:30



Voici une implémentation Java de la formule de Haversine.

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

Notez que nous arrondissons la réponse au km le plus proche.


49
2017-09-26 11:00



Merci beaucoup pour tout ça. J'ai utilisé le code suivant dans mon application iPhone Objective-C:

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

La latitude et la longitude sont en décimal. Je n'ai pas utilisé min () pour l'appel asin () car les distances que j'utilise sont si petites qu'elles n'en ont pas besoin.

Il a donné des réponses incorrectes jusqu'à ce que je passe dans les valeurs dans Radians - maintenant c'est à peu près la même chose que les valeurs obtenues à partir de l'application Map d'Apple :-)

Mise à jour supplémentaire:

Si vous utilisez iOS4 ou une version ultérieure, Apple propose des méthodes permettant de réaliser la même fonctionnalité avec:

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

    MKMapPoint  start, finish;


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

    return MKMetersBetweenMapPoints(start, finish) / 1000;
}

41
2017-12-07 13:56



C'est une fonction PHP simple qui donnera une approximation très raisonnable (sous +/- 1% de marge d'erreur).

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

Comme dit précédemment; la terre n'est pas une sphère. C'est comme un vieux vieux baseball avec lequel Mark McGwire a décidé de s'entraîner - il est plein de bosses et de bosses. Les calculs les plus simples (comme celui-ci) le traitent comme une sphère.

Différentes méthodes peuvent être plus ou moins précises en fonction de l'endroit où vous êtes sur cet ovoïde irrégulier ET de la distance entre vos points (plus ils sont proches, plus la marge d'erreur absolue est petite). Plus votre attente est précise, plus les maths sont complexes.

Pour plus d'informations: wikipedia distance géographique


35
2018-06-24 14:11



Je poste ici mon exemple de travail.

Liste tous les points du tableau ayant une distance entre un point désigné (nous utilisons un point aléatoire - lat: 45.20327, long: 23.7806) inférieur à 50 KM, avec latitude et longitude, dans MySQL (les champs de la table sont coord_lat et coord_long):

Liste ayant tous une DISTANCE <50, en Kilomètres (considéré comme rayon de la Terre 6371 KM):

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

L'exemple ci-dessus a été testé en MySQL 5.0.95 et 5.5.16 (Linux).


25
2018-03-12 23:37