Kembalikan semua hasil dalam radius 30 km dari titik lat / panjang tertentu?

21

Saya memiliki tabel dengan kolom the_geomyang berisi data yang mirip dengan:

0103000020E61000000100000005000000CE473AACFA071E40F27FB23340744740336FE841C6231E40873BED903F744740FC150A0ACE231E40D19E2684637647409C9B443D00081E409A9AF82664764740CE473AACFA071E40F27FB23340744740

Yang ketika menerapkan fungsi ST_AsEWKT(the_geom)kembali:

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

Saya perlu memilih semua data yang berada dalam radius 30 km dari titik lat / panjang tertentu, misalnya:

  • lat = 46.8167
  • lng = 6.9333

Namun setiap kali saya mencoba menggunakan ST_Distance(), saya selalu menerima nilai kurang dari 1, dan menggunakan ST_DWithin()selalu mengembalikan nilai true.

dan2k3k4
sumber

Jawaban:

23

Silakan periksa permintaan berikut untuk PostgreSQL untuk mendapatkan data dalam jarak tertentu. Saya harap ini akan membantu.

SELECT *
FROM your_table
WHERE ST_Distance_Sphere(the_geom, ST_MakePoint(your_lon,your_lat)) <= radius_mi * 1609.34
Farhat Abbas
sumber
1
Mampu membuatnya bekerja dengan: SELECT * FROM myTable WHERE GeometryType (ST_Centroid (the_geom)) = 'POINT' DAN ST_Distance_Sphere (ST_X (ST_Centroid (the_geom)), ST_Y (ST_Centroid (the_geom)), (STM) () , 46.8167))) <= 18 * 1609.34
dan2k3k4
Itu luar biasa :)
Farhat Abbas
2
Hanya untuk orang lain yang bertanya-tanya, angka 1609,34 adalah meter per mil, yang merupakan unit dasar yang digunakan postgres. Jadi untuk melakukan kilometer, kalikan dengan 1000.
1mike12
2
Catatan Pedantic: tepatnya 1609.344 (menurut definisi)
barrycarter
6

Sepertinya Anda menyimpan geometri dalam kolom geometri, bukan kolom geografi.
Itu bagus, tetapi fungsi ST_Distance akan mengembalikan pengukuran dalam unit proyeksi bukannya selalu meter. Dalam kasus Anda (4326), itu akan menjadi derajat.
Hanya menggunakan buffer dengan ST_Within tidak akan berfungsi, karena ST_Buffer akan diukur dengan derajat juga.

Anda dapat mengonversi data Anda menggunakan geografi alih-alih geometri, atau Anda dapat mengubah titik Anda menjadi beberapa proyeksi yang menggunakan meter, buffer, lalu mengonversi kembali ke 4326 untuk melihat apa yang ada di dalamnya:

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

Itu memproyeksikan titik ke 3857 , yang merupakan proyeksi populer dengan peta web. Kemudian buffer 30.000 meter kemudian memproyeksikan kembali ke 4326 sebelum meneruskannya ke ST_Within.

Genius Jahat
sumber
Kecuali pseudo-Mercator tidak dapat diandalkan untuk jarak, jadi kecuali jika data dekat dengan khatulistiwa, hasilnya akan mati, terutama dengan jarak 30 km.
Vince
6

Di dunia saya, menggunakan SRID khusus (untuk Google Maps) sesuatu seperti ini berfungsi:

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

di mana jenis locationgeometri (Titik, 3785), dan longitude,, latitudedan radiusmengapung (misalnya -100, 44, 30 untuk "unit" 100W / 44N / 30 - lihat di bawah)

Lihat Apa cara terbaik untuk menemukan semua objek dalam radius objek lain? dalam postgis docs:

The ST_DWithin(geometry, geometry, distance)Fungsi merupakan cara mudah melakukan pencarian jarak diindeks. Ia bekerja dengan membuat kotak pencarian yang cukup besar untuk melingkupi radius jarak, kemudian melakukan pencarian jarak yang tepat pada subset hasil yang diindeks.

UPDATE: unit bukan mil untuk SRID 3785 ... mereka tampaknya radian atau derajat atau sesuatu seperti itu. Tetapi spesifikasi untuk SRID saya mengatakan unitnya baik meter atau derajat dan itu jelas bukan keduanya, setidaknya tidak tanpa konversi:

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

AlexChaffee
sumber
Apa perbedaan antara 3785 (di pos Anda) dan 3857?
disetel
Itu adalah proyeksi yang berbeda. 3875 vs 3857 - Saya tidak tahu apakah ada yang lebih baik dari yang lain
AlexChaffee
1
"EPSG 3785 telah ditinggalkan demi EPSG 3857 yang identik" - github.com/rgeo/rgeo/pull/61
Yarin
2

Saya pikir ini harus bekerja:

SELECT gid FROM table 
WHERE ST_DWithin(the_geom, ST_SetSRID(ST_Point(6.9333, 46.8167), 4326), 30000)
Francisco Puga
sumber
3
jika Anda melemparkan the_geom ke geografi yang seharusnya berfungsi. st_dwithin (geografi (the_geom), geografi (<Point, 4326>), 30000)
cavila