Повернути всі результати в радіусі 30 км від певної ширини / довгої точки?


21

У мене є таблиця зі стовпцем, the_geomяка містить дані, схожі на:

0103000020E61000000100000005000000CE473AACFA071E40F27FB23340744740336FE841C6231E40873BED903F744740FC150A0ACE231E40D19E2684637647409C9B443D00081E409A9AF82664764740CE473AACFA071E40F27FB23340744740

Який при застосуванні функції ST_AsEWKT(the_geom)повертає:

SRID=4326;POLYGON((7.5077921782085 46.9082092877942,7.53493597966353 46.9081898840296,7.53496566473541 46.9249119938446,7.50781341296434 46.9249314035307,7.5077921782085 46.9082092877942))

Мені потрібно вибрати всі дані, які знаходяться в радіусі 30 км від певної ширини / довгої точки, наприклад:

  • лат. = 46,8167
  • lng = 6,9333

Однак, коли я намагався використовувати ST_Distance(), я завжди отримував значення менше 1, і ST_DWithin()завжди використовував істинну версію.

Відповіді:


23

Будь ласка, перегляньте наступний запит для PostgreSQL, щоб отримати дані на певній відстані. Сподіваюся, це допоможе.

SELECT *
FROM your_table
WHERE ST_Distance_Sphere(the_geom, ST_MakePoint(your_lon,your_lat)) <= radius_mi * 1609.34

1
Вмів працювати з ним: SELECT * FROM myTable WHERE GeometryType (ST_Centroid (the_geom)) = 'POINT' AND ST_Distance_Sphere (ST_Point (ST_X (ST_Centroid (the_geom)), ST_Y (ST_Centroid (the_geom)))), (ST_Ma9 )33) , 46.8167))) <= 18 * 1609.34
dan2k3k4

Це чудово :)
Фархат Аббас

2
Тільки для всіх, хто цікавиться, цифра 1609,34 - це метри на милю, яку використовують базові одиниці. Так що робити кілометри, очевидно, помножити на 1000.
1міке12

2
Педантична нота: саме 1609.344 (за визначенням)
barrycarter

6

Це здається, що ви зберігаєте свою геометрію в стовпці з геометрією, а не в стовпці з географією.
Це добре, але функція ST_Distance повертає вимірювання в проекційних одиницях замість завжди лічильників. У вашому випадку (4326), це будуть ступені.
Просто використання буфера з ST_Within також не буде працювати, оскільки ST_Buffer буде вимірюватися і градусами.

Ви можете або перетворити свої дані для використання географії замість геометрії, або ви можете перетворити свою точку в якусь проекцію, яка використовує метри, буфер, а потім перетворити назад в 4326, щоб побачити, що знаходиться в ній:

SELECT
    *
FROM <your data>
WHERE ST_Within(the_geom, 
                ST_Transform(ST_Buffer(ST_Transform(ST_SetSRID(ST_MakePoint(6.9333, 46.8167), 4326), 3857), 30000), 4326)) = 1

Це проектує точку в 3857 , що є проекцією, популярною у веб-картах. Потім він зберігає його на 30 000 метрів, після чого відновлює його назад до 4326 перед тим, як передавати його ST_Within.


За винятком того, що псевдо-Меркатор недостовірний для відстані, тому, якщо дані не будуть близькі до екватора, результати будуть вимкнені, особливо з відстані 30 км.
Вінс

6

У моєму світі за допомогою спеціального SRID (для Карт Google) щось подібне спрацювало:

SELECT * FROM addresses WHERE ST_DWithin(location, ST_SetSRID(ST_MakePoint(longitude, latitude), 3785), radius);

де тип location- це геометрія (Point, 3785), і longitude, latitudeі radiusє поплавцями (наприклад, -100, 44, 30 для 100W / 44N / 30 "одиниць" - див. нижче)

Дивіться, який найкращий спосіб знайти усі об’єкти в радіусі іншого об’єкта? у документах Postgis:

ST_DWithin(geometry, geometry, distance)Функція являє собою зручний спосіб виконання індексованого пошуку відстані. Він працює, створюючи прямокутник пошуку, достатньо великий, щоб укласти радіус відстані, а потім виконувати точний пошук відстані в індексованому підмножині результатів.

ОНОВЛЕННЯ: одиниці не мають миль для SRID 3785 ... вони, здається, або радіани, або градуси, або щось подібне. Але специфікація для мого SRID говорить, що його одиниці є або метрами, або градусами, і це точно не те, принаймні, не без певного перетворення:

alex=# select * from spatial_ref_sys where srid=3785; srid | auth_name | auth_srid | srtext | proj4text
3785 | EPSG | 3785 | PROJCS["Popular Visualisation CRS / Mercator (deprecated)",GEOGCS["Popular Visualisation CRS",DATUM["Popular_Visualisation_Datum",SPHEROID["Popular Visualisation Sphere",6378137,0,AUTHORITY["EPSG","7059"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6055"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4055"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"],AUTHORITY["EPSG","3785"],AXIS["X",EAST],AXIS["Y",NORTH]] | +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs


Яка різниця між 3785 (у твоєму дописі) та 3857?
настроєно

Вони різні прогнози. 3875 проти 3857 - Я не знаю, чи один кращий за іншого
AlexChaffee

1
«EPSG 3785 застаріли на користь іншого ідентичного EPSG 3857» - github.com/rgeo/rgeo/pull/61
Ярина

2

Я думаю, що це має працювати:

SELECT gid FROM table 
WHERE ST_DWithin(the_geom, ST_SetSRID(ST_Point(6.9333, 46.8167), 4326), 30000)

3
якщо ви киньте the_geom на географію, яка повинна працювати. st_dwithin (географія (the_geom), географія (<Точка, 4326>), 30000)
cavila
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.