¿Devuelve todos los resultados dentro de un radio de 30 km de un punto lat / long específico?

21

Tengo una tabla con una columna the_geomque contiene datos similares a:

0103000020E61000000100000005000000CE473AACFA071E40F27FB23340744740336FE841C6231E40873BED903F744740FC150A0ACE231E40D19E2684637647409C9B443D00081E409A9AF82664764740CE473AACFA071E40F27FB23340744740

Que al aplicar la función ST_AsEWKT(the_geom)devuelve:

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

Necesito seleccionar todos los datos que están dentro de un radio de 30 km de un punto lat / long específico, por ejemplo:

  • lat = 46.8167
  • lng = 6.9333

Sin embargo, cada vez que intenté usar ST_Distance(), siempre recibí valores inferiores a 1, y el uso ST_DWithin()siempre devolvió verdadero.

dan2k3k4
fuente

Respuestas:

23

Consulte la siguiente consulta para PostgreSQL para obtener datos dentro de cierta distancia. Espero que sea de ayuda.

SELECT *
FROM your_table
WHERE ST_Distance_Sphere(the_geom, ST_MakePoint(your_lon,your_lat)) <= radius_mi * 1609.34
Farhat Abbas
fuente
1
Pude hacer que funcionara con: 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.93MakePoint (ST_33 MakePoint , 46.8167))) <= 18 * 1609.34
dan2k3k4
Eso es genial :)
Farhat Abbas
2
Solo para cualquiera que se pregunte, la cifra de 1609.34 es metros por milla, que es la unidad base que postgres está usando. Entonces, para hacer kilómetros, obviamente multiplique por 1000.
1mike12
2
Nota pedante: es 1609.344 exactamente (por definición)
barrycarter
6

Parece que está almacenando su geometría en una columna de geometría, no en una columna de geografía.
Eso está bien, pero la función ST_Distance devolverá mediciones en unidades de proyección en lugar de siempre medidores. En su caso (4326), eso serán grados.
Simplemente usar un búfer con ST_Within tampoco funcionará, ya que el ST_Buffer también se medirá con grados.

Puede convertir sus datos para usar la geografía en lugar de la geometría, o puede convertir su punto en alguna proyección que use medidores, búfer, y luego convertir de nuevo a 4326 para ver qué hay 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

Eso proyecta el punto en 3857 , que es una proyección popular entre los mapas web. Luego lo amortigua en 30,000 metros y luego lo vuelve a proyectar a 4326 antes de pasarlo a ST_Within.

Genio malvado
fuente
Excepto que un pseudo-Mercator no es confiable para la distancia, por lo tanto, a menos que los datos estén cerca del ecuador, los resultados estarán apagados, especialmente con una distancia de 30 km.
Vince
6

En mi mundo, usando un SRID personalizado (para Google Maps) algo como esto funcionó:

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

donde el tipo de locationes una geometría (Point, 3785), y longitude, latitudey radiusson flotadores (por ejemplo, -100, 44, 30 para 100W / 44N / 30 "unidades" - ver más abajo)

Vea ¿Cuál es la mejor manera de encontrar todos los objetos dentro de un radio de otro objeto? en los documentos postgis:

La ST_DWithin(geometry, geometry, distance)función es una forma práctica de realizar una búsqueda de distancia indexada. Funciona creando un rectángulo de búsqueda lo suficientemente grande como para encerrar el radio de distancia, luego realiza una búsqueda de distancia exacta en el subconjunto indexado de resultados.

ACTUALIZACIÓN: las unidades no son millas para SRID 3785 ... parecen ser radianes o grados o algo así. Pero la especificación para mi SRID dice que sus unidades son metros o grados y definitivamente no es ninguno de esos, al menos no sin alguna conversión:

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
fuente
¿Cuál es la diferencia entre 3785 (en tu publicación) y 3857?
sintonizado el
Son proyecciones diferentes. 3875 vs 3857 - No sé si uno es mejor que otro
AlexChaffee
1
"EPSG 3785 ha quedado en desuso a favor del EPSG 3857, que de otro modo sería idéntico" - github.com/rgeo/rgeo/pull/61
Yarin
2

Creo que esto debería funcionar:

SELECT gid FROM table 
WHERE ST_DWithin(the_geom, ST_SetSRID(ST_Point(6.9333, 46.8167), 4326), 30000)
Francisco Puga
fuente
3
si lanzas the_geom a la geografía eso debería funcionar. st_dwithin (geography (the_geom), geography (<Point, 4326>), 30000)
cavila