Uzyskaj odległość między dwoma punktami geograficznymi

108

Chcę stworzyć aplikację, która sprawdza najbliższe miejsce, w którym przebywa użytkownik. Mogę łatwo uzyskać lokalizację użytkownika i mam już listę miejsc z długością i szerokością geograficzną.

Jaki byłby najlepszy sposób na sprawdzenie najbliższego miejsca na liście w porównaniu z bieżącą lokalizacją użytkownika.

Nie mogłem znaleźć nic w Google API.

Chmouel Boudjnah
źródło

Odpowiedzi:

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ódła: http://developer.android.com/reference/android/location/Location.html#distanceTo(android.location.Location)

praveen
źródło
2
Prawdopodobnie wolniej niż przy użyciu Location.DistanceBetween (), ponieważ używa obiektów Location, ale działa bardzo dobrze do moich celów.
ZoltanF,
Którą klasę muszę zaimportować do lokalizacji, import android.location.Location;a którą
Pranav MS
@PranavMS tak android.location.Location;
AndrewS,
Myślę, że odległość Aby zwrócić odległość między pierwszym a ostatnim punktem, ale w linii odbytu, więc jeśli wybierzesz inny kierunek od punktu a do b, nigdy nie zostanie on sprecyzowany, ponieważ ścieżka jest inna, to znaczy, gdy łączy się odległość między zapisz każdą odległość między utworzonymi punktami, a następnie z ostatecznymi wynikami parametrów [] uzyskaj prawidłową odległość.
Gastón Saillén
122

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

Spójrz na distanceTo lub distanceBetween. Możesz utworzyć obiekt Location na podstawie szerokości i długości geograficznej:

Location location = new Location("");
location.setLatitude(lat);
location.setLongitude(lon);
haseman
źródło
37
distanceBetween to metoda statyczna, która pobiera 2 zestawy długich punktów, więc nie musisz nawet tworzyć instancji obiektu Location =)
Stan Kurdziel
4
Jestem pewien, że miał to na myśli jako distanceTometoda.
laph
To jest świetne i bardzo pomocne, ale do czego służy dostawca String w konstruktorze?
miss.serena
33

Rozwiązanie przybliżone (oparte na rzucie równokątnym), znacznie szybsze (wymaga tylko 1 tryg. I 1 pierwiastka kwadratowego).

To przybliżenie jest istotne, jeśli Twoje punkty nie są zbyt daleko od siebie. To zawsze będzie zawyżone w porównaniu z rzeczywistą odległością haversine. Na przykład doda nie więcej niż 0,05382% do rzeczywistej odległości, jeśli różnica szerokości lub długości geograficznej między dwoma punktami nie przekracza 4 stopni dziesiętnych .

Standardowa formuła (Haversine) jest dokładna (to znaczy działa dla dowolnej długości / szerokości geograficznej na Ziemi), ale jest znacznie wolniejsza, ponieważ wymaga 7 pierwiastków trygonometrycznych i 2 pierwiastków kwadratowych. Jeśli kilka punktów nie jest zbyt daleko od siebie, a absolutna precyzja nie jest najważniejsza, możesz użyć tej przybliżonej wersji (Equirectangular), która jest znacznie szybsza, ponieważ wykorzystuje tylko jeden trygonometryczny i jeden pierwiastek kwadratowy.

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

Możesz to dalej zoptymalizować, wykonując jedną z następujących czynności:

  1. Usunięcie pierwiastka kwadratowego, jeśli po prostu porównasz odległość z inną (w takim przypadku porównaj obie odległości do kwadratu);
  2. Rozkładając na czynniki cosinus, jeśli obliczasz odległość od jednego punktu wzorcowego do wielu innych (w takim przypadku wykonujesz rzut równokątny wyśrodkowany na punkcie wzorcowym, dzięki czemu możesz obliczyć cosinus raz dla wszystkich porównań).

Więcej informacji można znaleźć pod adresem : http://www.movable-type.co.uk/scripts/latlong.html

Istnieje ładna implementacja referencyjna formuły Haversine w kilku językach pod adresem : http://www.codecodex.com/wiki/Calculate_Distance_Between_Two_Points_on_a_Globe

Laurent Grégoire
źródło
wielki człowiek dzięki. Ale jeśli chcę uzyskać zestaw lokalizacji wokół jednego miejsca na obwodzie, czy powinienem użyć pętli while, aby porównać każdą lokalizację z przeszukiwaną i zachować tylko te, które znajdują się na obwodzie?
themhz
Możesz, ale to podejście brutalnej siły O(n). Aby uzyskać O(1)rozwiązanie, użyj indeksu przestrzennego 2D, aby przyciąć potencjalne dopasowania przed obliczeniem dokładnego rozwiązania. Wychodzimy z zakresu tego pytania :)
Laurent Grégoire
jest to bardzo ładne podsumowanie dobrych możliwych optymalizacji .. dzięki! Dokładnie to, czego szukałem
Sam Vloeberghs
Chciałem tylko wiedzieć, czy ta formuła działa na duże odległości
Sandipan Majhi
Zobacz odpowiedź, ale w skrócie: nie , to nie działa na duże odległości. Im większa odległość między dwoma punktami, tym większy błąd w porównaniu z dokładną formułą Haversine'a .
Laurent Grégoire
11

Jest kilka metod, których możesz użyć, ale aby określić, która z nich jest najlepsza, najpierw musimy wiedzieć, czy znasz wysokość użytkownika, a także wysokość innych punktów?

W zależności od pożądanego poziomu dokładności możesz przyjrzeć się formułom Haversine lub Vincenty ...

Te strony wyszczególniają formuły, a dla mniej skłonnych matematycznie zawierają również wyjaśnienie, jak zaimplementować je w skrypcie!

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

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

Jeśli masz jakiekolwiek problemy z którymkolwiek ze znaczeń w formułach, po prostu skomentuj, a ja postaram się na nie odpowiedzieć :)

Dwaine Bailey
źródło
4

Istnieją dwa sposoby uzyskania odległości między LatLng.

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

Zobacz

i drugi

public float distanceTo (Location dest) jak odpowiedział praveen.

Zar E Ahmer
źródło
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
źródło
1

Po prostu użyj następującej metody, podaj szerokość i długość i uzyskaj odległość w metrach:

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
źródło
2
latlong1 i latlong2 nie są zdefiniowane
Boy
1
co to jest latlong1 i latlong2?
Nisal Malinda Livera
0

możesz uzyskać odległość i czas za pomocą Google Map API Google Map API

po prostu prześlij pobrany plik JSON do tej metody, a otrzymasz w czasie rzeczywistym odległość i czas między dwoma latlongami

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
źródło
0

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

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

odległość = R ⋅ c

gdzie φ to szerokość geograficzna, λ to długość geograficzna, R to promień Ziemi (średni promień = 6 371 km);

zwróć uwagę, że kąty muszą być podane w radianach, aby przejść do funkcji trygonometrycznych!

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
źródło