PHP MySQL получает местоположение в радиусе пользователя от GPS

Например, у меня в моей базе данных автомобильные инциденты. Эти инциденты имеют широту и долготу. На мобильном телефоне с помощью GPS я получаю местоположение пользователя с его координатами. Пользователь может выбрать радиус, который он хочет знать, если вокруг него происходят инциденты. Итак, допустим, он хочет знать инциденты в 2 милях вокруг него.

Поэтому я отправляю с телефона на веб-службу широту, долготу и радиус пользователя, которые он выбрал. Мне нужно сделать SQL-запрос, чтобы получить инциденты в 2 мили вокруг пользователя.

У вас есть идеи, как это сделать?

    Расчет расстояния довольно дорогостоящим, как говорят другие. Возвращение огромных наборов данных также не очень хорошая идея – особенно учитывая, что PHP не так хорош в производительности.

    Я бы использовал эвристику, например, приближаясь к расстоянию с помощью простого сложения и вычитания.

    1 минута = 1,86 км = 1,15 мили

    Просто найдите db с инцидентами внутри этого диапазона (фактически, это квадрат, а не круг), а затем вы можете работать с теми, у кого есть PHP.


    EDIT : Вот альтернатива; приближение, что намного дешевле вычислительно:

    Ориентировочное расстояние в милях:

    sqrt(x * x + y * y) where x = 69.1 * (lat2 - lat1) and y = 53.0 * (lon2 - lon1) 

    Вы можете повысить точность этого приблизительного расчета расстояния, добавив косинусную математическую функцию:

    Улучшенное приблизительное расстояние в милях:

     sqrt(x * x + y * y) where x = 69.1 * (lat2 - lat1) and y = 69.1 * (lon2 - lon1) * cos(lat1/57.3) 

    Источник: http://www.meridianworlddata.com/Distance-Calculation.asp


    EDIT 2 : Я провел кучу тестов со случайно генерируемыми наборами данных.

    • Разница в точности для 3 алгоритмов минимальна, особенно на малых расстояниях
    • Самый медленный алгоритм (один со всей связью функций триггера) в 4 раза медленнее, чем два других.

    Определенно не стоит. Просто идите с приближением.

    Код находится здесь: http://pastebin.org/424186

     function distance($lat1,$lon1,$lat2,$lon2,$unit) { $theta=$lon1-$lon2; $dist=sin(deg2rad($lat1))*sin(deg2rad($lat2))+cos(deg2rad($lat1))*cos(deg2rad($lat2))*cos(deg2rad($theta)); $dist=acos($dist); $dist=rad2deg($dist); $miles=$dist*60*1.1515; $unit=strtoupper($unit); if ($unit=="K") { return ($miles*1.609344); } else if ($unit=="N") { return ($miles*0.8684); } else { return $miles; } } // end function $x_lat=center_of_serach; $x_lon=center_of_serach; $_distance=some_distance_in_miles; $query1 = "SELECT * FROM `location_table` WHERE somefield=somefilter"; $result=mysql_db_query($db_conn, $query1); $max_rows=mysql_num_rows($result); if ($max_rows>0) { while ( $data1=mysql_fetch_assoc($result) ) { if ( distance($x_lat,$x_lon,$data1['lat'],$data1['lng'],'m')<$_distance ) { //do stuff } } 

    Его быстрее получить все данные и запустить их через функцию, а не использовать запрос, если ваша база данных не слишком велика.

    Он работает и для Килоса и Морских миль. 😉

    Существует формула для вычисления расстояния между двумя координатами lat / lon. Остерегайтесь, хотя – это довольно дорогостоящий вычислительный процесс, поэтому, если у вас много инцидентов, вы захотите быть умными. Прежде всего, прочитайте о математике .

    Что касается PHP-кода, быстрый google включил эту ссылку , которая, похоже, работает.

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

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

    Я сделал быстрый поиск и включил это сообщение в блоге, которое дает хорошее объяснение и SQL для выбора записей в заданном радиусе.

    В комментариях он предлагает: «Для скорости на больших наборах данных вы, вероятно, захотите захватить квадратный блок вокруг точки начала сначала, добавив милю или около того к и из обоих лат / лон для начала, а затем используя вышеприведенное в качестве подзаголовка для работы из середины ", которая звучит для меня как способ пойти.

      SELECT 3963 * ACOS( SIN(RADIANS($pointAlat)) * SIN(RADIANS($pointAlat)) + COS(RADIANS($pointAlat)) * COS(RADIANS($pointBlat)) * COS(RADIANS($pointAlong) - RADIANS($pointBlong))) AS distance; 

    Кроме того, если вы ищете хорошее чтение / учебник по этому вопросу .. Проверьте здесь http://www.phpfreaks.com/forums/index.php/topic,208965.0.html