Верх страницы
Обложка к записи Расчет расстояний между городами по их координатам
Время для прочтения: 0 мин. 42 сек.

Расчет расстояний между городами по их координатам

Расчет расстояний между точками по их координатам на плоскости элементарен, на поверхности Земли — немного посложнее: мы рассмотрим измерение расстояния и начального азимута между точками без проекционных преобразований.

Для начала разберемся в терминологии.

Введение

Длина дуги большого круга – кратчайшее расстояние между любыми двумя точками находящимися на поверхности сферы, измеренное вдоль линии соединяющей эти две точки (такая линия носит название ортодромии) и проходящей по поверхности сферы или другой поверхности вращения.

Сферическая геометрия отличается от обычной Эвклидовой и уравнения расстояния также принимают другую форму. В Эвклидовой геометрии, кратчайшее расстояние между двумя точками – прямая линия. На сфере, прямых линий не бывает. Эти линии на сфере являются частью больших кругов – окружностей, центры которых совпадают с центром сферы.

Начальный азимут — азимут, взяв который при начале движения из точки А, следуя по большому кругу на кратчайшее расстояние до точки B, конечной точкой будет точка B. При движении из точки A в точку B по линии большого круга азимут из текущего положения на конечную точку B постоянно меняется. Начальный азимут отличен от постоянного, следуя которому, азимут из текущей точки на конечную не меняется, но маршрут следования не является кратчайшим расстоянием между двумя точками.

Через любые две точки на поверхности сферы, если они не прямо противоположны друг другу (то есть не являются антиподами), можно провести уникальный большой круг. Две точки, разделяют большой круг на две дуги. Длина короткой дуги – кратчайшее расстояние между двумя точками. Между двумя точками-антиподами можно провести бесконечное количество больших кругов, но расстояние между ними будет одинаково на любом круге и равно половине окружности круга, или π*R, где R – радиус сферы.

На плоскости (в прямоугольной системе координат), большие круги и их фрагменты, как было упомянуто выше, представляют собой дуги во всех проекциях, кроме гномонической, где большие круги — прямые линии. На практике это означает, что самолеты и другой авиатранспорт всегда использует маршрут минимального расстояния между точками для экономии топлива, то есть полет осуществляется по расстоянию большого круга, на плоскости это выглядит как дуга.

Форма Земли может быть описана как сфера, поэтому уравнения для вычисления расстояний на большом круге важны для вычисления кратчайшего расстояния между точками на поверхности Земли и часто используются в навигации.

Вычисление расстояния этим методом более эффективно и во многих случаях более точно, чем вычисление его для спроектированных координат (в прямоугольных системах координат), поскольку, во-первых, для этого не надо переводить географические координаты в прямоугольную систему координат (осуществлять проекционные преобразования) и, во-вторых, многие проекции, если неправильно выбраны, могу привести к значительным искажениям длин в силу особенностей проекционных искажений.

Известно, что более точно описывает форму Земли не сфера, а эллипсоид, однако в данной статье рассматривается вычисление расстояний именно на сфере, для вычислений используется сфера радиусом 6372795 метров, что может привести к ошибке вычисления расстояний порядка 0.5%.

Формулы

Существует три способа расчета сферического расстояния большого круга.

1. Сферическая теорема косинусов

В случае маленьких расстояний и небольшой разрядности вычисления (количество знаков после запятой), использование формулы может приводить к значительным ошибкам связанным с округлением.

φ1, λ1; φ2, λ2 — широта и долгота двух точек в радианах

Δλ — разница координат по долготе

Δδ — угловая разница

Δδ = arccos {sin φ1 sin φ2 + cos φ1 cos φ2 cos Δλ}

Для перевода углового расстояния в метрическое, нужно угловую разницу умножить на радиус Земли (6372795 метров), единицы конечного расстояния будут равны единицам, в которых выражен радиус (в данном случае — метры).

2. Формула гаверсинусов

Используется, чтобы избежать проблем с небольшими расстояниями.

3. Модификация для антиподов

Предыдущая формула также подвержена проблеме точек-антиподов, чтобы ее решить используется следующая ее модификация.

Моя реализация на РНР

// Радиус земли
define('EARTH_RADIUS', 6372795);
 
/*
* Расстояние между двумя точками
* $φA, $λA - широта, долгота 1-й точки,
* $φB, $λB - широта, долгота 2-й точки
* Написано по мотивам http://gis-lab.info/qa/great-circles.html
* Михаил Кобзарев <mikhail@kobzarev.com>
*
*/
function calculateTheDistance ($φA, $λA, $φB, $λB) {
 
// перевести координаты в радианы
$lat1 = $φA * M_PI / 180;
$lat2 = $φB * M_PI / 180;
$long1 = $λA * M_PI / 180;
$long2 = $λB * M_PI / 180;
 
// косинусы и синусы широт и разницы долгот
$cl1 = cos($lat1);
$cl2 = cos($lat2);
$sl1 = sin($lat1);
$sl2 = sin($lat2);
$delta = $long2 - $long1;
$cdelta = cos($delta);
$sdelta = sin($delta);
 
// вычисления длины большого круга
$y = sqrt(pow($cl2 * $sdelta, 2) + pow($cl1 * $sl2 - $sl1 * $cl2 * $cdelta, 2));
$x = $sl1 * $sl2 + $cl1 * $cl2 * $cdelta;
 
//
$ad = atan2($y, $x);
$dist = $ad * EARTH_RADIUS;
 
return $dist;
}

Пример вызова функции:

$lat1 = 77.1539;
$long1 = -139.398;
$lat2 = -77.1804;
$long2 = -139.55;
 
echo calculateTheDistance($lat1, $long1, $lat2, $long2) . " метров";
// Вернет "17166029 метров"

Статья взята с сайта gis-lab.info Автор: Максим Дубинин

Ссылки

Автор: Кобзарёв Михаил

Русский разработчик с 20-ти летним стажем. Работаю с PHP, ООП, JavaScript, Git, WordPress, Битрикс, Joomla, Drupal, Opencart, DLE, Laravel, Moonshine, SuiteCRM.

Оптимизирую сайты под Google Page Speed, настраиваю импорты для больших магазинов на WooCommerce + WP All Import. Пишу плагины на заказ. Все мои услуги.

Веду блог о разработке, дайджест в телеграмме и в ВК.

Вы всегда можете нанять меня.

Комментарии
Подписаться
Уведомить о
guest

34 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии
Максим Дубинин
13 лет назад

Мы не против когда используют материалы нашего сайта, но их использование должно сопровождаться _четким_ указанием источника.

Согласитесь, взять 1 в 1 авторский текст и иллюстрации и дать источник в разделе ссылки среди других никак не определяет кто же написал этот текст и создал эти иллюстрации.

Надеюсь на понимание и исправление этого мелкого недоразумения. Автор статьи.

Cimebiar
13 лет назад

суперский

Mari
13 лет назад

Легко разобраться в большом разнообразии гис, если знать цели применения

BaltikS
13 лет назад

А дистанция в каких единицах выражается???

Павел
Павел
12 лет назад
Ответить на  Кобзарёв Михаил

Да нет, в метрах

Ян
Ян
13 лет назад

У меня проблема. Я считал аналогичным способом опираясь на координаты с карт гугл. Потом пересчитал по Вашим формулам. Результат один и тот же. Но он не совпадает в полтора раза с данными померяными линейкой в том же гугл earth.
как получить результат приближенный к картам?

Jluc
Jluc
12 лет назад
Ответить на  Кобзарёв Михаил

А как её нужно учесть?
Просьба привести примеры методов дающих хорошую точность вычислений.

Andy
12 лет назад

Добрый день! Дополните статью примером вызова Вашей функции. Как правильно передать в функцию координаты точек? Спасибо!

akuba
12 лет назад

спасибо, кому надо адаптировал для javascript

function calculateDistance(latA, longA, latB, longB) {
    var EARTH_RADIUS = 6372795;

    lat1 = latA * Math.PI / 180;
    lat2 = latB * Math.PI / 180;
    long1 = longA * Math.PI / 180;
    long2 = longB * Math.PI / 180;
 
    cl1 = Math.cos(lat1);
    cl2 = Math.cos(lat2);
    sl1 = Math.sin(lat1);
    sl2 = Math.sin(lat2);
    delta = long2 - long1;
    cdelta = Math.cos(delta);
    sdelta = Math.sin(delta);
 
    y = Math.sqrt(Math.pow(cl2 * sdelta, 2) + Math.pow(cl1 * sl2 - sl1 * cl2 * cdelta, 2));
    x = sl1 * sl2 + cl1 * cl2 * cdelta;
 
    ad = Math.atan2(y, x);
    dist = Math.ceil(ad * EARTH_RADIUS);
 
    return dist;
}
RX200
RX200
3 лет назад
Ответить на  akuba

много лишнего, вот переписал в соответствии с более правильным алгоритмом построенным на основе Ортодомии:

function distance(latA, longA, latB, longB) {
   var EARTH_RADIUS = 6372795;//радиус земли в метрах.
   //Переводим угловые координаты в радианы, для функций javascript Math которые работают с радианами.
   let lat1 = latA * Math.PI / 180;
   let lat2 = latB * Math.PI / 180;
   let long1 = longA * Math.PI / 180;
   let long2 = longB * Math.PI / 180;
   
   //Получаем угловое расстояние в радианах, и так как в радианах просто умножаем на радиус.
   let a = Math.acos(Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(long2 – long1));
   return EARTH_RADIUS * a;
}
BlackTomCat
BlackTomCat
11 лет назад

Существует Vincenty формула, которая позволяет со значительной точностью рассчитываеть расстояние между пунками на Земле. Формула базируется на представлении Земли в виде эллипсоида. Причем можно использовать варианты WGS-84, на котором базируется современная геодезия, либо альтернативы. Для WGS-84 a=6378137m, b=6356752.314245m. Саму формулу легко найти на страницах. Точность около 0.115 mm

Micael
Micael
11 лет назад

помогите как можно расчитать расстояние между несколькими точками есть масив данных выводится через WHILE в PHP, грубо говоря есть х точек (трек) нужно расчитать его длину.

x-noname
11 лет назад

А тут долгота с широтой не перепутаны случайно? А то у меня с гуглом совпало, только после того, как поменял их местами.

Drol
Drol
7 лет назад
Ответить на  x-noname

Чувак! ТЫ реально прав! ЛЮДИ МЕНЯЙТЕ ИХ МЕСТАМИ тут есть ОШИБКА. Над Поменять координаты местами

egor
egor
11 лет назад

syntax error, unexpected ‘$’, expecting ‘&’ or variable

Максим
11 лет назад

Большое спасибо, за подбор формул, очень помогли!

Серго Арбузов
11 лет назад

Добрый день!
Спасибо — очень пригодилось!
Может вы сможете помочь мне с еще одной проблемой (которую я давно не могу решить, обгуглил уже все вдоль и поперек)
Задача следующая: необходимо получить координаты вершин многоугольника имя координаты (lat,lng) центра и радиус (в км или м — не важно)
Натолкните на мысль….

Максим
11 лет назад
Ответить на  Серго Арбузов

Может квадрата, раз радиус есть? Получается надо найти вершины квадрата, в который вписана окружность с известным радиусом и центром?

Александр Аваков
Александр Аваков
7 лет назад

Спасибо за метод

mihdan
7 лет назад
Ответить на  Александр Аваков

Всегда пожалуйста!

Anton Kondakov
6 лет назад

Всем, привет. Переписал на Java. Странно но у меня не получается.
77.1539/-139.398 -77.1804/-139.55
Ответ 1.7296047E7
по другим координатам, близко но не точно
77.1539/120.398 77.1804/129.55
Ответ 239902.0
Подскажите, пожалуйста где напортачил?
[code lang=»php»]
double _latA = 77.1539;
double _longA = -139.398;
double _latB = -77.1804;
double _longB = -139.55;
// перевести координаты в радианты
double lat1 =(_latA * Math.PI) / 180.; //φA
double lat2 = (_latB * Math.PI )/ 180.; //φB
double long1 = (_longA * Math.PI) / 180.; //λA
double long2 = (_longB * Math.PI) / 180.; //λB

// косинусы и синусы широт и разницы долгот
double cosLat1 = Math.cos(lat1);
double cosLat2 = Math.cos(lat2);
double sinLat1 = Math.sin(lat1);
double sinLat2 = Math.sin(lat2);
double delta = long1 — long2;
double cosDelta = Math.cos(delta);
double sinDelta = Math.sin(delta);

//вычисления длины большого круга
double y = Math.sqrt(Math.pow(cosLat1 * sinDelta, 2) Math.pow(cosLat1 * sinLat2 — sinLat1 * cosLat2 * cosDelta, 2));
double x = sinLat1 * sinLat2 cosLat1 * cosLat2 * sinDelta;

double ad = Math.atan2(y,x);
double dist = Math.ceil(ad * EARTH_RADIUS);
System.out.println(«The distance between this places is: » dist » meters»);
[code]

Александр
Александр
5 лет назад

Добрый день!
А есть пример для расчета координат на сфере по азимуту и расстоянию от реперной точки?
На плоскости очень уж неточно..

Предыдущая запись
Следующая запись

Давайте дружить
в Телеграме

Авторский блог вашего покорного слуги в Telegram про web, программирование, алгоритмы, инструменты разработчика, WordPress, Joomla, Opencart, Laravel, Moonshine, фильмы и сериалы