Выбор точек из базы данных карты по радиусу
У меня есть база данных с широтой/долготой точек. Если я хочу выбрать все точки в определенном диапазоне с центром в определенной точке, он отлично работает, но если в этом центре есть какая-либо точка, он не будет выбран!
Я использую этот запрос:
SELECT *, ( 6371 * acos( cos( radians(-27.5796498) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(-48.543221) ) + sin( radians(-27.5796498) ) * sin( radians( latitude ) ) ) ) AS distance FROM map HAVING distancia <= 2
В приведенном выше случае радиус равен "2", а центр карты находится в [-27.5796498, -27.5796498]. Этот запрос работает очень хорошо, но если какой-то пункт находится в этом очень точном центре, он не будет выбран. Почему?
EDIT: я обнаружил, что приведенная выше формула возвращает хорошее значение для всех точек. НО до точки, расположенной в центре MYSQL, возвращает значение NULL в столбец "расстояние"! Как профессионалы справляются с этим видом или проблемой использования SQL для выбора точек в пределах диапазона, включая центральную точку?
EDIT2: я мог бы создать еще один запрос, чтобы выбрать все точки, расположенные в самом центре радиуса, но это неэффективно, может быть, какой-то математический волшебник может придумать лучшую формулу.
Ответы
Ответ 1
Иногда параметр ACOS()
может быть чуть больше 1 - немного за пределами области этой функции - когда расстояния малы. Там есть лучшая формула расстояния, благодаря Винценти. Он использует функцию ATAN2(y,x)
, а не функцию ACOS()
и, следовательно, более численно стабилен.
Это он.
DEGREES(
ATAN2(
SQRT(
POW(COS(RADIANS(lat2))*SIN(RADIANS(lon2-lon1)),2) +
POW(COS(RADIANS(lat1))*SIN(RADIANS(lat2)) -
(SIN(RADIANS(lat1))*COS(RADIANS(lat2)) *
COS(RADIANS(lon2-lon1))) ,2)),
SIN(RADIANS(lat1))*SIN(RADIANS(lat2)) +
COS(RADIANS(lat1))*COS(RADIANS(lat2))*COS(RADIANS(lon2-lon1))))
Здесь более полная запись, включая определение хранимой функции для MySQL, здесь.
Другим решением является использование ISNULL(ACOS(formula), 0.0)