Отримайте відстань між двома геоточками


108

Я хочу зробити додаток, який перевіряє найближче місце, де знаходиться користувач. Я можу легко отримати місцезнаходження користувача, і у мене вже є список місць із широтою та довготою.

Який найкращий спосіб дізнатись найближче місце списку щодо поточного місцезнаходження користувача.

Я не зміг знайти нічого в API google.

Відповіді:


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

Довідка: http://developer.android.com/reference/android/location/Location.html#distanceTo(android.location.Location)


2
Можливо, повільніше, ніж використання Location.DistanceBetween (), оскільки він використовує об’єкти Location, але працює для моїх цілей дуже добре.
ZoltanF

Який клас мені потрібно імпортувати для місцеположення import android.location.Location;чи який
Pranav MS

@PranavMS так android.location.Location;
AndrewS

Я думаю, що distanceTo повертає відстань між першою та останньою точкою, але прямолінійною лінією, тож якщо ви будете приймати будь-які інші вказівки від точки a до b, вона ніколи не буде звинувачуватися, оскільки шлях інший, тобто коли distanceBet Between приєднується, ви можете збережіть кожну відстань між створеними точками, а потім з кінцевими результатами параметра [] отримайте правильну відстань.
Gastón Saillén

122

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

Подивіться на відстаньдо або відстань між. Ви можете створити об’єкт "Місцезнаходження" із широти та довготи:

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

37
distanceBet Between - це статичний метод, який займає 2 набори довгих точок, тому вам навіть не потрібно створювати об'єкт Location =)
Stan Kurdziel

4
Я впевнений, що він це мав на увазі для distanceToметоду.
laph

Це чудово і дуже корисно, але для чого постачальник String в конструкторі?
miss.serena

33

Наближене рішення (засноване на рівнокутній проекції), набагато швидше (для нього потрібен лише 1 трійник і 1 квадратний корінь).

Це наближення доречне, якщо ваші точки не надто далеко одна від одної. Це завжди буде завищено в порівнянні з реальною відстанью Гаверсина. Наприклад, це додасть не більше 0,05382% до реальної відстані, якщо дельта широта або довгота між вашими двома точками не перевищуватиме 4 десяткові градуси .

Стандартна формула (Haversine) є точною (тобто працює для будь-якої пари довготи / широти на землі), але набагато повільніше, оскільки їй потрібно 7 тригонометричних та 2 квадратних кореня. Якщо ваша пара очок не надто далеко одна від одної, і абсолютна точність не є першорядною, ви можете використовувати цю приблизну версію (Equirectangular), яка набагато швидша, оскільки використовується лише один тригонометричний і один квадратний корінь.

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

Ви можете оптимізувати це далі :

  1. Видалення квадратного кореня, якщо ви просто порівняєте відстань з іншою (у такому випадку порівняйте обидві відстані у квадраті);
  2. Розділення косинуса, якщо обчислити відстань від однієї головної точки до багатьох інших (у такому випадку ви робите прямокутну проекцію, зосереджену на головній точці, щоб ви могли обчислити косинус один раз для всіх порівнянь).

Для отримання додаткової інформації див: http://www.movable-type.co.uk/scripts/latlong.html

Приємна контрольна реалізація формули Хаверсіна кількома мовами: http://www.codecodex.com/wiki/Calculate_Distance_Between_Two_Points_on_a_Globe


великий чоловік ніж. Але якщо мені потрібно отримати набір розташувань навколо одного місця в периметрі, чи повинен я використовувати цикл часу, щоб перевірити кожне місце розташування проти шуканого та зберегти лише ті, які знаходяться в периметрі?
themhz

Можна, але це підхід грубої сили O(n). Для O(1)рішення використовуйте двовимірний просторовий індекс, щоб обрізати потенційні збіги, перш ніж обчислити точне рішення. Ми залишаємо сферу цього питання :)
Лоран Грегоар

це дуже приємний підбір хороших можливих оптимізацій .. thx! Саме те, що я шукав
Сем Влобергс

Мені просто хотілося дізнатися, чи працює ця формула на великих відстанях
Сандіпан Маджі

Дивіться відповідь, але коротко: ні , це не працює на великих відстанях. Чим більше відстань між двома точками, тим більша помилка порівняно з точною формулою Гаверсіна.
Лоран

11

Ви можете скористатися декількома методами, але щоб визначити, який із них найкращий, ми спочатку повинні знати, чи знаєте ви висоту користувача, а також висоту інших точок?

Залежно від рівня точності, яку ви шукаєте, ви можете заглянути у формули Гаверсіна чи Вінсентя ...

На цих сторінках докладно описані формули, і для менш математично схильних також є пояснення, як їх реалізувати в сценарії!

Формула Гаверсіна: http://www.movable-type.co.uk/scripts/latlong.html

Формула Вінсентя: http://www.movable-type.co.uk/scripts/latlong-vincenty.html

Якщо у вас є проблеми з будь-яким із значень у формулах, просто прокоментуйте, і я зроблю все можливе, щоб відповісти на них :)


4

Існує два способи отримати відстань між LatLng.

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

Дивіться це

і друге

public float distanceTo (Location dest) як відповів 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

Просто скористайтеся наступним методом, пропустіть його по ширині і довго і отримайте відстань у метрі:

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 та latlong2 не визначені
Хлопчик

1
що таке latlong1 & latlong2?
Nisal Malinda Livera

0

ви можете отримати відстань і час за допомогою API Google Map Map Google Map API

просто передайте завантажений JSON цьому методу, ви отримаєте в режимі реального часу відстань та час між двома латлонгами

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

відстань = R ⋅ c

де φ - широта, λ - довгота, R - радіус Землі (середній радіус = 6,371км);

зауважте, що кути повинні бути в радіанах, щоб перейти до триггерних функцій!

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.