php mysql сравнивает long и lat, возвращает менее 10 миль - PullRequest
6 голосов
/ 19 февраля 2010

Хей, я хочу найти расстояние (в милях) между двумя точками, используя значения широты и долготы, и проверить, находятся ли они в радиусе 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);
}

Эта функция возвращает значение типа 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 набора значений lat / long и расстояние между ними равноскажем, 20 миль, моя функция is_within_10_miles () возвращает false.

Теперь у меня есть база данных 'location' (4 поля - ID, name, lat, long).

Я хочунайти все местоположения, которые находятся в радиусе 10 миль.

Любые идеи?

РЕДАКТИРОВАТЬ: я могу перебрать ВСЕ и выполнить 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 в моем запросе.

РЕДАКТИРОВАТЬ, РЕДАКТИРОВАТЬ

Эта легенда из 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

Это на самом деле работает.Проблема в том, что я хочу выбрать * строки, а не выбирать их по одной.Как мне это сделать?

Ответы [ 5 ]

12 голосов
/ 19 февраля 2010

Вам, вероятно, не нужно делать это в коде, вы, вероятно, можете делать все это в БД. если вы используете пространственный индекс . Документация MySQL для пространственного индекса

РЕДАКТИРОВАТЬ, чтобы отразить ваши изменения:

Я думаю, вы хотите что-то вроде этого:

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:

1 голос
/ 19 февраля 2010

Перед вашим запросом рассчитайте максимальную и минимальную широту и долготу вашего десятимильного круга. Это даст вам четыре числа, поэтому в первой части предложения 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 голосов
/ 02 августа 2012

Я просто оставлю это здесь:

https://gist.github.com/899413

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

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

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

(я построил это ровно 10 лет назад ... кажется, что это все еще самое умное решение с mysql)

0 голосов
/ 29 декабря 2011

Начальная точка широты и долготы

$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 < 10 ORDER BY distance limit 10

Найти все локации в радиусе 10 миль.
Работает нормально!

0 голосов
/ 19 февраля 2010

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

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

Иногда нам нужно найти список мест, которыенаходятся в пределах определенного радиуса от центра места, где координаты мест сохраняются в базе данных.Теперь у нас есть 2 решения для этого - либо переберите все места, найдите расстояние от центральной точки и оставьте места, у которых расстояние меньше или равно радиусу, либо сделайте функцию sql, чтобы найти расстояние двух мест, и выберитеместа, имеющие расстояние, меньшее или равное радиусу.Очевидно, что второй вариант лучше, чем первый.Итак, я написал функцию Mysql, которая сделает всю работу за вас.В моем случае координаты были сохранены в базе данных в виде строки вида «10.1357002, 49.9225563, 0».Это стандартный формат координат, который используется многими (например, карта Google).Первый элемент - это долгота, второй - широта, а третий можно игнорировать (всегда 0).Итак, вот функция Mysql, которая возвращает расстояние между двумя координатами в милях.

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, имеющая поля id, почтовый индекс, координаты.Так что ваш sql должен выглядеть так:

  select id, postcode from POSTCODES where GetDistance("10.1357002, 49.9225563, 0", coordinates) <= 40;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...