İki coğrafi nokta arasındaki mesafeyi öğrenin


108

Bir kullanıcının bulunduğu en yakın yeri kontrol eden bir uygulama yapmak istiyorum. Kullanıcının konumunu kolayca alabiliyorum ve enlem ve boylam ile yerlerin bir listesi zaten var.

Mevcut kullanıcı konumuna göre listenin en yakın yerini bilmenin en iyi yolu nedir?

Google API'lerinde hiçbir şey bulamadım.

Yanıtlar:


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

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


2
Location.DistanceBetween () kullanmaktan muhtemelen daha yavaştır çünkü Location nesnelerini kullanıyor ancak benim amaçlarım için çok iyi çalışıyor.
ZoltanF

Konum için hangi sınıfı import android.location.Location;veya hangisini içe
aktarmam gerekiyor

@PranavMS evet android.location.Location;
AndrewS

Bence uzaklık: İlk ve son nokta arasındaki mesafeyi rektal bir çizgide döndürmek için, yani a noktasından b noktasına başka yönler alırsanız, yol farklı olduğu için hiçbir zaman ilişkilendirilmeyecektir, yani mesafe arasındaki mesafe birleştiğinde oluşturulan noktalar arasındaki her mesafeyi kaydedin ve ardından nihai parametre sonuçlarıyla [] doğru mesafeyi alın.
Gastón Saillén

122

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

Mesafe veya Aradaki mesafeye bakın. Enlem ve boylamdan bir Location nesnesi oluşturabilirsiniz:

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

37
distanceBetween, 2 set enlem uzun nokta alan statik bir yöntemdir, bu nedenle bir Location nesnesini başlatmanıza bile gerek yoktur =)
Stan Kurdziel

4
Eminim bunu distanceToyöntem için kastetti .
laph

Bu harika ve süper faydalıdır, ancak yapılandırıcıdaki String sağlayıcısı ne için?
miss.serena

33

Yaklaşık bir çözüm (eşit köşeli bir projeksiyona dayalı), çok daha hızlı (yalnızca 1 trigonometrik ve 1 kare kök gerektirir).

Puanlarınız birbirinden çok uzak değilse, bu yaklaşım önemlidir. Gerçek haversine mesafesine kıyasla her zaman fazla tahmin edecektir . Örneğin , iki noktanız arasındaki delta enlemi veya boylamı 4 ondalık dereceyi geçmiyorsa , gerçek mesafeye % 0,05382'den fazlasını eklemeyecektir .

Standart formül (Haversine) kesin olanıdır (yani, dünyadaki herhangi bir boylam / enlem çiftinde işe yarar) ancak 7 trigonometrik ve 2 kare köke ihtiyaç duyduğundan çok daha yavaştır . Birkaç noktanız birbirinden çok uzak değilse ve mutlak hassasiyet çok önemli değilse, bu yaklaşık versiyonu (Equirectangular) kullanabilirsiniz; bu, yalnızca bir trigonometrik ve bir karekök kullandığı için çok daha hızlıdır.

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

Bunu şunlardan birini yaparak daha da optimize edebilirsiniz :

  1. Mesafeyi bir başkasıyla karşılaştırırsanız karekökü kaldırmak (bu durumda her iki mesafenin karesini karşılaştırın);
  2. Bir ana noktadan diğer birçok noktaya olan mesafeyi hesaplarsanız kosinüsü çarpanlarına ayırın (bu durumda, ana noktaya ortalanmış eşdüzgen projeksiyonu yaparsınız, böylece tüm karşılaştırmalar için kosinüsü bir kez hesaplayabilirsiniz).

Daha fazla bilgi için bkz: http://www.movable-type.co.uk/scripts/latlong.html

Haversine formülünün birkaç dilde güzel bir referans uygulaması var: http://www.codecodex.com/wiki/Calculate_Distance_Between_Two_Points_on_a_Globe


harika adam thanx. Ancak, bir çevredeki bir konumun etrafında bir dizi konum almam gerekirse, her konumu aranan konumla karşılaştırmak ve yalnızca çevrede bulunanları tutmak için bir süre döngüsü kullanmalı mıyım?
themhz

Yapabilirsin, ama bu bir kaba kuvvet yaklaşımı O(n). Bir O(1)çözüm için, kesin çözümü hesaplamadan önce olası eşleşmeleri kırpmak için 2B uzamsal indeks kullanın. Bu sorunun kapsamını bırakıyoruz :)
Laurent Grégoire

bu, olası güzel optimizasyonların çok güzel bir özetidir .. teşekkürler! Tam olarak aradığım şey
Sam Vloeberghs

Sadece bu formülün uzun mesafelerde işe
yarayıp yaramadığını

Cevabı görün, ama kısaca: hayır , uzun mesafelerde işe yaramıyor. İki nokta arasındaki mesafe ne kadar büyükse, kesin Haversine formülüne kıyasla hata o kadar büyük olur.
Laurent Grégoire

11

Kullanabileceğiniz birkaç yöntem var, ancak hangisinin en iyisi olduğunu belirlemek için öncelikle kullanıcının rakımının yanı sıra diğer noktaların rakımının farkında olup olmadığınızı bilmemiz gerekir.

Peşinde olduğunuz doğruluk seviyesine bağlı olarak Haversine veya Vincenty formüllerine bakabilirsiniz ...

Bu sayfalar, formülleri detaylandırıyor ve matematiksel olarak daha az eğilimli olanlar için aynı zamanda bunların komut dosyasında nasıl uygulanacağına dair bir açıklama da sağlıyor!

Haversine Formülü: http://www.movable-type.co.uk/scripts/latlong.html

Vincenty Formülü: http://www.movable-type.co.uk/scripts/latlong-vincenty.html

Formüllerdeki herhangi bir anlamla ilgili herhangi bir sorununuz varsa, sadece yorum yapın ve bunları cevaplamak için elimden geleni yapacağım :)


4

LatLng arasında mesafe almanın iki yolu vardır.

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

Bunu gör

ve ikinci

public float distanceTo (Location dest) praveen tarafından cevaplandığı gibi.


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

Sadece aşağıdaki yöntemi kullanın, enlem ve boylam geçin ve metre cinsinden mesafeyi alın:

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 ve latlong2 tanımlanmamış
Boy

1
latlong1 ve latlong2 nedir?
Nisal Malinda Livera

0

Google Map API Google Map API kullanarak mesafe ve süre elde edebilirsiniz

indirilen JSON'u bu yönteme geçirmeniz yeterlidir, iki enlem arasındaki gerçek zamanlı Mesafe ve Zaman

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 − bir))

mesafe = R ⋅ c

φ enlem, λ boylam, R dünyanın yarıçapı (ortalama yarıçap = 6,371 km);

trigonometrik fonksiyonlara geçmek için açıların radyan cinsinden olması gerektiğini unutmayın!

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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.