Выбор точек из базы данных карты по радиусу

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

Я использую этот запрос:

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)