Я пишу сайт, который в основном ищет места в радиусе 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
Я провел кучу тестов со случайно создаваемыми наборами данных.
Определенно не стоит. Просто идите с приближением.
Код находится здесь: 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)
Радиус находится в милях.
Очевидно, вы можете немного почистить математику.
Редактирование: я забыл упомянуть, что вам нужно немного подкорректировать его, если вам нужно поддерживать местоположения вблизи экватора, международную линию дат и т. Д. Очевидно, что для Северной Америки все было бы хорошо.