Obtenez la distance entre deux points géographiques

108

Je souhaite créer une application qui vérifie l'endroit le plus proche où se trouve un utilisateur. Je peux facilement obtenir la localisation de l'utilisateur et j'ai déjà une liste de lieux avec latitude et longitude.

Quelle serait la meilleure façon de connaître l'emplacement le plus proche de la liste par rapport à l'emplacement actuel de l'utilisateur.

Je n'ai rien trouvé dans les API google.

Chmouel Boudjnah
la source

Réponses:

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

Référence: http://developer.android.com/reference/android/location/Location.html#distanceTo(android.location.Location)

Praveen
la source
2
Probablement plus lent que d'utiliser Location.DistanceBetween () car il utilise des objets Location mais fonctionne très bien pour mes besoins.
ZoltanF
Quelle classe je dois importer pour l'emplacement import android.location.Location;ou laquelle
Pranav MS
@PranavMS oui android.location.Location;
AndrewS
Je pense que distanceTo renvoie la distance entre le premier et le dernier point mais sur une ligne rectale, donc si vous prenez une autre direction du point a au point b, il ne sera jamais précis car le chemin est différent, c'est quand la distance entre se joint, vous pouvez enregistrer chaque distance entre les points créés, puis avec les résultats finaux des paramètres [] obtenir la distance correcte.
Gastón Saillén
122

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

Regardez à distanceÀ ou à distanceEntre. Vous pouvez créer un objet Location à partir d'une latitude et d'une longitude:

Location location = new Location("");
location.setLatitude(lat);
location.setLongitude(lon);
haseman
la source
37
distanceBetween est une méthode statique qui prend 2 ensembles de points lat longs, vous n'avez donc même pas besoin d'instancier un objet Location =)
Stan Kurdziel
4
Je suis sûr qu'il voulait dire ça pour la distanceTométhode.
laph
C'est génial et très utile, mais à quoi sert le fournisseur String dans le constructeur?
miss.serena
33

Une solution approchée (basée sur une projection équirectangulaire), beaucoup plus rapide (elle ne nécessite que 1 trig et 1 racine carrée).

Cette approximation est pertinente si vos points ne sont pas trop éloignés. Il surestimera toujours par rapport à la distance transversale réelle. Par exemple, il n'ajoutera pas plus de 0,05382% à la distance réelle si le delta de latitude ou de longitude entre vos deux points ne dépasse pas 4 degrés décimaux .

La formule standard (Haversine) est la formule exacte (c'est-à-dire qu'elle fonctionne pour n'importe quel couple de longitude / latitude sur terre) mais elle est beaucoup plus lente car elle nécessite 7 racines trigonométriques et 2 racines carrées. Si vos deux points ne sont pas trop éloignés et que la précision absolue n'est pas primordiale, vous pouvez utiliser cette version approximative (équirectangulaire), qui est beaucoup plus rapide car elle n'utilise qu'une seule trigonométrique et une racine carrée.

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

Vous pouvez optimiser cela davantage en:

  1. Suppression de la racine carrée si vous comparez simplement la distance à une autre (dans ce cas, comparez les deux distances au carré);
  2. Factorisation du cosinus si vous calculez la distance entre un point maître et plusieurs autres (dans ce cas, vous effectuez la projection équirectangulaire centrée sur le point maître, vous pouvez donc calculer le cosinus une fois pour toutes les comparaisons).

Pour plus d'informations, voir: http://www.movable-type.co.uk/scripts/latlong.html

Il existe une belle implémentation de référence de la formule Haversine dans plusieurs langues à l' adresse : http://www.codecodex.com/wiki/Calculate_Distance_Between_Two_Points_on_a_Globe

Laurent Grégoire
la source
grand homme merci. Mais si j'ai besoin d'obtenir un ensemble d'emplacements autour d'un emplacement dans un périmètre, dois-je utiliser une boucle while pour vérifier chaque emplacement par rapport à celui recherché et ne conserver que ceux qui sont dans le périmètre?
themhz
Vous pouvez, mais c'est une approche de force brute O(n). Pour une O(1)solution, utilisez un index spatial 2D pour réduire les correspondances potentielles avant de calculer la solution exacte. On sort du cadre de cette question :)
Laurent Grégoire
c'est une très belle synthèse de belles optimisations possibles .. thx! Exactement ce que je cherchais
Sam Vloeberghs
Je voulais juste savoir si cette formule fonctionne pour les grandes distances
Sandipan Majhi
Voir la réponse, mais en bref: non , cela ne fonctionne pas sur de grandes distances. Plus la distance entre les deux points est grande, plus l'erreur est grande par rapport aux formules exactes de Haversine .
Laurent Grégoire
11

Vous pouvez utiliser plusieurs méthodes, mais pour déterminer laquelle est la meilleure, nous devons d'abord savoir si vous connaissez l'altitude de l'utilisateur, ainsi que l'altitude des autres points.

En fonction du niveau de précision que vous recherchez, vous pouvez vous pencher sur les formules Haversine ou Vincenty ...

Ces pages détaillent les formules et, pour les moins inclinés mathématiquement, expliquent également comment les implémenter dans un script!

Formule Haversine: http://www.movable-type.co.uk/scripts/latlong.html

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

Si vous rencontrez des problèmes avec l'une des significations des formules, il suffit de commenter et je ferai de mon mieux pour y répondre :)

Dwaine Bailey
la source
4

Il existe deux façons d'obtenir la distance entre LatLng.

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

Regarde ça

et deuxieme

public float distanceTo (Location dest) comme répondu par praveen.

Zar E Ahmer
la source
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
la source
1

Utilisez simplement la méthode suivante, passez-le lat et long et obtenez la distance en mètre:

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
la source
2
latlong1 et latlong2 ne sont pas définis
Garçon
1
qu'est-ce que latlong1 & latlong2?
Nisal Malinda Livera
0

vous pouvez obtenir la distance et le temps à l'aide de l'API google Map API Google Map

il suffit de passer le JSON téléchargé à cette méthode, vous obtiendrez la distance et le temps en temps réel entre deux 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);


}
Sai Gopi moi
la source
0

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

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

distance = R ⋅ c

où φ est la latitude, λ est la longitude, R est le rayon de la Terre (rayon moyen = 6 371 km);

notez que les angles doivent être en radians pour passer aux fonctions trigonométriques!

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
la source