Равнопрямоугольная аппроксимация в PHP

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

define('EARTH_RADIUS', 6371);

function equirectangularRad($latFrom, $lngFrom, $latTo, $lngTo) {
    $latDelta = $latTo - $latFrom;
    $lngDelta = $lngTo - $lngFrom;

    $x = $lngDelta * cos(($latFrom + $latTo) * .5);
    $radius = sqrt(($x * $x) + ($latDelta * $latDelta));

    return $radius * EARTH_RADIUS;
}

Кажется, что расстояния всегда рассчитываются с пересечением нулевого меридиана, а не кратчайшего расстояния. то есть от координаты (lat = 0, long = -180) до (lat = 0, long = 180) вдоль экватора расстояние должно быть нулевым. Вместо этого функция возвращает длину окружности Земли вдоль экватора; примерно 40030 км.

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

Для справки; это реализация гаверсинуса, которую я использую:

function haversineRad($latFrom, $lngFrom, $latTo, $lngTo) {
    $latDelta = $latTo - $latFrom;
    $lngDelta = $lngTo - $lngFrom;              

    $latSin = sin($latDelta * .5);
    $lngSin = sin($lngDelta * .5);
    $radius = 2. * asin(sqrt(($latSin * $latSin) + cos($latFrom) * cos($latTo) * ($lngSin * $lngSin)));

    return $radius * EARTH_RADIUS;
}   

person Martijn    schedule 01.12.2014    source источник
comment
@mudasobwa, по модулю 360 (или, скорее, 2 * пи) работать не будет. Где-то нужна инверсия. У меня есть некоторый ограниченный успех с использованием $lngDelta = abs($lngTo - $lngFrom); $lngDelta = min($lngDelta, (2 * pi()) - $lngDelta);, но это по-прежнему вызывает довольно большие ошибки на полюсах (с которыми я могу жить) и в значительной степени замедляет его примерно до скорости гаверсинуса (что делает использование равнопрямоугольного приближения бессмысленным).   -  person Martijn    schedule 01.12.2014


Ответы (2)


Я не знаю, откуда у вас свои формулы. Приведенные ниже 3 формулы рассчитывают расстояние между 2 координатами.

Равнопрямоугольный

function Equirectangular($lat1,$lng1,$lat2,$lng2){
$x = deg2rad($lng2-$lng1) * cos(deg2rad($lat1+$lat2)/2);
$y = deg2rad($lat1-$lat2);
$R = 6372.8; // gives d in km
$distance = sqrt($x*$x + $y*$y) * $R;
return $distance;
}

РЕДАКТИРОВАТЬ. Изменен Equirectangular () для учета комментария. Сделали значения lng абсолютными с помощью функции php abs (). Он начинает дрейфовать от хаверсинуса, когда lng2 переходит с отрицательного на положительный.

function Equirectangular($lat1,$lng1,$lat2,$lng2){
$lng1 = abs($lng1);
$lng2 = abs($lng2);
$alpha = $lng2-$lng1;
$x = deg2rad($alpha) * cos(deg2rad($lat1+$lat2)/2);
$y = deg2rad($lat1-$lat2);
$R = 6372.8; // gives d in km
$distance = sqrt($x*$x + $y*$y) * $R;
return $distance;
}

Гаверсин

function Haversine($lat1,$lng1,$lat2,$lng2) {
  $deltaLat = $lat2 - $lat1 ;
  $deltaLng = $lng2 - $lng1 ;
  $earthRadius = 6372.8; // 3959 in miles.
  $alpha = $deltaLat/2;
  $beta = $deltaLng/2;
  $a = sin(deg2rad($alpha)) * sin(deg2rad($alpha)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin(deg2rad($beta)) * sin(deg2rad($beta)) ;
  $c = 2 * atan2(sqrt($a), sqrt(1-$a));
  $distance = $earthRadius * $c;
  return $distance;
} 

СферическийЗаконКозин

function SphericalLawOfCosines($lat1,$lng1,$lat2,$lng2) {
 $lat1 = deg2rad($lat1);
 $lat2 = deg2rad($lat2);
 $deltaLng = deg2rad($lng2-$lng1);
 $R = 6372.8; // gives d in km
$d = acos( sin($lat1)*sin($lat2) + cos($lat1)*cos($lat2) * cos($deltaLng) ) * $R;
return $d;
}

Равнопрямоугольный - самый простой, но менее точный. Для двух других. Тот, который нужно использовать, зависит от задействованных расстояний. См. Это Ответ. Для небольших расстояний (порядка 1 метра или меньше) используйте хаверсин. Для больших расстояний используйте сферический закон косинусов.

Результаты по формулам

0, -179 до 0, -179 равнопрямоугольный 0 км Хаверсин 0 км

0, -179 до 0, -159 Равнопрямоугольный 2224,526851 км Хаверсин 2224,526851 км

0, -179 до 0, -139 Равнопрямоугольная 4449,053703 км Хаверсин 4449,053703 км

0, -179 до 0, -119 Равнопрямоугольный 6673,580554 км Хаверсин 6673,580554 км

0, -179 до 0, -99 Равнопрямоугольная 8898.107406 км Хаверсин 8898.107406 км

0, -179 до 0, -79 Равнопрямоугольная 11122,634257 км Хаверсин 11122,634257 км

0, -179 до 0, -59 Равнопрямоугольный 13347,161109 км Хаверсин 13347,161109 км

0, -179 до 0, -39 Равнопрямоугольный 15571.68796 км Хаверсин 15571.68796 км

0, -179 до 0, -19 Равнопрямоугольный 17796,214811 км Хаверсин 17796,214811 км

0, -179 до 0,1 Равнопрямоугольный 19798.288978 км Хаверсин 20020.741663 км

0, -179 до 0,21 Равнопрямоугольный 17573.762126 км Хаверсин 17796.214811 км

0, -179 до 0,41 Равнопрямоугольный 15349,235275 км Хаверсин 15571,68796 км

0, -179 до 0,61 Равнопрямоугольный 13124.708423 км Хаверсин 13347.161109 км

0, -179 до 0,81 Равнопрямоугольный 10900,181572 км Хаверсин 11122,634257 км

0, -179 до 0,101 Равнопрямоугольный 8675.654721 км Хаверсин 8898.107406 км

0, -179 до 0,121 Равнопрямоугольный 6451.127869 км Хаверсин 6673.580554 км

0, -179 до 0,141 Равнопрямоугольный 4226.601018 км Хаверсин 4449.053703 км

0, -179 до 0,161 Равнопрямоугольный 2002.074166 км Гаверсин 2224.526851 км

person david strachan    schedule 01.12.2014
comment
У них та же проблема, которую я описал в своем вопросе: Equirectangular(0,-179,0,179) возвращает 39819.030640452, Haversine(0,-179,0,179) возвращает 222.45268514219. Очевидно, что равнопрямоугольник не рассчитывает кратчайшее расстояние. SphericalLawOfCosines возвращает 222,45268514218, почти то же самое, что и Хаверсин. У формулы равнопрямоугольника есть проблемы с расстояниями, пересекающими меридиан долготы -180/180 градусов. - person Martijn; 02.12.2014
comment
@Martijn изменил Equirectangular(), чтобы рассмотреть комментарий. - person david strachan; 02.12.2014

Вы повторно используете latDelta одно из применений, добавляющее их, а другое - вычитаемое.

http://www.movable-type.co.uk/scripts/latlong.html

есть рабочий javascript.

переведено ..

$x = ($lngTo-$lngFrom) * cos(($latTo+$latFrom)/2);
$y = ($latTo-$latFrom)
$d = sqrt($x*$x + $y*$y) * EARTH_RADIUS;
person exussum    schedule 01.12.2014
comment
Я не вижу разницы между моей функцией и формулой на этой странице. (фактически, эта страница использовалась как ссылка). - person Martijn; 01.12.2014