2010-02-19 2 views
6

Hay Я хочу найти расстояние (в милях) между двумя точками, используя lat и длинные значения, и проверить, находятся ли они в радиусе 10 миль друг от друга.php mysql сравнить long и lat, вернуть их менее 10 миль

Когда пользователь входит в систему, их лат/длинные значения сохраняются в сеансе

$_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); 
} 

Это один возвращает логическое значение, если расстояние между 2 комплектами широты и Лонга под 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, а не выбирать их по одному. Как мне это сделать?

+0

Смотрите мой выбор. Это функция MySQL, которая будет делать то, что вам нужно. –

ответ

12

Возможно, вам не обязательно это делать в коде, возможно, вы можете сделать все это в БД. если вы используете spatial index. MySQL docuemtnation for spatial index

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:

+0

Я обновил вопрос, надеюсь, это будет яснее. – dotty

+0

Да, это работает, но как выбрать ВСЕ (*) строки? – dotty

+0

srry. отредактирован снова. Это просто SELECT *, ......... – easement

-1

Это должно указывать на правильное направление - никакая каламбур не предназначена.

функции Mysql найти расстояние между двумя пунктами, используя широту/долготу

Иногда нам нужно выяснить список мест, которые находятся в пределах определенного радиуса от центра места, где координаты места сохраняется в базе данных. Теперь у нас есть 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; 
+0

Я обновил вопрос, надеюсь, это будет яснее. – dotty

+0

Это будет компьютер для каждой записи в поисковом наборе. Он вернет правильный результат, но он будет супер-неэффективным, если набор поиска станет большим. – VoidPointer

+0

Он попросил SQL-решение. –

1

Перед запросом, рассчитать максимальную и минимальную широту и долготу вашего десятимильного круга. Это даст вам четыре числа, поэтому первая часть вашего предложения where исключает любые строки, которые выходят за пределы приблизительной 10-мильной коробки.

Тогда сложное реальное расстояние, где предложение проверяет только те, что находятся внутри квадрата, чтобы увидеть, находятся ли они внутри круга.

Читайте документацию СУБД, чтобы увидеть, будет ли применять ленивые вычисления, или если вам нужно будет организовать его как

SELECT * 
FROM (SELECT * 
     FROM table 
     WHERE (simple rough box clause) 
    ) 
WHERE (complex clause) 

вместо обычного

SELECT * FROM table WHERE (simple clause) AND (complex clause) 
+0

Отлично, -1 без комментария в ответе на 2,5 года. – Emyr

+0

Имейте +1, потому что это не плохо первый разрез. :-) –

-1

Origin точки широты и долготы

$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 миль.
Работаю отлично!

-1

Я просто хочу, чтобы оставить это здесь:

https://gist.github.com/899413

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

Для этого вам нужно преобразовать все точки при вставке в километры, чтобы выложить их на плоскую карту. (см. функции php)

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

(я построил это ровно 10 лет назад ... Кажется, что это все-таки умный решение с MySQL)