Найти ближайшую долготу и широту в массиве? - PullRequest
16 голосов
/ 06 марта 2012

У меня есть долгота и широта в виде строки в PHP, как показано ниже

49.648881
-103.575312

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

array(
'0'=>array('item1','otheritem1details....','55.645645','-42.5323'),
'1'=>array('item1','otheritem1details....','100.645645','-402.5323')
);

Я хочу вернуть массив, который имеет ближайший тип long и lad.В этом случае это будет первый (и да, я знаю, что -400 не является возможным значением).

Есть ли какой-нибудь быстрый и простой способ сделать это?Я пробовал поиск по массиву, но это не сработало.

Разностный код

function distance($lat1, $lon1, $lat2, $lon2, $unit) { 

  $theta = $lon1 - $lon2; 
  $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta)); 
  $dist = acos($dist); 
  $dist = rad2deg($dist); 
  $miles = $dist * 60 * 1.1515;
  $unit = strtoupper($unit);

  if ($unit == "K") {
    return ($miles * 1.609344); 
  } else if ($unit == "N") {
      return ($miles * 0.8684);
    } else {
        return $miles;
      }
}

Ответы [ 4 ]

30 голосов
/ 06 марта 2012

Сначала необходимо отобразить расстояние каждого элемента до контрольной точки.

Затем вы сортируете карту, и затем вы можете определить, какое из них имеет самое низкое (или самое высокое, если вы перевернетесь поиск) расстояние:

$ref = array(49.648881, -103.575312);

$items = array(
    '0' => array('item1','otheritem1details....','55.645645','-42.5323'),
    '1' => array('item1','otheritem1details....','100.645645','-402.5323')
);

$distances = array_map(function($item) use($ref) {
    $a = array_slice($item, -2);
    return distance($a, $ref);
}, $items);

asort($distances);

echo 'Closest item is: ', var_dump($items[key($distances)]);

Выход:

Closest item is: array(4) {
  [0]=>
  string(5) "item1"
  [1]=>
  string(21) "otheritem1details...."
  [2]=>
  string(9) "55.645645"
  [3]=>
  string(8) "-42.5323"
}

Позаботьтесь, чтобы у вас был правильный порядок длинны и долготы.

Функция расстояния (только заголовок слегка изменился, а единицы измерения были отброшены):

function distance($a, $b)
{
    list($lat1, $lon1) = $a;
    list($lat2, $lon2) = $b;

    $theta = $lon1 - $lon2;
    $dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) +  cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
    $dist = acos($dist);
    $dist = rad2deg($dist);
    $miles = $dist * 60 * 1.1515;
    return $miles;
}
7 голосов
/ 07 марта 2012

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

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

x = Δlon * cos(lat)   // lat/lon are in radians!
y = Δlat
distance = R * sqrt( x² + y² )  // R is radius of the earth; 
                                // typical value is 6371 km

Ссылка: http://www.movable -type.co.uk / scripts / latlong.html

Код расстояния

function distanceMeters($lat1, $lon1, $lat2, $lon2) { 
  $x = deg2rad( $lon1 - $lon2 ) * cos( deg2rad( $lat1 ) );
  $y = deg2rad( $lat1 - $lat2 ); 
  $dist = 6371000.0 * sqrt( $x*$x + $y*$y );

  return $dist;
}
1 голос
/ 06 марта 2012

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

0 голосов
/ 06 марта 2012

Итерация по массиву, сравнение значений с тем, что у вас есть.Если значение меньше вашего текущего сохраненного значения (или если у вас нет текущего сохраненного значения), сохраните это значение вместо этого, в противном случае выбросьте его.

$closest = null;
foreach($array as $key => $value){
    $distance = //compare distance here;
    if ($closest === null || $closest > $distance) {
        $closest = $distance;
    };
};

Конечно, это будет сделаноболее сложным является тот факт, что широта и долгота находятся на сфере, а долготы 179 и -179 ближе, чем 90 и 179.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...