Obtener la distancia entre dos puntos geográficos

108

Quiero hacer una aplicación que verifique el lugar más cercano donde se encuentra un usuario. Puedo obtener fácilmente la ubicación del usuario y ya tengo una lista de lugares con latitud y longitud.

¿Cuál sería la mejor manera de conocer el lugar más cercano de la lista con la ubicación actual del usuario?

No pude encontrar nada en las API de Google.

Chmouel Boudjnah
fuente

Respuestas:

164
Location loc1 = new Location("");
loc1.setLatitude(lat1);
loc1.setLongitude(lon1);

Location loc2 = new Location("");
loc2.setLatitude(lat2);
loc2.setLongitude(lon2);

float distanceInMeters = loc1.distanceTo(loc2);

Referencia: http://developer.android.com/reference/android/location/Location.html#distanceTo(android.location.Location)

praveen
fuente
2
Probablemente más lento que usar Location.DistanceBetween () ya que usa objetos Location pero funciona muy bien para mis propósitos.
ZoltanF
Qué clase tengo que importar para la ubicación import android.location.Location;o cuál
Pranav MS
@PranavMS sí android.location.Location;
AndrewS
Creo que distanceTo devuelve la distancia entre el primer y el último punto, pero en una línea rectal, por lo que si toma cualquier otra dirección desde el punto a hasta b, nunca se aclarará, ya que el camino es diferente, ahí es cuando se une la distancia entre, puede guarde cada distancia entre los puntos que se han creado y luego con los resultados del parámetro final [] obtenga la distancia correcta.
Gastón Saillén
122

http://developer.android.com/reference/android/location/Location.html

Mire en distanceTo o distanceBetween. Puede crear un objeto de ubicación a partir de una latitud y una longitud:

Location location = new Location("");
location.setLatitude(lat);
location.setLongitude(lon);
haseman
fuente
37
distanceBetween es un método estático que toma 2 conjuntos de puntos de latitud, por lo que ni siquiera es necesario crear una instancia de un objeto de ubicación =)
Stan Kurdziel
4
Estoy seguro de que quiso decir eso por distanceTométodo.
laph
Esto es genial y muy útil, pero ¿para qué sirve el proveedor String en el constructor?
miss.serena
33

Una solución aproximada (basada en una proyección equirrectangular), mucho más rápida (solo requiere 1 trig y 1 raíz cuadrada).

Esta aproximación es relevante si sus puntos no están muy separados. Siempre se sobrestimará en comparación con la distancia real de Haversine. Por ejemplo, no agregará más de 0.05382% a la distancia real si la latitud o longitud delta entre sus dos puntos no excede los 4 grados decimales .

La fórmula estándar (Haversine) es la exacta (es decir, funciona para cualquier par de longitud / latitud en la tierra) pero es mucho más lenta ya que necesita 7 raíces trigonométricas y 2 cuadradas. Si sus dos puntos no están muy separados y la precisión absoluta no es primordial, puede usar esta versión aproximada (equirrectangular), que es mucho más rápida ya que usa solo una raíz trigonométrica y una raíz cuadrada.

// Approximate Equirectangular -- works if (lat1,lon1) ~ (lat2,lon2)
int R = 6371; // km
double x = (lon2 - lon1) * Math.cos((lat1 + lat2) / 2);
double y = (lat2 - lat1);
double distance = Math.sqrt(x * x + y * y) * R;

Puede optimizar esto aún más mediante:

  1. Quitar la raíz cuadrada si simplemente compara la distancia con otra (en ese caso, compare ambas distancias al cuadrado);
  2. Factorizar el coseno si calcula la distancia desde un punto maestro a muchos otros (en ese caso, hace la proyección equirrectangular centrada en el punto maestro, por lo que puede calcular el coseno una vez para todas las comparaciones).

Para obtener más información, consulte: http://www.movable-type.co.uk/scripts/latlong.html

Hay una buena implementación de referencia de la fórmula de Haversine en varios idiomas en: http://www.codecodex.com/wiki/Calculate_Distance_Between_Two_Points_on_a_Globe

Laurent Grégoire
fuente
gran hombre gracias. Pero si necesito obtener un conjunto de ubicaciones alrededor de una ubicación en un perímetro, ¿debería usar un bucle while para comparar cada ubicación con la buscada y mantener solo las que están en el perímetro?
themhz
Puedes, pero ese es un enfoque de fuerza bruta O(n). Para una O(1)solución, use un índice espacial 2D para recortar las coincidencias potenciales antes de calcular la solución exacta. Salimos del alcance de esta pregunta :)
Laurent Grégoire
Este es un resumen muy agradable de posibles optimizaciones agradables ... ¡gracias! Exactamente lo que estaba buscando
Sam Vloeberghs
Solo quería saber si esta fórmula funciona para grandes distancias
Sandipan Majhi
Vea la respuesta, pero en resumen: no , no funciona para grandes distancias. Cuanto mayor sea la distancia entre los dos puntos, mayor será el error en comparación con las fórmulas exactas de Haversine .
Laurent Grégoire
11

Hay un par de métodos que podría utilizar, pero para determinar cuál es el mejor, primero debemos saber si conoce la altitud del usuario, así como la altitud de los otros puntos.

Dependiendo del nivel de precisión que busque, puede buscar en las fórmulas de Haversine o Vincenty ...

Estas páginas detallan las fórmulas y, para los menos inclinados a las matemáticas, también proporcionan una explicación de cómo implementarlas en un script.

Fórmula de Haversine: http://www.movable-type.co.uk/scripts/latlong.html

Fórmula Vincenty: http://www.movable-type.co.uk/scripts/latlong-vincenty.html

Si tiene algún problema con alguno de los significados en las fórmulas, simplemente comente y haré todo lo posible para responderlos :)

Dwaine Bailey
fuente
4

Hay dos formas de calcular la distancia entre LatLng.

public static void distanceBetween (double startLatitude, double startLongitude, double endLatitude, double endLongitude, float[] results)

Mira esto

y segundo

public float distanceTo (Location dest) como respondió praveen.

Zar E Ahmer
fuente
3
private float getDistance(double lat1, double lon1, double lat2, double lon2) {
        float[] distance = new float[2];
        Location.distanceBetween(lat1, lon1, lat2, lon2, distance);
        return distance[0];
    }
Levon Petrosyan
fuente
1

Simplemente use el siguiente método, páselo lat y long y obtenga la distancia en metros:

private static double distance_in_meter(final double lat1, final double lon1, final double lat2, final double lon2) {
    double R = 6371000f; // Radius of the earth in m
    double dLat = (lat1 - lat2) * Math.PI / 180f;
    double dLon = (lon1 - lon2) * Math.PI / 180f;
    double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
            Math.cos(latlong1.latitude * Math.PI / 180f) * Math.cos(latlong2.latitude * Math.PI / 180f) *
                    Math.sin(dLon/2) * Math.sin(dLon/2);
    double c = 2f * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    double d = R * c;
    return d;
}
farhad.kargaran
fuente
2
latlong1 y latlong2 no están definidos
Chico
1
¿Qué es latlong1 y latlong2?
Nisal Malinda Livera
0

puede obtener la distancia y el tiempo utilizando la API de mapas de Google API de mapas de Google

simplemente pase el JSON descargado a este método, obtendrá la distancia y el tiempo en tiempo real entre dos latlong's

void parseJSONForDurationAndKMS(String json) throws JSONException {

    Log.d(TAG, "called parseJSONForDurationAndKMS");
    JSONObject jsonObject = new JSONObject(json);
    String distance;
    String duration;
    distance = jsonObject.getJSONArray("routes").getJSONObject(0).getJSONArray("legs").getJSONObject(0).getJSONObject("distance").getString("text");
    duration = jsonObject.getJSONArray("routes").getJSONObject(0).getJSONArray("legs").getJSONObject(0).getJSONObject("duration").getString("text");

    Log.d(TAG, "distance : " + distance);
    Log.d(TAG, "duration : " + duration);

    distanceBWLats.setText("Distance : " + distance + "\n" + "Duration : " + duration);


}
Sai Gopi Me
fuente
0

a = sin² (Δφ / 2) + cos φ1 ⋅ cos φ2 ⋅ sin² (Δλ / 2)

c = 2 ⋅ atan2 (√a, √ (1 − a))

distancia = R ⋅ c

donde φ es la latitud, λ es la longitud, R es el radio de la Tierra (radio medio = 6.371 km);

¡tenga en cuenta que los ángulos deben estar en radianes para pasar a funciones trigonométricas!

fun distanceInMeter(firstLocation: Location, secondLocation: Location): Double {
    val earthRadius = 6371000.0
    val deltaLatitudeDegree = (firstLocation.latitude - secondLocation.latitude) * Math.PI / 180f
    val deltaLongitudeDegree = (firstLocation.longitude - secondLocation.longitude) * Math.PI / 180f
    val a = sin(deltaLatitudeDegree / 2).pow(2) +
            cos(firstLocation.latitude * Math.PI / 180f) * cos(secondLocation.latitude * Math.PI / 180f) *
            sin(deltaLongitudeDegree / 2).pow(2)
    val c = 2f * atan2(sqrt(a), sqrt(1 - a))
    return earthRadius * c
}


data class Location(val latitude: Double, val longitude: Double)
Kourosh
fuente