Как точно хранить данные геолокации, фильтровать их в радиусе и рассчитывать расстояние? - PullRequest
0 голосов
/ 14 января 2019

Я пишу новые места с:

ST_SetSrid(ST_MakePoint(:longitude, :latitude), 4326)

Они сохраняются под "profile".location:

SRID=4326;POINT(-75.1234 35.1234)

Я пытаюсь отфильтровать профили с точностью до :radius в метрах, где :ownLocation - это строка местоположения, состоящая из набора чисел:

ST_DWithin("profile".location, :ownLocation::geometry, :radius)

Тогда, когда я верну результаты и вычислю их расстояние с помощью: ST_Distance( ST_Transform("profile".location::geometry, 3857::int), ST_Transform(:ownLocation::geometry, 3857::int) ) as distance

и переведите расстояние в метры в мили, мои результаты немного смещены. Допустим, я установил максимальный радиус в пределах 10 миль - расстояние, которое я получаю, кажется где-то от 0 до 23 миль (ожидалось бы, что 0-10 миль).

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


Обновление после решения: хранить как 4326, отображать расстояние как 3857

хранить как 4326:

ST_SetSrid(ST_MakePoint(:longitude, :latitude), 4326)

фильтр с использованием типа geography, поэтому он может принимать радиус фильтра в метрах, которые будут проходить пользователи:

ST_DWithin("profile".location::geography, :ownLocation::geography, :radiusInMeters)

отображать расстояние от 4326 до 3857 метров с коррекцией (https://postgis.net/docs/ST_Distance.html):

ST_Distance(
ST_Transform("profile".location::geometry, 3857),
ST_Transform(:ownLocation::geometry, 3857)
) * cosd(42.3521) as distance

Ответы [ 2 ]

0 голосов
/ 14 января 2019

3857 не подходит для вычисления расстояний, так как оно вносит важные искажения при удалении от экватора.

Вместо этого вы можете использовать ST_Distance, используя тип данных geography:

ST_Distance("profile".location::geography,:ownLocation::geography) as distance

Относительно st_dwithin используется проекционная единица, а не градусы, а градусы. Вы также можете использовать тип данных geography здесь.

0 голосов
/ 14 января 2019

Единица EPSG 4326 - градусы, тогда как единица EPSG 3857 - метры.

ST_DWithin ("profile" .location,: ownLocation :: geometry,: radius) будет принимать градусы в виде радиуса, а не метров или миль.

Преобразовать "профиль" .location и: ownLocation :: geometry до 3857 должно работать;

...