Относительная позиция в PHP между 2 точками (широта/долгота)

У меня есть база данных аэропортов с широтой и долготой для каждой точки. Я хочу запустить PHP-скрипт, чтобы найти все аэропорты, находящиеся рядом с данным аэропортом, с их расстоянием и относительным направлением.

т.е. для аэропорта KLDJ (40-37-02.810N 074-14-40.539W)

Аэропорт поблизости
KJFK – аэропорт имени Джона Ф. Кеннеди (21,2 морской мили к северо-востоку) (40-38-23.104N 073-46-44.132W)

Я использовал код с http://www.movable-type.co.uk/scripts/latlong.html, чтобы найти расстояние, и попытался использовать его для определения пеленга, что может быть неправильным.

//BEARING RHUMB LINE
$phi = log(tan($lat2/2+pi/4)/tan($lat1/2+pi/4));
$distance['bearing'] = (rad2deg(atan2($theta, $phi)) +180) % 360;

Я в основном хочу прогнать все точки через этот скрипт и найти расстояние, которое у меня уже есть, но потом направление. (т.е. С, Ю, З, В, СЗ, ЮЗ, СВ, ЮВ)


person Brian H    schedule 18.05.2010    source источник


Ответы (3)


В значительной степени заимствовано из методов координаты-в-php/" rel="noreferrer">здесь и с использованием данных из здесь, я собрал этот пример

<?php

$chicago = array(
    'lat' => 41.9
  , 'lng' => 87.65
);

$dallas = array(
    'lat' => 32.73
  , 'lng' => 96.97
);

$ftworth = array(
    'lat' => 32.82
  , 'lng' => 97.35
);

$bearing = getBearingBetweenPoints( $dallas, $chicago );

echo "Bearing: $bearing&deg;<br>";
echo "Direction: " . getCompassDirection( $bearing );

function getBearingBetweenPoints( $point1, $point2 )
{
  return getRhumbLineBearing( $point1['lat'], $point2['lng'], $point2['lat'], $point1['lng'] );
}

function getRhumbLineBearing($lat1, $lon1, $lat2, $lon2) {
  //difference in longitudinal coordinates
  $dLon = deg2rad($lon2) - deg2rad($lon1);

  //difference in the phi of latitudinal coordinates
  $dPhi = log(tan(deg2rad($lat2) / 2 + pi() / 4) / tan(deg2rad($lat1) / 2 + pi() / 4));

  //we need to recalculate $dLon if it is greater than pi
  if(abs($dLon) > pi()) {
    if($dLon > 0) {
      $dLon = (2 * pi() - $dLon) * -1;
    }
    else {
      $dLon = 2 * pi() + $dLon;
    }
  }
  //return the angle, normalized
  return (rad2deg(atan2($dLon, $dPhi)) + 360) % 360;
}

function getCompassDirection( $bearing )
{
  static $cardinals = array( 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'N' );
  return $cardinals[round( $bearing / 45 )];
}
person Peter Bailey    schedule 18.05.2010
comment
Питер, я пробовал это без особой удачи. Код выглядел очень похоже на то, что у меня было раньше, но с некоторыми особенностями, которые выглядели так, будто он может работать. Как я упоминал выше, я хорош на расстоянии, но пеленг/курс сбивает меня с толку. Когда я попробовал линейный код Rhumb, я просто получил странный результат. С вашими я получаю 0 или 180 градусов и всегда на север. Есть предположения? В любом случае, я ценю усилия! - person Brian H; 20.05.2010
comment
работает отлично, прямо из коробки. конечно, есть геометрические упрощения (земля НЕ идеальная сфера), которые вполне приемлемы, особенно для относительно небольших расстояний в десятки миль. ПРОГОЛОСОВАНО! :) - person tony gil; 02.12.2013

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

person cem    schedule 18.05.2010

Глядя на другую страницу того же сайта:

$lat = 0;  // latitude of centre of bounding circle in degrees
$lon = 0;  // longitude of centre of bounding circle in degrees
$rad = 0;  // radius of bounding circle in chosen units

// Choose your unit of measure... 
$r = 6371;  // earth's radius in km
$r = 3959;  // earth's radius in miles
// or
$r = 3440;  // earth's radius in nautical miles

// convert point of origin to radians
$lat = deg2rad($lat);
$lon = deg2rad($lon);

// first-cut bounding box (in radians)
$maxLat = $lat + $rad / $r;
$minLat = $lat - $rad / $r;
// compensate for longitude getting smaller with increasing latitude
$maxLon = ( $lon + $rad / $r ) / cos( $lat );
$minLon = ( $lon - $rad / $r ) / cos( $lat );

в сочетании с запросом:

$query = 'SELECT
  id
, lat
, lon
, ACOS(SIN('.$lat.') * SIN(RADIANS(lat)) + COS('.$lat.') * COS(RADIANS(lat)) * COS(RADIANS(lon) - '. $lon.')) * '.$r.' AS distance
FROM (
   SELECT
     id
   , lat
   , lon
   FROM MyTable
   WHERE 
     RADIANS(lat) > $minLat AND RADIANS(lat) < '.$maxLat.'
    AND 
     RADIANS(lon) > $minLon AND RADIANS(lon) < '.$maxLon.'
) AS FirstCut 
WHERE ACOS(SIN('.$lat.') * SIN(RADIANS(lat)) + COS('.$lat.') * COS(RADIANS(lat)) * COS(RADIANS(lon) - '. $lon.')) * '.$r.' < '.$rad;

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

Осталось только рассчитать азимут для возвращаемых местоположений. Что можно сделать с помощью формулы линии румба.

Вышеприведенное предполагает, что ваша база данных заполнена координатами в градусах.

Если бы вы хранили свои местоположения в виде объектов геометрии, вы могли бы использовать Встроенные пространственные функции MySQL. Хотя я совершенно уверен, что MySQL включает только ограничивающие прямоугольники.

person Jacco    schedule 18.05.2010
comment
Да, у меня был запрос посмотреть все 20 тысяч аэропортов и узнать расстояние. Я сопоставил это с некоторыми другими онлайн-инструментами, и мои расчеты были правильными. Проблема заключалась в моей формуле локсодромии, я ошибся на -12 до +18 градусов, поэтому решил, что сделал что-то не так, поэтому обратился к сообществу ... хотя мог бы использовать вышеизложенное некоторое время назад :) - person Brian H; 19.05.2010
comment
Было бы полезно, если бы вы добавили эту информацию к вопросу. - person Jacco; 19.05.2010