Restituire tutti i risultati entro un raggio di 30 km da un lat / long point specifico?


21

Ho una tabella con una colonna the_geomche contiene dati simili a:

0103000020E61000000100000005000000CE473AACFA071E40F27FB23340744740336FE841C6231E40873BED903F744740FC150A0ACE231E40D19E2684637647409C9B443D00081E409A9AF82664764740CE473AACFA071E40F27FB23340744740

Che quando si applica la funzione ST_AsEWKT(the_geom)restituisce:

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

Devo selezionare tutti i dati entro un raggio di 30 km da un punto lat / long specifico, ad esempio:

  • lat = 46.8167
  • lng = 6.9333

Tuttavia, ogni volta che ho provato a utilizzare ST_Distance(), ho sempre ricevuto valori inferiori a 1 e l'utilizzo ha ST_DWithin()sempre restituito true.

Risposte:


23

Controlla la seguente query per PostgreSQL per ottenere i dati a una certa distanza. Spero che sarà di aiuto.

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

1
È stato in grado di farlo funzionare con: SELECT * FROM myTable DOVE GeometryType (ST_Centroid (the_geom)) = 'POINT' E ST_Distance_Sphere (ST_Point (ST_X (ST_Centroid (the_geom)), ST_Y (ST_Centroid (the_geom)), (ST_MakePoint (6.933) , 46.8167))) <= 18 * 1609.34
dan2k3k4

Fantastico :)
Farhat Abbas,

2
Solo per chiunque si stia chiedendo, la cifra del 1609.34 è metri per miglio, che è l'unità base che utilizza Postgres. Quindi, per fare chilometri, ovviamente moltiplicare per 1000.
1mike12

2
Nota pedante: è esattamente 1609.344 (per definizione)
barrycarter il

6

Sembra che tu stia memorizzando la tua geometria in una colonna geometrica, non in una colonna geografica.
Va bene, ma la funzione ST_Distance restituirà le misure in unità di proiezione anziché sempre in metri. Nel tuo caso (4326), saranno gradi.
Anche l'utilizzo di un buffer con ST_Within non funzionerà, poiché anche ST_Buffer misurerà con gradi.

Puoi convertire i tuoi dati per usare la geografia anziché la geometria, oppure puoi convertire il tuo punto in una proiezione che utilizza metri, buffer, quindi riconvertire in 4326 per vedere cosa c'è dentro:

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

Ciò proietta il punto nel 3857 , che è una proiezione popolare con le mappe web. Quindi lo bufferizza di 30.000 metri, quindi lo ripropone a 4326 prima di passarlo a ST_Within.


Tranne che uno pseudo-mercatore non è affidabile per la distanza, quindi a meno che i dati non siano vicini all'equatore, i risultati saranno spenti, specialmente con una distanza di 30 km.
Vince l'

6

Nel mio mondo, usando un SRID personalizzato (per Google Maps) qualcosa del genere ha funzionato:

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

dove il tipo di locationuna geometria (punto, 3785), e longitude, latitudee radiussono galleggianti (ad esempio -100, 44, 30 per 100W / 44N / 30 "unità" - vedi sotto)

Vedi Qual è il modo migliore per trovare tutti gli oggetti nel raggio di un altro oggetto? nei documenti postgis:

La ST_DWithin(geometry, geometry, distance)funzione è un modo pratico per eseguire una ricerca di distanza indicizzata. Funziona creando un rettangolo di ricerca abbastanza grande da racchiudere il raggio della distanza, quindi eseguendo una ricerca della distanza esatta sul sottoinsieme indicizzato di risultati.

AGGIORNAMENTO: le unità non sono miglia per SRID 3785 ... sembrano essere radianti o gradi o qualcosa del genere. Ma la specifica per il mio SRID dice che le sue unità sono o metri o gradi ed è sicuramente nessuna di queste, almeno non senza alcuna conversione:

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


Qual è la differenza tra 3785 (nel tuo post) e 3857?
sintonizzato il

Sono proiezioni diverse. 3875 vs 3857 - Non so se uno è meglio di un altro
AlexChaffee,

1
"EPSG 3785 è stato deprecato a favore di EPSG 3857 altrimenti identico" - github.com/rgeo/rgeo/pull/61
Yarin

2

Penso che questo dovrebbe funzionare:

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

3
se lanci the_geom in geografia che dovrebbe funzionare. st_dwithin (geografia (the_geom), geografia (<Point, 4326>), 30000)
cavila,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.