php mysql сравнить long и lat, вернуть менее 10 миль

Хей я хочу найти расстояние (в милях) между двумя точками, используя 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 &lt; $dist ORDER BY distance limit 10 

Найдите все местоположение в радиусе 10 миль.
Работаю отлично!