Renvoyer tous les résultats dans un rayon de 30 km d'un point lat / long spécifique?

21

J'ai un tableau avec une colonne the_geomqui contient des données similaires à:

0103000020E61000000100000005000000CE473AACFA071E40F27FB23340744740336FE841C6231E40873BED903F744740FC150A0ACE231E40D19E2684637647409C9B443D00081E409A9AF82664764740CE473AACFA071E40F27FB23340744740

Qui lors de l'application de la fonction ST_AsEWKT(the_geom)renvoie:

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

J'ai besoin de sélectionner toutes les données qui se trouvent dans un rayon de 30 km d'un point lat / long spécifique, par exemple:

  • lat = 46.8167
  • lng = 6.9333

Cependant, chaque fois que j'essayais d'utiliser ST_Distance(), je recevais toujours des valeurs inférieures à 1, et l'utilisation ST_DWithin()renvoyait toujours true.

dan2k3k4
la source

Réponses:

23

Veuillez consulter la requête suivante pour PostgreSQL pour obtenir des données à une certaine distance. J'espère que cela aidera.

SELECT *
FROM your_table
WHERE ST_Distance_Sphere(the_geom, ST_MakePoint(your_lon,your_lat)) <= radius_mi * 1609.34
Farhat Abbas
la source
1
A pu le faire fonctionner avec: 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_MakePoint (6.9333 , 46.8167))) <= 18 *
1609.34
C'est super :)
Farhat Abbas
2
Juste pour quiconque se pose la question, le chiffre 1609,34 est le mètre par mile, qui est l'unité de base utilisée par postgres. Donc pour faire des kilomètres, multipliez évidemment par 1000.
1mike12
2
Note pédantique: c'est 1609.344 exactement (par définition)
barrycarter
6

Il semble que vous stockiez votre géométrie dans une colonne de géométrie, pas une colonne de géographie.
C'est bien, mais la fonction ST_Distance renverra des mesures en unités de projection au lieu de toujours mètres. Dans votre cas (4326), ce seront des degrés.
L'utilisation d'un tampon avec ST_Within ne fonctionnera pas non plus, car le ST_Buffer sera également mesuré en degrés.

Vous pouvez convertir vos données pour utiliser la géographie au lieu de la géométrie, ou vous pouvez convertir votre point en une projection qui utilise des mètres, un tampon, puis reconvertir en 4326 pour voir ce qu'il contient:

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

Cela projette le point en 3857 , qui est une projection populaire avec les cartes Web. Il le tamponne ensuite de 30 000 mètres puis le reprojete au 4326 avant de le passer à ST_Within.

Génie du mal
la source
Sauf qu'un pseudo-Mercator n'est pas fiable pour la distance, donc à moins que les données ne soient proches de l'équateur, les résultats seront erronés, surtout avec une distance de 30 km.
Vince
6

Dans mon monde, utiliser un SRID personnalisé (pour Google Maps) quelque chose comme ça a fonctionné:

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

où le type de locationest une géométrie (Point, 3785), et longitude, latitudeet radiussont des flotteurs (par exemple -100, 44, 30 pour des "unités" 100W / 44N / 30 - voir ci-dessous)

Voir Quelle est la meilleure façon de trouver tous les objets dans un rayon d'un autre objet? dans les documents postgis:

La ST_DWithin(geometry, geometry, distance)fonction est un moyen pratique d'effectuer une recherche de distance indexée. Il fonctionne en créant un rectangle de recherche suffisamment grand pour englober le rayon de distance, puis en effectuant une recherche de distance exacte sur le sous-ensemble de résultats indexé.

MISE À JOUR: les unités ne sont pas des miles pour SRID 3785 ... elles semblent être des radians ou des degrés ou quelque chose comme ça. Mais la spécification de mon SRID indique que ses unités sont en mètres ou en degrés et ce n'est certainement ni l'un ni l'autre, du moins pas sans une certaine conversion:

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
la source
Quelle est la différence entre 3785 (dans votre message) et 3857?
réglé le
Ce sont des projections différentes. 3875 vs 3857 - Je ne sais pas si l'un est meilleur qu'un autre
AlexChaffee
1
"EPSG 3785 a été déprécié au profit de l'EPSG 3857 par ailleurs identique" - github.com/rgeo/rgeo/pull/61
Yarin
2

Je pense que cela devrait fonctionner:

SELECT gid FROM table 
WHERE ST_DWithin(the_geom, ST_SetSRID(ST_Point(6.9333, 46.8167), 4326), 30000)
Francisco Puga
la source
3
si vous lancez the_geom dans une géographie qui devrait fonctionner. st_dwithin (géographie (the_geom), géographie (<Point, 4326>), 30000)
cavila