Pregunta Calcule la distancia entre dos puntos de latitud y longitud? (Fórmula Haversine)


¿Cómo calculo la distancia entre dos puntos especificados por latitud y longitud?

Para aclarar, me gustaría la distancia en kilómetros; los puntos usan el sistema WGS84 y me gustaría entender las precisiones relativas de los enfoques disponibles.


704
2017-08-26 12:50


origen


Respuestas:


Esta enlazar puede ser útil para usted, ya que detalla el uso de la Fórmula Haversine para calcular la distancia

Extracto:

Este script [en Javascript] calcula las distancias de gran círculo entre los dos puntos:   es decir, la distancia más corta sobre la superficie de la tierra, utilizando el   Fórmula '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



Necesitaba calcular una gran cantidad de distancias entre los puntos para mi proyecto, así que seguí adelante y traté de optimizar el código, lo he encontrado aquí. En promedio en diferentes navegadores mi nueva implementación corre 2 veces más rápido que la respuesta más votada.

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
}

Puedes jugar con mi jsPerf y ver resultados aquí.

Recientemente tuve que hacer lo mismo en Python, así que aquí hay una implementación 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...

Y para completar: Haversine en wiki


256
2018-02-07 08:52



Aquí hay una implementación de 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



Aquí hay una implementación java de la fórmula 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));
}

Tenga en cuenta que aquí estamos redondeando la respuesta al km más cercano.


49
2017-09-26 11:00



Muchas gracias por todo esto. Usé el siguiente código en mi aplicación Objective-C para 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;
}

Latitud y Longitud están en decimal. No utilicé min () para la llamada a asin () ya que las distancias que estoy usando son tan pequeñas que no lo requieren.

Dio respuestas incorrectas hasta que aprobé los valores en radianes, ahora es más o menos lo mismo que los valores obtenidos de la aplicación Map de Apple :-)

Actualización adicional:

Si está utilizando iOS4 o posterior, entonces Apple proporciona algunos métodos para hacerlo, de modo que la misma funcionalidad se lograría con:

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



Esta es una función PHP simple que proporcionará una aproximación muy razonable (con un margen de error 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;
}
?>

Como se dijo antes; la tierra NO es una esfera. Es como una vieja y vieja pelota de béisbol con la que Mark McGwire decidió practicar: está llena de abolladuras y golpes. Los cálculos más simples (como este) lo tratan como una esfera.

Diferentes métodos pueden ser más o menos precisos según dónde se encuentre en este ovoide irregular Y qué tan separados estén sus puntos (cuanto más cerca estén, menor será el margen de error absoluto). Cuanto más precisa sea tu expectativa, más complejas serán las matemáticas.

Para más información: distancia geográfica de wikipedia


35
2018-06-24 14:11



Publiqué aquí mi ejemplo de trabajo.

Enumera todos los puntos en la tabla que tienen distancia entre un punto designado (usamos un punto aleatorio - lat: 45.20327, largo: 23.7806) menos de 50 KM, con latitud y longitud, en MySQL (los campos de la tabla son coord_lat y coord_long):

Enumere todos los que tengan DISTANCIA <50, en Kilómetros (se considera radio de la Tierra 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

El ejemplo anterior fue probado en MySQL 5.0.95 y 5.5.16 (Linux).


25
2018-03-12 23:37