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


908

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

Pour plus de précision, je voudrais la distance en kilomètres; les points utilisent le système WGS84 et j'aimerais comprendre la précision relative des approches disponibles.


Pour une meilleure précision - voir stackoverflow.com/questions/1420045/…
Lior Kogan

3
Notez que vous ne pouvez pas appliquer une formule Haversine sur un ellipsoïde de révolution comme WGS 84. Vous ne pouvez appliquer cette méthode que sur une sphère avec un rayon.
Mike T

3
La plupart des réponses ici utilisent une trigonométrie sphérique simple, donc les résultats sont plutôt bruts par rapport aux distances ellipsoïdes WGS84 utilisées dans le système GPS. Certaines des réponses se réfèrent à la formule de Vincenty pour les ellipsoïdes, mais cet algorithme a été conçu pour être utilisé sur les calculatrices de bureau des années 1960 et il a des problèmes de stabilité et de précision; nous avons maintenant de meilleurs matériels et logiciels. Veuillez consulter GeographicLib pour une bibliothèque de haute qualité avec des implémentations dans différentes langues.
PM 2Ring

@MikeT - vrai, bien que la plupart des réponses ici semblent utiles sur de petites distances : si vous prenez lat / long de WGS 84 et appliquez Haversine comme s'il s'agissait de points sur une sphère, n'obtenez-vous pas des réponses dont les erreurs ne sont dues qu'à le facteur d'aplatissement de la Terre, alors peut-être à moins de 1% d'une formule plus précise? Avec la mise en garde que ce sont de petites distances, disons dans une seule ville.
ToolmakerSteve

1
Pour ces plateformes: Mono / .NET 4.5 / .NET Core / Windows Phone 8.x / Universal Windows Platform / Xamarin iOS / Xamarin Android voir stackoverflow.com/a/54296314/2736742
A. Morel

Réponses:


1149

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

Extrait:

Ce script [en Javascript] calcule les distances des grands cercles entre les deux points - c'est-à-dire la distance la plus courte sur la surface de la terre - en utilisant 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)
}

51
Ce calcul / cette méthode explique-t-il que la Terre est un sphéroïde (pas une sphère parfaite)? La question d'origine demandait la distance entre les points d'un globe WGS84. Je ne sais pas combien d'erreur se glisse en utilisant une sphère parfaite, mais je soupçonne que cela peut être beaucoup en fonction de l'emplacement des points sur le globe, donc la distinction mérite d'être gardée à l'esprit.
redcalx

15
La formule Haversine ne tient pas compte du fait que la Terre est un sphéroïde, vous obtiendrez donc une erreur en raison de ce fait. Il ne peut pas être garanti correct à mieux que 0,5%. Cela peut ou peut ne pas être un niveau d'erreur acceptable.
Brandon

24
Y a-t-il une raison d'utiliser à la Math.atan2(Math.sqrt(a), Math.sqrt(1-a))place de Math.asin(Math.sqrt(h)), qui serait la mise en œuvre directe de la formule que l'article Wikipedia utilise? Est-il plus efficace et / ou plus stable numériquement?
musiphil

16
@UsmanMutawakil Eh bien, les 38 miles que vous obtenez sont la distance sur la route. Cet algorithme calcule une distance en ligne droite à la surface de la Terre. Google Maps dispose d'un outil de distance (en bas à gauche, "Labs") qui fait de même, utilisez-le pour comparer.
Pascal

4
@ Forte_201092: Parce que ce n'est pas nécessaire - comme (sin(x))²égal(sin(-x))²
Jean Hominal

360

J'avais besoin de calculer beaucoup de distances entre les points pour mon projet, alors j'ai continué et j'ai essayé d'optimiser le code, j'ai trouvé ici. En moyenne, dans différents navigateurs, ma nouvelle implémentation s'exécute 2 fois plus vite que la réponse la plus votée.

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 les résultats ici .

Récemment, j'ai dû faire la même chose en python, voici donc une implémentation de python :

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...

Et pour être complet: Haversine sur wiki.


13
@AngularM et il est fort probable que google calcule la distance si vous prenez des routes et non une ligne droite.
Salvador Dali

3
Google calcule la distance de conduite, ce calcul "à vol d'oiseau"
Hobbyist

4
@Ouadie et cela améliorera-t-il la vitesse? Probablement pas, mais je vais me retrouver avec beaucoup de "vos trucs ne fonctionnent pas" pour les gens qui copytapent dans les anciens navigateurs
Salvador Dali

4
bien ouais mais qu'est-ce que cela // 2 * R; R = 6371 kmsignifie? et la méthode actuelle fournit une réponse en km ou en miles? a besoin d'une meilleure documentation. Merci
Khalil Khalaf

20
@KhalilKhalaf plaisantez-vous ou essayez-vous de troller ici? km signifie kilomètres. Que pensez-vous que R représente (surtout si nous parlons d'un shpere)? Devinez dans quelles unités la réponse sera si vous voyez déjà le km. Quel type de documentation recherchez-vous ici: il y a littéralement 4 lignes là-bas.
Salvador Dali

69

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

}

14
Vous utilisez le rayon équatorial, mais vous devez utiliser le rayon moyen, qui est de 6371 km
Philippe Leybaert

7
Cela ne devrait-il pas être double dlon = Radians(lon2 - lon1);etdouble dlat = Radians(lat2 - lat1);
Chris Marisic

Je suis d'accord avec Chris Marisic. J'ai utilisé le code d'origine et les calculs étaient erronés. J'ai ajouté l'appel pour convertir les deltas en radians et cela fonctionne correctement maintenant. J'ai soumis une modification et j'attends qu'elle soit évaluée par des pairs.
Bryan Bedard

J'ai soumis une autre modification, car lat1 et lat2 doivent également être convertis en radians. J'ai également révisé la formule de l'affectation à a pour qu'elle corresponde à la formule et au code trouvés ici: movable-type.co.uk/scripts/latlong.html
Bryan Bedard

la RADIUSvaleur doit-elle être 6371 comme dans les autres réponses?
Chris Hayes

66

Voici une implémentation java de la formule 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 ici la réponse au km le plus proche.


2
Si nous voulions calculer la distance entre deux points en mètres, quelle serait la manière la plus précise? Pour utiliser 6371000comme rayon de la terre? (le rayon moyen de la Terre est de 6371000 mètres) ou convertir des kilomètres en mètres à partir de votre fonction?
Micro

si vous voulez des miles, multipliez le résultat par0.621371
lasec0203

42

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écimales. 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 les valeurs en radians - maintenant c'est à peu près les mêmes 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 fournit quelques méthodes pour ce faire afin que la même fonctionnalité soit obtenue avec:

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

    MKMapPoint  start, finish;


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

    return MKMetersBetweenMapPoints(start, finish) / 1000;
}


Je pense que la parenthèse autour pow(sin(dlat / 2), 2) + cos(convertToRadians(place1.latitude))est incorrecte. Supprimez-les et le résultat correspond à ce que j'obtiens lorsque j'utilise d'autres implémentations sur cette page, ou implémentez la formule Haversine de Wikipedia à partir de zéro.
zanedp

En utilisant les coordonnées (40.7127837, -74.0059413) pour NYC et (34.052234, -118.243685) pour LA, avec ()environ cette somme, j'obtiens 3869.75. Sans eux, j'obtiens 3935,75, ce qui correspond à peu près à ce que révèle une recherche sur le Web.
zanedp

40

Il s'agit d'une simple fonction PHP 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 plus simples (comme celui-ci) le traitent comme une sphère.

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

Pour plus d'informations: distance géographique wikipedia


4
Cela fonctionne parfaitement! Je viens d'ajouter $ distance_miles = $ km * 0.621371; et c'est tout ce dont j'avais besoin pour une distance approximative en miles! Merci Tony.

31

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 du tableau sont coord_lat et coord_long):

Énumérez tous ayant une DISTANCE <50, en kilomètres (considéré comme le 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é dans MySQL 5.0.95 et 5.5.16 (Linux).


Je pense qu'une bonne approche pourrait être de filtrer les résultats à l'aide d'une approximation, de sorte que la formule lourde n'est appliquée que dans certains cas. Particulièrement utile si vous avez d'autres conditions. J'utilise ceci pour le aprox initial: stackoverflow.com/questions/1253499/…
Pato

28

Dans les autres réponses, une implémentation est manquant.

Le calcul de la distance entre deux points est assez simple avec la distmfonction du geospherepackage:

distm(p1, p2, fun = distHaversine)

où:

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

Comme la terre n'est pas parfaitement sphérique, la formule de Vincenty pour les ellipsoïdes est probablement la meilleure façon de calculer les distances. Ainsi dans le geospherepackage que vous utilisez alors:

distm(p1, p2, fun = distVincentyEllipsoid)

Bien sûr, vous n'avez pas nécessairement à utiliser le geospherepackage, vous pouvez également calculer la distance en base Ravec une fonction:

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

Pour être sûr que je suis clair sur ce que vous avez dit: Le code que vous donnez à la fin du post: Est-ce une implémentation de la formule Vincenty? Pour autant que vous le sachiez, cela devrait donner la même réponse que d'appeler Vincenty dans la géosphère? [Je n'ai pas de géosphère ou autre bibliothèque; à la recherche d'un code à inclure dans une application multiplateforme. Je voudrais bien sûr vérifier certains cas de test par rapport à une bonne calculatrice connue.]
ToolmakerSteve

1
@ToolmakerSteve la fonction à la fin de ma réponse est une implémentation de la méthode Haversine
Jaap

Salut @Jaap pourrais-je demander quelle est l'unité de mesure pour la formule? Est-ce en mètres?
Jackson

11

Le haversine est certainement une bonne formule pour probablement la plupart des cas, d'autres réponses l'incluent déjà, donc je ne vais pas prendre de la place. Mais il est important de noter que quelle que soit la formule utilisée (oui pas une seule). En raison de l'énorme plage de précision possible ainsi que du temps de calcul requis. Le choix de la formule nécessite un peu plus de réflexion qu'une simple réponse simple.

Cette publication d'une personne de la NASA est la meilleure que j'ai trouvée pour discuter des options

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

Par exemple, si vous triez simplement des lignes par distance dans un rayon de 100 miles. La formule de la terre plate sera beaucoup plus rapide que la 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;

Remarquez qu'il n'y a qu'un cosinus et une racine carrée. Vs 9 d'entre eux sur la formule Haversine.


C'est une belle possibilité. Sachez simplement que la distance maximale recommandée dans la discussion est de 12 miles, et non de 100 , et que même dans ce cas, les erreurs peuvent grimper jusqu'à 30 mètres (100 ft), selon la position du globe.
Eric Wu du

7

Vous pouvez utiliser la génération dans CLLocationDistance pour calculer ceci:

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

Dans votre cas, si vous voulez que les kilomètres soient divisés par 1000.


7

Je n'aime pas ajouter une autre réponse, mais l'API Google maps v.3 a une géométrie sphérique (et plus). Après avoir converti votre WGS84 en degrés décimaux, vous pouvez le faire:

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

Aucun mot sur la précision des calculs de Google ou même sur le modèle utilisé (même s'il dit "sphérique" plutôt que "géoïde". Soit dit en passant, la distance en "ligne droite" sera évidemment différente de la distance si l'on voyage sur la surface de la terre qui est ce que tout le monde semble présumer.


la distance est en mètres. alternativement, on peut utiliser computeLength ()
electrobabe

7

Implantation de python Origin est le centre des États-Unis contigus.

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

Pour obtenir la réponse en kilomètres, définissez simplement miles = false.


1
Vous importez un package non standard qui fait tout le travail. Je ne sais pas si c'est si utile.
Teepeemm

Le package est dans le PyPI, Python Package Index, en tant que package python 3 avec numpy et scikit-learn. Je ne sais pas pourquoi on est apposé sur les paquets. Ils ont tendance à être très utiles. En open source, on pourrait également examiner les méthodes contenues. Je pense que beaucoup trouveraient ce paquet utile, donc je laisserai le message malgré le downvote. À votre santé. :)
invoketheshell

7

Il pourrait y avoir une solution plus simple et plus correcte: le périmètre de la terre est de 40 000 km à l'équateur, environ 37 000 sur le cycle de Greenwich (ou n'importe quelle longitude). Donc:

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

Je suis d'accord pour qu'il soit affiné car, j'ai moi-même dit que c'est un ellipsoïde, donc le rayon à multiplier par le cosinus varie. Mais c'est un peu plus précis. Par rapport à Google Maps, cela a permis de réduire considérablement l'erreur.


Cette fonction est-elle la distance de retour en km?
Wikki

C'est juste parce que l'équateur et les cycles de longitude sont en Km. Pour les miles, il suffit de diviser 40000 et 37000 par 1,6. Sentant geek, vous pouvez le convertir en Ris, multiplié par environ 7 ou en parasang, divisant par 2,2 ;-)
Meymann

Cela semble être la meilleure réponse proposée ici. Je souhaite l'utiliser mais je me demande simplement s'il existe un moyen de vérifier l'exactitude de cet algorithme. J'ai testé f (50,5,58,3). Il donne 832 km, tandis que movable-type.co.uk/scripts/latlong.html utilisant la formule «haversine» donne 899 km. Y a-t-il une si grande différence?
Chong Lip Phang

De plus, je pense que la valeur retournée par le code ci-dessus est en m, et non en km.
Chong Lip Phang

@ChongLipPhang - ATTENTION: le théorème de Pythagore n'est qu'une approximation raisonnable pour les petites zones , car ce théorème suppose que la terre est plate. Dans un cas extrême, commencez sur l'équateur et déplacez-vous de 90 degrés vers l'est et de 90 degrés vers le nord. Le résultat final est bien sûr le pôle nord, et équivaut à se déplacer de 0 degré vers l'est et de 90 degrés vers le nord; ainsi faire sqrt (sqr (dx) + sqr (dy)) sera sauvagement désactivé dans le premier cas. ~ sqrt (10km sqr + 10km sqr) ~ = 14,4 km vs distance correcte ~ 10km.
ToolmakerSteve

7

Toutes les réponses ci-dessus supposent que la terre est une sphère. Cependant, une approximation plus précise serait celle d'un sphéroïde oblat.

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

Voici l'implémentation SQL pour calculer la distance en 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;

Pour plus de détails sur l'implémentation en programmant le langage, vous pouvez simplement parcourir le script php donné ici


5

Voici une implémentation dactylographiée de la formule Haversine

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

Comme indiqué, un calcul précis doit tenir compte du fait que la terre n'est pas une sphère parfaite. Voici quelques comparaisons des différents algorithmes proposés ici:

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

Sur de petites distances, l'algorithme de Keerthana semble coïncider avec celui de Google Maps. Google Maps ne semble suivre aucun algorithme simple, ce qui suggère que c'est peut-être la méthode la plus précise ici.

Quoi qu'il en soit, voici une implémentation Javascript de l'algorithme de Keerthana:

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

Ce script [en PHP] calcule les distances entre les deux points.

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

Implémentation Java selon la formule Haversine

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

Pour calculer la distance entre deux points sur une sphère, vous devez faire le calcul du Grand Cercle .

Il existe un certain nombre de bibliothèques C / C ++ pour aider à la projection de cartes dans MapTools si vous devez reprojeter vos distances à une surface plane. Pour ce faire, vous aurez besoin de la chaîne de projection des différents systèmes de coordonnées.

Vous pouvez également trouver MapWindow un outil utile pour visualiser les points. En tant que source ouverte, c'est un guide utile sur la façon d'utiliser la bibliothèque proj.dll, qui semble être la bibliothèque de projection open source principale.


3

Voici l'implémentation de réponse acceptée portée sur Java au cas où quelqu'un en aurait besoin.

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

Voici l'implémentation VB.NET, cette implémentation vous donnera le résultat en KM ou en Miles basé sur une valeur Enum que vous passez.

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

Lors du calcul de "a", avez-vous écrit Math.Sin ( dLat ..) deux fois par erreur?
Marco Ottina

2

J'ai condensé le calcul vers le bas en simplifiant la formule.

Le voici en 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;
}}

La solution de Chuck, valable également pour des miles.


2

Voici mon implémentation Java pour le calcul de la distance via les degrés décimaux après quelques recherches. J'ai utilisé le rayon moyen du monde (de wikipedia) en km. Si vous voulez des résultats en miles, utilisez le rayon du monde en miles.

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

Dans Mysql, utilisez la fonction suivante pour passer les paramètres en utilisant 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

voici un exemple en sql postgres (en km, pour la version miles, remplacer 1.609344 par la version 0.8684)

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

Voici un autre code converti en Ruby :

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

il y a un bon exemple ici pour calculer la distance avec 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;
     }
 }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.