Определение расстояния между двумя точками на карте
Содержание
Для вычисления расстояния в километрах между двумя географическими точками, которые заданы парой координат, воспользуемся формулой гаверсинуса. Она точно вычисляет кратчайшее расстояние между двумя точками на поверхности сферы с учетом ее кривизны.
Формула гаверсинуса
Гаверсинус (haversine) – специальная математическая функция, равная sin²(θ/2).
Формула гаверсинуса для расстояния между двумя точками на сфере:
Она же текстом:
a = sin²((φ2 − φ1) / 2) + cos φ1 ⋅ cos φ2 ⋅ sin²((λ2 − λ1) / 2)
c = 2 ⋅ arcsin(√a)
d = r ⋅ c
где φ1, φ2 – координаты по широте в радианах; λ1, λ1 – координаты по долготе в радианах; r – радиус Земли в километрах (в среднем он равен примерно 6371 км).
Вариация с Atan2 и почему
Вместо arcsin для расчетов будем использовать atan2. Оба варианта математически эквивалентны, но atan2 более стабилен численно.
c = 2 ⋅ arcsin(√a)
c = 2 ⋅ atan2(√a, √(1 − a))
Функция arcsin определена только для аргументов в диапазоне [-1, 1]. Из-за ошибок округления с плавающей точкой значение a может стать чуть больше 1, что вызовет ошибку:
// Потенциальная проблема:
const a = 1.0000000000000001; // Из-за ошибок округления
const c = 2 * Math.asin(Math.sqrt(a)); // Ошибка! asin(>1) не определен
atan2(y, x) более устойчив к ошибкам округления. Даже если из-за численных погрешностей a станет чуть больше 1, atan2(y, x) продолжит корректно работать:
// Более устойчивый вариант:
const a = 1.0000000000000001;
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); // Работает!
Реализация на JS
//расстояние между 2 точками на карте по формуле гаверсина
function dist2CoordsInKm(coord1, coord2) {
const [lat1, lon1] = coord1;
const [lat2, lon2] = coord2;
const R = 6371; // Радиус Земли в км
const dLat = degToRad(lat2 - lat1);
const dLon = degToRad(lon2 - lon1);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(degToRad(lat1)) * Math.cos(degToRad(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}
//перевод градусов в радианы
function degToRad(deg) {
return deg * (Math.PI / 180);
}
Функция принимает на вход 2 точки, которые заданы парой координат [lat, lon].
Пример использования (Москва и Санкт-Петербург):
dist2CoordsInKm([55.7540584, 37.62049], [59.9390012, 30.3158184]); //634.4325191115644
Преимущества перед плоскими расчетами
- Корректно работает на больших расстояниях
- Учитывает реальную форму Земли
- Точно вычисляет расстояния между географическими координатами
Оставьте комментарий
Если эта статья была полезной для вас, оставьте комментарий ниже или задайте интересующий Вас вопрос. Ваш опыт может помочь другим читателям!
Написать комментарий