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

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

pour clarifier, 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.

732
demandé sur Zero 2008-08-26 16:50:45

30 réponses

Ce lien pourrait être utile pour vous, car il décrit en détail l'utilisation de la Haversine formule pour calculer la distance.

extrait:

ce script [en Javascript] calcule les distances entre les deux points – c'est – à-dire, la distance la plus courte au-dessus de la surface de la terre-en utilisant le 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)
}
913
répondu Chuck 2014-07-31 01:25:14

j'ai besoin de calculer beaucoup de distances entre les points pour mon projet, donc je suis allé de l'avant et a essayé d'optimiser le code, j'ai trouvé ici. En moyenne, sur différents navigateurs, ma nouvelle implémentation tourne 2 fois plus vite que la réponse la plus en vogue.

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 eu besoin de faire la même chose en python, donc voici un python de mise en œuvre :

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 par souci d'exhaustivité: Haversine sur wiki.

266
répondu Salvador Dali 2017-04-16 19:45:25

voici un C# Implementation:

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;
    }
58
répondu jaircazarin-old-account 2016-11-01 09:11:43

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 kilomètre le plus proche.

50
répondu whostolebenfrog 2016-11-29 09:19:04

Merci beaucoup pour tout cela. J'ai utilisé le code suivant dans mon application objectif-c iPhone:

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

Latitude et 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 ne l'exigent pas.

il a donné des réponses incorrectes jusqu'à ce que je passe dans les valeurs dans Radians-maintenant, il est à peu près la même que les valeurs obtenues à partir de la carte App D'Apple: -)

Mise à jour supplémentaire:

si vous utilisez iOS4 ou plus tard, alors Apple fournir quelques méthodes pour le faire de sorte que la même fonctionnalité serait atteinte avec:

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

    MKMapPoint  start, finish;


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

    return MKMetersBetweenMapPoints(start, finish) / 1000;
}
41
répondu Stephen Watson 2014-07-31 01:26:41

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

<?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 avant; la terre n'est pas une sphère. C'est comme une vieille balle de baseball avec laquelle Mark McGwire a décidé de s'entraîner - elle est pleine 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 selon l'endroit où vous êtes sur cette irrégulière ovoid et à quel point vos points sont éloignés les uns des autres (plus ils sont rapprochés, plus la marge d'erreur absolue est petite). Plus vos attentes sont précises, plus les calculs sont complexes.

pour plus d'informations: wikipedia geographic distance

35
répondu tony gil 2017-06-22 20:33:20

, je poste ici mon exemple.

énumérer 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) moins de 50 KM, avec latitude et longitude, en MySQL (les champs de la table sont coordin_lat et coordin_long):

Liste tous avoir la DISTANCE<50, Kilomètres (considéré comme du 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).

26
répondu conualfy 2014-07-31 01:31:00

dans les autres réponses, il manque une implémentation dans .

calculer la distance entre deux points est assez simple avec la fonction distm du paquet geosphere :

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 ellipsoïdes est probablement la meilleure façon de calculer distance. Ainsi, dans le paquet geosphere vous utilisez alors:

distm(p1, p2, fun = distVincentyEllipsoid)

bien sûr, vous ne devez pas nécessairement utiliser geosphere paquet, vous pouvez également calculer la distance en base R avec 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)
}
20
répondu Jaap 2018-06-15 13:35:00

vous pouvez utiliser le build in 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 des kilomètres, divisez-les PAR 1000.

7
répondu André Cytryn 2013-06-26 08:43:46

La haversine est certainement une bonne formule pour probablement la plupart des cas, d'autres réponses incluent déjà donc je ne vais pas prendre l'espace. 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 le temps de calcul requis. Le choix de la formule nécessite un peu plus de réflexion qu'une simple réponse sans hésitation.

Cette annonce d'une personne à la nasa, est le meilleur que j'ai trouvé à discussion des options

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

par exemple, si vous ne faites que trier les lignes par distance dans un rayon de 100 miles. La formule de la Terre Plate sera beaucoup plus rapide que l'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 de Haversine.

7
répondu Arturo Hernandez 2013-11-04 16:20:08

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

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

pas un mot sur la précision des calculs de Google ou même quel modèle est utilisé (bien qu'il ne dise "sphérique" plutôt que "géoïde". D'ailleurs, la distance" en ligne droite " sera évidemment différente de la distance si l'on voyage à la surface de la Terre qui est ce que tout le monde semble présumer.

6
répondu Steven Christenson 2014-07-20 00:10:07

cela dépend plutôt comment vous voulez être précis et ce que datum le lat et long sont définis sur. Très, très approximativement vous faites un peu de trigonométrie sphérique, mais corriger pour le fait que la terre n'est pas une Sphère rend les formules plus compliquées.

5
répondu Pete Kirkham 2008-08-26 12:59:13

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). Ainsi:

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 qu'il devrait être 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. Comparé à Google Maps et il a réduit l'erreur de manière significative.

5
répondu Meymann 2016-02-10 07:26:41

Voici une tapuscrit la mise en œuvre de la Haversine formule

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;
}
4
répondu Sel 2015-12-26 08:13:11

toutes les réponses ci-dessus supposent que la Terre est une sphère. Cependant, plus précise rapprochement serait celle d'un sphéroïde oblate.

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
4
répondu Keerthana Gopalakrishnan 2016-06-16 22:25:37

pour calculer la distance entre deux points sur une sphère vous devez faire le grand calcul de cercle .

il y a un certain nombre de bibliothèques C/C++ pour aider avec la projection de carte à MapTools si vous avez besoin de reprojecter 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 aussi trouver MapWindow a outil utile pour visualiser les points. Aussi ouvert ses indications utiles sur la façon d'utiliser le proj.dll bibliothèque, qui semble être la bibliothèque principale de projection open source.

3
répondu 2008-10-19 01:30:09

Python implimentation L'origine 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 mettez simplement miles=false.

3
répondu invoketheshell 2015-07-14 05:52:12

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;
        }
    }
3
répondu Er.Subhendu Kumar Pati 2017-02-21 07:04:55

j'ai condensé le calcul en simplifiant la formule.

ici C'est en rubis:

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
répondu Kache 2013-06-13 02:28:45

Voici l'implémentation de réponse acceptée portée en 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
répondu Eddnav 2015-10-12 20:59:53

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;
     }
 }
1
répondu ayalcinkaya 2013-01-15 01:48:23

Voici la mise en œuvre VB.NET, cette implémentation vous donnera le résultat en KM ou 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
1
répondu Taiseer Joudeh 2013-04-02 08:35:43

Voici mon implémentation java pour la distance de calcul via des degrés décimaux après une recherche. J'ai utilisé le rayon moyen du monde (de wikipedia) en km. Si vous voulez des miles de résultat, 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;
}
1
répondu user2881716 2014-02-12 20:52:42

dans Mysql utiliser la fonction suivante passer les paramètres comme 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;
1
répondu shanavascet 2014-05-28 08:59:44
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}
));
1
répondu Raphael C 2015-04-29 14:22:25

voici un exemple dans postgres sql (en km, Pour la version miles, remplacer 1.609344 par 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;
1
répondu fisc 2016-12-21 07:34:02

comme indiqué, un calcul précis devrait tenir compte du fait que la terre n'est pas une sphère parfaite. Voici quelques comparaisons des divers algorithmes offerts 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 pas suivre un algorithme simple, suggérant qu'il peut être la méthode la plus précise ici.

en tout cas, voici un Javascript mise en œuvre 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));
}
1
répondu Chong Lip Phang 2018-04-19 09:14:27

Voici une fonction javascript simple qui peut être utile à partir de ce lien .. d'une manière ou d'une autre lié, mais nous utilisons Google earth JavaScript plugin au lieu de cartes

function getApproximateDistanceUnits(point1, point2) {

    var xs = 0;
    var ys = 0;

    xs = point2.getX() - point1.getX();
    xs = xs * xs;

    ys = point2.getY() - point1.getY();
    ys = ys * ys;

    return Math.sqrt(xs + ys);
}

les unités ne sont pas en distance mais en termes de ratio par rapport à vos coordonnées. Il ya d'autres calculs liés, Vous pouvez remplacer la fonction getApproximateDistanceUnits lien ici

alors j'utilise cette fonction pour voir si une longitude de latitude est dans le rayon

function isMapPlacemarkInRadius(point1, point2, radi) {
    if (point1 && point2) {
        return getApproximateDistanceUnits(point1, point2) <= radi;
    } else {
        return 0;
    }
}

point peut être défini comme

 $$.getPoint = function(lati, longi) {
        var location = {
            x: 0,
            y: 0,
            getX: function() { return location.x; },
            getY: function() { return location.y; }
        };
        location.x = lati;
        location.y = longi;

        return location;
    };

alors vous pouvez faire votre chose pour voir si un point est dans une région avec un rayon dire:

 //put it on the map if within the range of a specified radi assuming 100,000,000 units
        var iconpoint = Map.getPoint(pp.latitude, pp.longitude);
        var centerpoint = Map.getPoint(Settings.CenterLatitude, Settings.CenterLongitude);

        //approx ~200 units to show only half of the globe from the default center radius
        if (isMapPlacemarkInRadius(centerpoint, iconpoint, 120)) {
            addPlacemark(pp.latitude, pp.longitude, pp.name);
        }
        else {
            otherSidePlacemarks.push({
                latitude: pp.latitude,
                longitude: pp.longitude,
                name: pp.name
            });

        }
0
répondu bherto39 2012-10-17 09:12:48
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;
}}

solution de Chuck, valable aussi pour miles.

0
répondu MPaulo 2013-11-08 06:34:35
//JAVA
    public Double getDistanceBetweenTwoPoints(Double latitude1, Double longitude1, Double latitude2, Double longitude2) {
    final int RADIUS_EARTH = 6371;

    double dLat = getRad(latitude2 - latitude1);
    double dLong = getRad(longitude2 - longitude1);

    double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(getRad(latitude1)) * Math.cos(getRad(latitude2)) * Math.sin(dLong / 2) * Math.sin(dLong / 2);
    double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    return (RADIUS_EARTH * c) * 1000;
    }

    private Double getRad(Double x) {
    return x * Math.PI / 180;
    }
0
répondu borchvm 2014-06-27 17:41:41