Calcola la distanza tra due punti geografici


108

Voglio creare un'app che controlli il luogo più vicino a cui si trova un utente. Posso facilmente ottenere la posizione dell'utente e ho già un elenco di luoghi con latitudine e longitudine.

Quale sarebbe il modo migliore per conoscere la posizione più vicina dell'elenco rispetto alla posizione dell'utente corrente.

Non sono riuscito a trovare nulla nelle API di Google.

Risposte:


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

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


2
Probabilmente più lento rispetto all'utilizzo di Location.DistanceBetween () poiché utilizza oggetti Location ma funziona molto bene per i miei scopi.
ZoltanF

Quale classe devo importare per la posizione import android.location.Location;o quale
Pranav MS

@PranavMS sì android.location.Location;
AndrewS

Penso che la distanza To restituisca la distanza tra il primo e l'ultimo punto ma in una linea rettale, quindi se prendi qualsiasi altra direzione dal punto a al punto b non sarà mai precisa poiché il percorso è diverso, ecco quando la distanza tra si unisce, puoi salvare ogni distanza tra i punti creati e poi con i risultati del parametro finale [] ottenere la distanza corretta.
Gastón Saillén

122

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

Guarda in distanceTo o distanceBetween. Puoi creare un oggetto Posizione da una latitudine e longitudine:

Location location = new Location("");
location.setLatitude(lat);
location.setLongitude(lon);

37
distanceBetween è un metodo statico che richiede 2 set di punti lat long, quindi non è nemmeno necessario istanziare un oggetto Location =)
Stan Kurdziel

4
Sono sicuro che lo intendesse per distanceTometodo.
laph

Questo è ottimo e super utile, ma a cosa serve il provider di stringhe nel costruttore?
miss

33

Una soluzione approssimata (basata su una proiezione equirettangolare), molto più veloce (richiede solo 1 trigonometrico e 1 radice quadrata).

Questa approssimazione è rilevante se i tuoi punti non sono troppo distanti. Sarà sempre sopravvalutare rispetto alla distanza reale dell'haversine. Ad esempio, aggiungerà non più dello 0,05382% alla distanza reale se il delta di latitudine o longitudine tra i due punti non supera i 4 gradi decimali .

La formula standard (Haversine) è quella esatta (cioè funziona per qualsiasi coppia di longitudine / latitudine sulla terra) ma è molto più lenta in quanto necessita di 7 radici trigonometriche e 2 radici quadrate. Se la tua coppia di punti non è troppo lontana e la precisione assoluta non è fondamentale, puoi usare questa versione approssimativa (equirettangolare), che è molto più veloce in quanto utilizza solo una radice trigonometrica e una radice quadrata.

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

Puoi ottimizzarlo ulteriormente in uno dei seguenti modi:

  1. Rimuovendo la radice quadrata se si confronta semplicemente la distanza con un'altra (in tal caso si confronta entrambe le distanze al quadrato);
  2. Scomporre il coseno se si calcola la distanza da un punto master a molti altri (in tal caso si esegue la proiezione equirettangolare centrata sul punto master, in modo da poter calcolare il coseno una volta per tutti i confronti).

Per maggiori informazioni vedere: http://www.mohable-type.co.uk/scripts/latlong.html

C'è una bella implementazione di riferimento della formula Haversine in diverse lingue su: http://www.codecodex.com/wiki/Calculate_Distance_Between_Two_Points_on_a_Globe


grand'uomo grazie. Ma se ho bisogno di ottenere una serie di posizioni attorno a una posizione in un perimetro, dovrei usare un ciclo while per controllare ogni posizione rispetto a quella cercata e mantenere solo quelle che si trovano nel perimetro?
themhz

Puoi, ma questo è un approccio di forza bruta O(n). Per una O(1)soluzione, utilizzare un indice spaziale 2D per tagliare le potenziali corrispondenze prima di calcolare la soluzione esatta. Stiamo abbandonando lo scopo di questa domanda :)
Laurent Grégoire

questo è un bel riassunto di belle possibili ottimizzazioni .. grazie! Esattamente quello che stavo cercando
Sam Vloeberghs

Volevo solo sapere se questa formula funziona per grandi distanze
Sandipan Majhi

Vedi la risposta, ma in breve: no , non funziona per grandi distanze. Maggiore è la distanza tra i due punti, maggiore sarà l'errore rispetto alle esatte formule di Haversine .
Laurent Grégoire

11

Ci sono un paio di metodi che potresti usare, ma per determinare quale è il migliore dobbiamo prima sapere se sei consapevole dell'altitudine dell'utente, così come l'altitudine degli altri punti?

A seconda del livello di precisione che stai cercando, potresti esaminare le formule Haversine o Vincenty ...

Queste pagine descrivono in dettaglio le formule e, per i meno inclini alla matematica, forniscono anche una spiegazione su come implementarle in script!

Formula Haversine: http://www.mohable-type.co.uk/scripts/latlong.html

Formula Vincenty: http://www.mohable-type.co.uk/scripts/latlong-vincenty.html

Se hai problemi con uno qualsiasi dei significati nelle formule, commenta e farò del mio meglio per risponderti :)


4

Ci sono due modi per ottenere la distanza tra LatLng.

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

Guarda questo

e secondo

public float distanceTo (Location dest) come risposto da praveen.


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

1

Usa il seguente metodo, passalo lungo e lungo e ottieni la distanza in metri:

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

2
latlong1 e latlong2 non sono definiti
Ragazzo

1
cosa sono latlong1 e latlong2?
Nisal Malinda Livera

0

puoi ottenere distanza e tempo utilizzando l'API di Google Map Google Map API di Google Map

basta passare il JSON scaricato a questo metodo per ottenere la distanza e il tempo in tempo reale tra due latlong

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


}

0

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

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

distanza = R ⋅ c

dove φ è la latitudine, λ è la longitudine, R è il raggio terrestre (raggio medio = 6.371 km);

nota che gli angoli devono essere in radianti per passare alle funzioni trigonometriche!

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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.