2008-08-26 52 views
654

¿Cómo calculo la distancia entre dos puntos especificados por latitud y longitud?¿Calcula la distancia entre dos puntos de latitud y longitud? (Fórmula de Haversine)

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.

+0

Para una mayor precisión - ver https://stackoverflow.com/questions/1420045/how-to-find-distance-from-the -latitud-y-longitud-de-dos-ubicaciones/1422562 # 1422562 –

Respuesta

827

Este link puede ser útil para usted, ya que detalla el uso del Haversine formula para calcular la distancia.

Extracto:

Este script [en Javascript] calcula las distancias de círculo máximo entre los dos puntos - , es decir, la distancia más corta sobre la superficie de la tierra - con ayuda de la 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) 
} 
+27

¿Este cálculo/método explica que la Tierra sea un esferoide (no una esfera perfecta)? La pregunta original pedía distancia entre puntos en un globo WGS84. No estoy seguro de cuánto error se infiltra usando una esfera perfecta, pero sospecho que puede ser bastante dependiendo de dónde estén los puntos en el globo, por lo tanto, la distinción vale la pena tener en cuenta. – redcalx

+10

La fórmula de Haversine no tiene en cuenta que la Tierra sea un esferoide, por lo que recibirá algún error debido a ese hecho. No se puede garantizar que sea correcto a mejor que 0.5%. Sin embargo, ese puede o no ser un nivel aceptable de error. – Brandon

+2

Envolvió la lógica en una función, por lo que debería ser utilizable en JS de fábrica, realmente usándola en NodeJS ahora ... – Tracker1

5

Más bien depende de cómo es exacto que desea ser y lo datum del lat y largo se definen sucesivamente. Muy, muy aproximadamente, haces un poco de trigonometría esférica, pero corrigiendo el hecho de que la tierra no es una esfera hace que las fórmulas sean más complicadas.

3

Para calcular la distancia entre dos puntos en una esfera, debe hacer el Great Circle calculation.

Hay una serie de bibliotecas C/C++ para ayudar con la proyección del mapa en MapTools si necesita reproyectar sus distancias a una superficie plana. Para hacer esto necesitarás la cadena de proyección de los diversos sistemas de coordenadas.

También puede encontrar MapWindow una herramienta útil para visualizar los puntos. Además, como fuente abierta, es una guía útil sobre cómo usar la biblioteca proj.dll, que parece ser la biblioteca principal de proyección de código abierto.

56

Aquí es un C# Aplicación:

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

Está utilizando el radio ecuatorial, pero debe usar el radio medio, que es 6371 km –

+7

¿No debería ser 'doble dlon = Radians (lon2 - lon1);' y 'double dlat = Radians (lat2 - lat1) ; ' –

+0

Estoy de acuerdo con Chris Marisic. Usé el código original y los cálculos fueron incorrectos. Añadí la llamada para convertir los deltas a radianes y ahora funciona correctamente. Envié una edición y estoy esperando que sea revisada por pares. –

41

Muchas gracias por todo esto. He utilizado el siguiente código en mi Objective-C aplicación para el 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 son 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.

Se dieron respuestas incorrectas hasta que pasé en los valores en radianes - ahora es más o menos lo mismo que los valores obtenidos de aplicación de mapas de Apple :-)

actualización adicional:

Si está utilizando iOS4 o temprano entonces Apple presentan algunos métodos para hacer esto por lo que la misma funcionalidad se logra con:

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

    MKMapPoint start, finish; 


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

    return MKMetersBetweenMapPoints(start, finish)/1000; 
} 
+0

mente si lo uso en una aplicación de iOS estoy trabajando ¿en? UPVOTED :) –

+1

Disculpa la demora (!), Pero por supuesto está bien. :-) –

+0

iOS SDK tiene su propia implementación: https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocation_Class/#//apple_ref/occ/instm/CLLocation/distanceFromLocation: – tuler

1

Got Error- ningún método 'toRad'

Así modificado el procedimiento anterior para llamar toRad método-

toRad(lat2-lat1) 

Math.cos(toRad(lat1)) 

y añade el método-

//degrees to radians 
function toRad(degree) 
{ 
    rad = degree* Math.PI/ 180; 
    return rad; 
} 
23

he puesto aquí mi ejemplo de trabajo.

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

Lista teniendo todos DISTANCIA < 50, en kilómetros (radio considerado 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 se probó en MySQL 5.0.95 y 5.5.16 (Linux).

+0

Sería bueno tener esto para SQL Server (T-SQL). – JustJohn

+0

Luego créelo y publíquelo aquí :) – testing123

+0

Creo que un buen enfoque podría ser filtrar los resultados utilizando una aproximación, por lo que la fórmula pesada se aplica solo en algunos casos. Especialmente útil si tienes otras condiciones. Estoy usando esto para el aproximado inicial: http://stackoverflow.com/questions/1253499/simple-calculations-for-working-with-lat-lon-km-distance – Pato

31

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

Los 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: wikipedia geographic distance

+3

¡Esto funciona perfectamente! Acabo de agregar $ distance_miles = $ km * 0.621371; ¡y eso es todo lo que necesitaba para la distancia aproximada en millas! Gracias Tony. – scottcarmich

+1

tk u @ScottCarmichael. me alegro de que funcionó 4 u. –

+0

sí, AbraCadaver, quise decir Big Mac, está bien. Y gracias por la limpieza, rara vez me molesto en capitalizar más. –

47

Aquí es una aplicació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.

+0

Si quisiéramos calcular la distancia entre dos puntos en metros, ¿cuál sería la forma más precisa? Para usar '6371000' como el radio de la tierra? (radio medio de la tierra es 6371000 metros) o convertir kilómetros a metros de su función? – Micro

0

Aquí es una función de JavaScript simple que puede ser útil a partir de este link .. relacionados de alguna manera, pero estamos usando Google Earth Plugin javascript en lugar de mapas

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

Las unidades Tho no están en la distancia, pero en términos de una relación relativa a tus coordenadas.Hay otros cálculos relacionados que pueden sustituir a los getApproximateDistanceUnits funcionan link here

Entonces utilizar esta función para ver si una latitud y longitud se encuentra dentro del radio de

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

punto puede definirse como

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

luego puede hacer lo suyo para ver si un punto está dentro de una región con un radio decir:

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

     } 
1

no es un buen ejemplo de aquí para calcular la distancia con 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

Aquí está la aplicación VB.NET, esta aplicación le dará el resultado en km o millas en base a un valor de enumeración que pase .

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 
2

He resumido el cálculo simplificando la fórmula.

Aquí está en Rubí:

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 
7

Puede utilizar la estructura en CLLocationDistance para calcular esto:

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

En su caso si usted quiere los kilómetros simplemente dividir por 1000.

6

El haversine es definitivamente una buena fórmula para la mayoría de los casos, otras respuestas ya la incluyen, así que no voy a tomar el espacio. Pero es importante tener en cuenta que no importa qué fórmula se use (sí, no solo una). Debido a la amplia gama de precisión posible, así como el tiempo de cálculo requerido. La elección de la fórmula requiere un poco más de reflexión que una simple respuesta obvia.

El anuncio de una persona en la NASA, es el mejor que he encontrado en discutiendo las opciones

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

Por ejemplo, si usted está ordenando las filas de la distancia en un radio de 100 millas. La fórmula de tierra plana será mucho más rápida 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; 

Observe que hay un solo coseno y una raíz cuadrada. Vs 9 de ellos en la fórmula Haversine.

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

Solución de Chuck, válida también para millas.

226

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

Puede jugar con mi jsPerf y ver la results here.

recientemente que tenía que hacer lo mismo en Python, por lo que aquí es una aplicación pitón:

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 en aras de la exhaustividad: Haversine en la wiki.

+0

El js anterior parece estar 40 millas incorrecto cuando lo convierto de km a millas – AngularM

+0

@AngularM y ha calculado que está mal? ¿Con qué lo comparaste? –

+0

Lo comparé con los mapas de google. Parecía estar a 40 millas menos en comparación con los mapas de google de londres a birmingham – AngularM

1

Aquí está mi implementación de java para la distancia de cálculo mediante grados decimales después de algunas búsquedas. Utilicé el radio medio del mundo (de wikipedia) en km. Si quiere millas de resultados, use el radio mundial en millas.

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

En las otras respuestas falta una implementación en .

calcular la distancia entre dos puntos es bastante sencillo con la función de distm de la geosphere paquete:

distm(p1, p2, fun = distHaversine) 

donde:

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

A medida que la tierra no es perfectamente esférica, la Vincenty formula for ellipsoids es probablemente la mejor forma de calcular distancias Así, en el paquete geosphere que utilizar a continuación:

distm(p1, p2, fun = distVincentyEllipsoid) 

¡Por supuesto que no necesariamente tiene que usar geosphere paquete, también se puede calcular la distancia de la base de R con una función:

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 
    c <- 2 * asin(pmin(1, sqrt(a))) 
    d = R * c 
    return(d) 
} 
1

En Mysql utilice la siguiente función pase los parámetros como usando 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; 
0
//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; 
    } 
5

No me gusta agregar una respuesta más, pero la versión 3 API de Google Maps tiene geometría esférica (y más). Después de la conversión de su WGS84 a grados decimales se puede hacer esto:

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

No se sabe acerca de cómo precisa cálculos de Google son o incluso qué modelo se utiliza (aunque sí dice "esférica" ​​en lugar de "geoide" Por cierto. , la distancia "recta" será obviamente diferente de la distancia si uno viaja en la superficie de la tierra, que es lo que todos parecen estar suponiendo.

+0

distancia en metros. alternativamente uno puede usar computeLength() – electrobabe

0

He creado este pequeño objeto LatLng de Javascript, podría ser útil para alguien.

var latLng1 = new LatLng(5, 3); 
var latLng2 = new LatLng(6, 7); 
var distance = latLng1.distanceTo(latLng2); 

Código:

/** 
* latLng point 
* @param {Number} lat 
* @param {Number} lng 
* @returns {LatLng} 
* @constructor 
*/ 
function LatLng(lat,lng) { 
    this.lat = parseFloat(lat); 
    this.lng = parseFloat(lng); 

    this.__cache = {}; 
} 

LatLng.prototype = { 
    toString: function() { 
     return [this.lat, this.lng].join(","); 
    }, 

    /** 
    * calculate distance in km to another latLng, with caching 
    * @param {LatLng} latLng 
    * @returns {Number} distance in km 
    */ 
    distanceTo: function(latLng) { 
     var cacheKey = latLng.toString(); 
     if(cacheKey in this.__cache) { 
      return this.__cache[cacheKey]; 
     } 

     // the fastest way to calculate the distance, according to this jsperf test; 
     // http://jsperf.com/haversine-salvador/8 
     // http://stackoverflow.com/questions/27928 
     var deg2rad = 0.017453292519943295; // === Math.PI/180 
     var lat1 = this.lat * deg2rad; 
     var lng1 = this.lng * deg2rad; 
     var lat2 = latLng.lat * deg2rad; 
     var lng2 = latLng.lng * deg2rad; 
     var a = (
      (1 - Math.cos(lat2 - lat1)) + 
      (1 - Math.cos(lng2 - lng1)) * Math.cos(lat1) * Math.cos(lat2) 
      )/2; 
     var distance = 12742 * Math.asin(Math.sqrt(a)); // Diameter of the earth in km (2 * 6371) 

     // cache the distance 
     this.__cache[cacheKey] = distance; 

     return distance; 
    } 
}; 
0

tenido un problema con math.deg en LUA ... si alguien sabe una solución por favor, limpiar el código!

Mientras tanto, aquí hay una implementación de Haversine en LUA (¡use esto con Redis!)

function calcDist(lat1, lon1, lat2, lon2) 
    lat1= lat1*0.0174532925 
    lat2= lat2*0.0174532925 
    lon1= lon1*0.0174532925 
    lon2= lon2*0.0174532925 

    dlon = lon2-lon1 
    dlat = lat2-lat1 

    a = math.pow(math.sin(dlat/2),2) + math.cos(lat1) * math.cos(lat2) * math.pow(math.sin(dlon/2),2) 
    c = 2 * math.asin(math.sqrt(a)) 
    dist = 6371 * c  -- multiply by 0.621371 to convert to miles 
    return dist 
end 

aplausos!

1
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

implimentation Python origen es el centro de los Estados Unidos contiguos.

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

Para obtener la respuesta en kilómetros, simplemente configure millas = falso.

+1

Está importando un paquete no estándar que hace todo el trabajo. No sé si eso es tan útil. – Teepeemm

+0

El paquete está en el PyPI, Python Package Index, como un paquete de python 3 junto con numpy y scikit-learn. No estoy seguro de por qué uno está en contra de los paquetes. Tienden a ser bastante útiles. Como fuente abierta, también se podría examinar los métodos que contiene. Creo que a muchos les resultaría útil este paquete, así que dejaré la publicación a pesar del voto a la baja. Aclamaciones. :) – invoketheshell

2

Aquí está la implementación de respuesta aceptada portada a Java en caso de que alguien lo necesite.

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

Aquí es una mecanografiado aplicación de la fórmula 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; 
} 
4

No puede haber una solución más simple y más correcto: El perímetro de la tierra es 40.000 kilometros en el ecuador, alrededor de 37.000 en Ciclo Greenwich (o cualquier longitud). Por lo tanto:

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

Estoy de acuerdo que debe ser afinado-como, me dijeron que se trata de un elipsoide, por lo que el área para ser multiplicado por el coseno varía. Pero es un poco más preciso. En comparación con Google Maps, redujo significativamente el error.

+0

¿Esta función devuelve la distancia en km? – Wikki

+0

Lo es, solo porque el ecuador y los ciclos de longitud están en Km. Por millas, simplemente divida 40000 y 37000 por 1.6. Sintiéndose geek, puedes convertirla en Ris, multiplicarla por 7 o para parasang, dividir por 2.2 ;-) – Meymann

2

Todas las respuestas anteriores asumen que la tierra es una esfera. Sin embargo, una aproximación más precisa sería la de un esferoide achatado.

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 
0

aquí es un ejemplo en el postgres SQL (en km, para la versión millas, reemplazar 1,609344 por la versión 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; 
3

Este script [en PHP] calcula las distancias entre los dos puntos.

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

Aquí hay otro convertidos a Rubí código:

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 
Cuestiones relacionadas