PHP MySql и геолокация

Я пишу сайт, который в основном ищет места в радиусе 25 миль от лата и долго, используя php и mysql.

Мне интересно, как это работает?

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

Каков наилучший способ сделать это?

EDIT: Я нашел этот код для вычисления расстояния между двумя точками.

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; } } 

Является ли способ сделать это вычисление в MYSQL, чтобы посмотреть, так что я могу вернуться только в том случае, если мили = <25?

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

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

Ориентировочное расстояние в милях:

 sqrt(x * x + y * y) where x = 69.1 * (lat2 - lat1) and y = 53.0 * (lon2 - lon1) 

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

Улучшенное приблизительное расстояние в милях:

 sqrt(x * x + y * y) where x = 69.1 * (lat2 - lat1) and y = 69.1 * (lon2 - lon1) * cos(lat1/57.3) 

Источник: http://www.meridianworlddata.com/Distance-Calculation.asp


Я провел кучу тестов со случайно создаваемыми наборами данных.

  • Разница в точности для 3 алгоритмов минимальна , особенно на малых расстояниях
  • Самый медленный алгоритм – это, конечно, тот, который имеет триггерные функции (тот, который на ваш вопрос). Он в 4 раза медленнее, чем два других.

Определенно не стоит. Просто идите с приближением.
Код находится здесь: http://pastebin.org/424186


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

 SELECT columns FROM table WHERE DISTANCE(col_x, col_y, target_x, target_y) < 25 

Возможно, вы захотите взглянуть на это решение – несколько обходное решение для brilliat.

Вы можете сделать это легко в два этапа:

  • Найдите все местоположения в пределах 25 миль в каждом направлении точки. Это будет выглядеть так: WHERE lat BETWEEN $lat1 AND $lat2 AND lng BETWEEN $lng1 AND $lng2

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

Для первой части, вот какой-то код, который я укладываю (не помню источник):

 $lat_range = $radius / ((6076 / 5280) * 60); $lng_range = $radius / (((cos(($city['lat'] * 3.141592653589 / 180)) * 6076) / 5280) * 60); 

В основном просто используйте ($lat - $lat_range, $lat + $lat_range) и ($lng - $lng_range, $lng + $lng_range) Радиус находится в милях.

Очевидно, вы можете немного почистить математику.

Редактирование: я забыл упомянуть, что вам нужно немного подкорректировать его, если вам нужно поддерживать местоположения вблизи экватора, международную линию дат и т. Д. Очевидно, что для Северной Америки все было бы хорошо.