php mysql выдерживают сравнение долго и lat, возвращают менее чем 10 миль

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

Теперь, у меня есть база данных 'местоположений' (4 поля - идентификатор, имя, lat, долго).

Я хочу найти все местоположения, которые являются в 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 "
";

}

Демонстрационный результат был бы

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

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

6
задан dotty 19 February 2010 в 15:56
поделиться

3 ответа

Вам, вероятно, не нужно делать это в коде, вы, вероятно, можете сделать все это в базе данных. если вы используете пространственный индекс . Документация 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 :

12
ответ дан 10 December 2019 в 00:37
поделиться

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

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

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

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

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

SELECT * FROM table WHERE (simple clause) AND (complex clause)
1
ответ дан 10 December 2019 в 00:37
поделиться

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

Функция 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;
-1
ответ дан 10 December 2019 в 00:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: