Хей я хочу найти расстояние (в милях) между двумя точками, используя lat и длинные значения, и проверить, находятся ли они в радиусе 10 миль друг от друга.
Когда пользователь входит в систему, их значения lat / long сохраняются в сеансе
$_SESSION['lat'] $_SESSION['long']
У меня есть 2 функции
Это работает на расстоянии в милях и возвращает округленное значение
function distance($lat1, $lng1, $lat2, $lng2){ $pi80 = M_PI / 180; $lat1 *= $pi80; $lng1 *= $pi80; $lat2 *= $pi80; $lng2 *= $pi80; $r = 6372.797; // mean radius of Earth in km $dlat = $lat2 - $lat1; $dlng = $lng2 - $lng1; $a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2); $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); $km = $r * $c; return floor($km * 0.621371192); }
Этот возвращает bool, если расстояние между двумя наборами lat и long составляет менее 10.
function is_within_10_miles($lat1, $lng1, $lat2, $lng2){ $d = distance($lat1, $lng1, $lat2, $lng2); if( $d <= 10 ){ return True; }else{ return False; } }
Обе функции работают как ожидалось, если я даю 2 набора латов / длин, а расстояние между ними – 20 миль, функция is_within_10_miles () возвращает false.
Теперь у меня есть база данных «местоположения» (4 поля – идентификатор, имя, lat, long).
Я хочу найти все местоположения, находящиеся в радиусе 10 миль.
Есть идеи?
EDIT: я могу прокрутить ВСЕ и выполнить на них is_within_10_miles (), как это
$query = "SELECT * FROM `locations`"; $result = mysql_query($query); while($location = mysql_fetch_assoc($result)){ echo $location['name']." is "; echo distance($lat2, $lon2, $location['lat'], $location['lon']); echo " miles form your house, is it with a 10 mile radius? "; if( is_within_10_miles($lat2, $lon2, $location['lat'], $location['lon']) ){ echo "yeah"; }else{ echo "no"; } echo "<br>";
}
Образец результата будет
goodison park is 7 miles form your house, is it with a 10 mile radius? yeah
Мне нужно каким-то образом выполнить функцию is_within_10_miles в моем запросе.
EDIT EDIT
Эта легенда из http://www.zcentric.com/blog/2007/03/calculate_distance_in_mysql_wi.html придумала это …
SELECT ((ACOS(SIN($lat * PI() / 180) * SIN(lat * PI() / 180) + COS($lat * PI() / 180) * COS(lat * PI() / 180) * COS(($lon - lon) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS distance FROM members HAVING distance<='10' ORDER BY distance ASC
Это действительно работает. Проблема в том, что я хочу выбрать * rows, а не выбирать их по одному. Как мне это сделать?
Вам, вероятно, не нужно делать это в коде, вы, вероятно, можете сделать все это в БД. если вы используете пространственный индекс . Документация MySQL для пространственного индекса
EDIT, чтобы отразить ваше редактирование:
Я думаю, вам нужно что-то вроде этого:
SELECT *, ((ACOS(SIN($lat * PI() / 180) * SIN(lat * PI() / 180) + COS($lat * PI() / 180) * COS(lat * PI() / 180) * COS(($lon - lon) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS distance FROM locations HAVING distance<='10' ORDER BY distance ASC
VIA: http://www.zcentric.com/blog/2007/03/calculate_distance_in_mysql_wi.html :
Перед тем, как сделать запрос, вычислите максимальную и минимальную широту и долготу вашего десятимильного круга. Это даст вам четыре числа, поэтому первая часть вашего предложения where исключает любые строки, которые выходят за пределы приблизительной 10-мильной коробки.
Затем сложное реальное расстояние, где предложение проверяет только те, что находятся внутри квадрата, чтобы увидеть, находятся ли они внутри круга.
Ознакомьтесь с документами СУБД, чтобы узнать, будет ли применяться ленивая оценка, или если вам нужно будет
SELECT * FROM (SELECT * FROM table WHERE (simple rough box clause) ) WHERE (complex clause)
вместо обычного
SELECT * FROM table WHERE (simple clause) AND (complex clause)
Это должно указывать вам в правильном направлении – каламбур не предназначен.
Функция Mysql для нахождения расстояния между двумя местами с использованием lat / long
Иногда нам нужно узнать список мест, находящихся в определенном радиусе от центра, где координаты мест сохраняются в базе данных. Теперь у нас есть 2 решения для этого: либо пройдите по всем местам, чтобы найти расстояние от центральной точки, и сохраните места, расстояние которых меньше или равно радиусу, или сделайте функцию sql, чтобы найти расстояние до двух мест, и выберите места с расстоянием, меньшим или равным радиусу. Очевидно, второй вариант лучше первого. Поэтому я написал функцию Mysql, которая выполняет эту работу для вас. В моем случае координаты были сохранены в базе данных как строка формы «10.1357002, 49.9225563, 0». Это стандартный формат координат, который используется многими (например, карта Google). Первый элемент – долгота, вторая – широта, и мы можем игнорировать третий (всегда 0). Итак, вот функция Mysql, которая возвращает расстояние между двумя координатами в Miles.
DELIMITER $$ DROP FUNCTION IF EXISTS `GetDistance`$$ CREATE FUNCTION `GetDistance`(coordinate1 VARCHAR(120), coordinate2 VARCHAR(120)) RETURNS VARCHAR(120) BEGIN DECLARE pos_comma1, pos_comma2 INT; DECLARE lon1, lon2, lat1, lat2, distance DECIMAL(12,8); select locate(',', coordinate1) into pos_comma1; select locate(',', coordinate1, pos_comma1+1) into pos_comma2; select CAST(substring(coordinate1, 1, pos_comma1-1) as DECIMAL(12,8)) into lon1; select CAST(substring(coordinate1, pos_comma1+1, pos_comma2-pos_comma1-1) as DECIMAL(12,8)) into lat1; select locate(',', coordinate2) into pos_comma1; select locate(',', coordinate2, pos_comma1+1) into pos_comma2; select CAST(substring(coordinate2, 1, pos_comma1-1) as DECIMAL(12,8)) into lon2; select CAST(substring(coordinate2, pos_comma1+1, pos_comma2-pos_comma1-1) as DECIMAL(12,8)) into lat2; select ((ACOS(SIN(lat1 * PI() / 180) * SIN(lat2 * PI() / 180) + COS(lat1 * PI() / 180) * COS(lat2 * PI() / 180) * COS((lon1 - lon2) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) into distance; RETURN distance; END$$ DELIMITER ;
Пример использования:
Допустим, вам нужно узнать все почтовые индексы, которые находятся в радиусе 40 миль от места, имеющего координату «10.1357002, 49.9225563, 0». У вас есть таблица POSTCODES с идентификаторами полей, почтовым индексом, координатами. Итак, ваш sql должен выглядеть так:
select id, postcode from POSTCODES where GetDistance("10.1357002, 49.9225563, 0", coordinates) <= 40;
Я просто собираюсь оставить это здесь:
https://gist.github.com/899413
это пример того, как запросить в квадрате (BETWEEN) на целые числа и сократить результаты с помощью SQRT (), чтобы выход возвращал круглый радиус результатов. (он также возвращает расстояние в километр)
для этого вам нужно преобразовать все точки при вставке в километры, чтобы выложить их на плоскую карту. (см. функции php)
результат – невероятный быстрый поиск по целому числу – МНОГО быстрее, чем выполнение всех вычислений в запросе, как говорится в каждом отдельном ответе.
(Я построил это ровно 10 лет назад … похоже, что это все еще самое умное решение с mysql)
Происхождение точки широты и долготы
$orig_lat=23.04988655049843; $orig_lon= 72.51734018325806; $dist=10; // Radius; //Latitude = database field name; //Longitude = database field name; $query = SELECT *, 3956 * 2 * ASIN(SQRT( POWER(SIN(($orig_lat -abs(dest.Latitude)) * pi()/180 / 2),2) + COS($orig_lat * pi()/180 ) * COS( abs(dest.Latitude) * pi()/180) * POWER(SIN(($orig_lon - dest.Longitude) * pi()/180 / 2), 2) )) as distance FROM tbl_name dest having distance < $dist ORDER BY distance limit 10
Найдите все местоположение в радиусе 10 миль.
Работаю отлично!