Получите расстояние между двумя географическими точками


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

Какой класс мне нужно импортировать для Location import android.location.Location;или какой
Pranav MS

@PranavMS да android.location.Location;
AndrewS

Я думаю, что distanceTo возвращает расстояние между первой и последней точкой, но в прямой линии, поэтому, если вы выберете какие-либо другие направления из точки a в точку b, его никогда не будет точным, поскольку путь другой, то есть когда distanceBetween соединяется, вы можете сохраните каждое расстояние между созданными точками, а затем с окончательным параметром results [] получите правильное расстояние.
Gastón Saillén

122

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

Смотрите в distanceTo или distanceBetween. Вы можете создать объект Location по широте и долготе:

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

37
distanceBetween - это статический метод, который принимает 2 набора длинных точек
широты

4
Я уверен, что он имел в виду distanceToметод.
лапф

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

33

Приближенное решение (на основе равнопрямоугольной проекции) намного быстрее (требуется только 1 триггер и 1 квадратный корень).

Это приближение актуально, если ваши точки не слишком далеко друг от друга. Он всегда будет завышен по сравнению с реальным гаверсинусным расстоянием. Например, это добавит не более 0,05382% к реальному расстоянию, если дельта широты или долготы между вашими двумя точками не превышает 4 десятичных градуса .

Стандартная формула (Хаверсинус) является точной (то есть она работает для любой пары долготы / широты на Земле), но намного медленнее, так как для этого требуется 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


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

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

это очень хороший обзор возможных оптимизаций .. спасибо! Именно то, что я искал
Sam Vloeberghs

Я просто хотел знать, работает ли эта формула на больших расстояниях
Сандипан Маджхи

Смотрите ответ, но вкратце: нет , на большие расстояния не работает. Чем больше расстояние между двумя точками, тем больше ошибка по сравнению с точной формулой Хаверсина .
Лоран Грегуар

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 не определены
Boy

1
что такое латлонг1 и латлонг2?
Нисал Малинда Ливера

0

вы можете получить расстояние и время с помощью Google Map API 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.