Alle Ergebnisse innerhalb eines Radius von 30 km um einen bestimmten Lat / Long-Punkt zurückgeben?


21

Ich habe eine Tabelle mit einer Spalte, the_geomdie folgende Daten enthält:

0103000020E61000000100000005000000CE473AACFA071E40F27FB23340744740336FE841C6231E40873BED903F744740FC150A0ACE231E40D19E2684637647409C9B443D00081E409A9AF82664764740CE473AACFA071E40F27FB23340744740

Was bei Anwendung der Funktion ST_AsEWKT(the_geom)zurückgibt:

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

Ich muss alle Daten auswählen, die sich in einem Umkreis von 30 km um einen bestimmten Lat / Long-Punkt befinden. Beispiel:

  • lat = 46,8167
  • lng = 6,9333

Wenn ich jedoch versuchte, zu verwenden ST_Distance(), erhielt ich immer Werte kleiner als 1 und gab ST_DWithin()immer true zurück.

Antworten:


23

Bitte überprüfen Sie die folgende Abfrage für PostgreSQL, um Daten innerhalb einer bestimmten Entfernung zu erhalten. Ich hoffe es wird helfen.

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

1
Konnte es zum Laufen bringen mit: SELECT * FROM myTable WHERE GeometryType (ST_Centroid (the_geom)) = 'POINT' UND ST_Distance_Sphere (ST_Point (ST_X (ST_Centroid (the_geom)), ST_Y (ST_Centroid (the_geom)), (ST_MakePoint (6.9 , 46.8167))) <= 18 * 1609,34
dan2k3k4

Das ist großartig :)
Farhat Abbas

2
Nur für alle anderen, die sich fragen, ist die Zahl 1609,34 Meter pro Meile. Dies ist die Basiseinheit, die Postgres verwendet. So Kilometer zu tun, offensichtlich mehrfach mit 1000
1mike12

2
Pedantischer Hinweis: Es ist genau
1609.344

6

Es hört sich so an, als würden Sie Ihre Geometrie in einer Geometriespalte speichern, nicht in einer Geografiespalte.
Das ist in Ordnung, aber die Funktion ST_Distance gibt Messungen in Projektionseinheiten anstelle von immer Metern zurück. In Ihrem Fall (4326) sind das Grad.
Nur einen Puffer mit ST_Within zu verwenden, funktioniert auch nicht, da der ST_Buffer auch mit Grad gemessen wird.

Sie können Ihre Daten entweder so konvertieren, dass Geografie anstelle von Geometrie verwendet wird, oder Sie können Ihren Punkt in eine Projektion konvertieren, die Meter und Puffer verwendet. Anschließend können Sie in 4326 zurückkonvertieren, um zu sehen, was sich darin befindet:

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

Das projiziert den Punkt in 3857 , eine Projektion, die bei Webkarten beliebt ist. Dann puffert es es um 30.000 Meter und projiziert es dann auf 4326 zurück, bevor es an ST_Within übergeben wird.


Außer ein Pseudo-Mercator ist für die Entfernung unzuverlässig. Wenn sich die Daten nicht in der Nähe des Äquators befinden, sind die Ergebnisse nicht korrekt, insbesondere bei einer Entfernung von 30 km.
Vince

6

In meiner Welt funktionierte mit einer benutzerdefinierten SRID (für Google Maps) Folgendes:

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

wobei der Typ locationeine Geometrie ist (Punkt, 3785), und longitude, latitudeund radiusSchwimmer sind (zB -100, 44, 30 für 100W / 44N / 30 "Einheiten" - siehe unten)

Siehe Was ist der beste Weg, um alle Objekte innerhalb eines Radius eines anderen Objekts zu finden? In den Postgis-Dokumenten:

Die ST_DWithin(geometry, geometry, distance)Funktion ist eine praktische Möglichkeit, eine indizierte Entfernungssuche durchzuführen. Dazu wird ein Suchrechteck erstellt, das groß genug ist, um den Entfernungsradius einzuschließen. Anschließend wird eine exakte Entfernungssuche für die indizierte Teilmenge der Ergebnisse durchgeführt.

UPDATE: Einheiten sind keine Meilen für SRID 3785 ... sie scheinen entweder Bogenmaß oder Grad oder so ähnlich zu sein. Die Spezifikation für meine SRID besagt jedoch, dass die Einheiten entweder Meter oder Grad sind und definitiv keine von diesen Einheiten, zumindest nicht ohne eine gewisse Umrechnung:

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


Was ist der Unterschied zwischen 3785 (in Ihrem Beitrag) und 3857?
abgestimmt

Das sind unterschiedliche Projektionen. 3875 vs 3857 - Ich weiß nicht, ob einer besser ist als der andere
AlexChaffee

1
"EPSG 3785 wurde zugunsten des ansonsten identischen EPSG 3857 abgelehnt" - github.com/rgeo/rgeo/pull/61
Yarin

2

Ich denke, dass dies funktionieren sollte:

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

3
Wenn Sie the_geom auf Geografie umwandeln, sollte dies funktionieren. st_dwithin (geography (the_geom), geography (<Point, 4326>), 30000)
cavila
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.