11. Relaciones Espaciales

Hasta ahora solo hemos usado funciones espaciales que miden (ST_Area, ST_Length), serializan (ST_GeomFromText) o deserializan (ST_AsGML) geometrías. Lo que estas funciones tienen en común es que solo trabajan con una geometría a la vez.

Las bases de datos espaciales son potentes porque no solo almacenan geometrías, también tienen la capacidad de comparar relaciones entre geometrías.

Preguntas como «¿Cuáles son los parqueaderos de bicicletas más cercanos a un parque?» o «¿Dónde están las intersecciones de líneas de metro y calles?» solo pueden responderse comparando geometrías que representan los parqueaderos de bicicletas, las calles y las líneas de metro.

El estándar OGC define el siguiente conjunto de métodos para comparar geometrías.

11.1. ST_Equals

ST_Equals(geometry A, geometry B) prueba la igualdad espacial de dos geometrías.

_images/st_equals.png

ST_Equals devuelve TRUE si dos geometrías del mismo tipo tienen valores de coordenadas x,y idénticos, es decir, si la segunda forma es igual (idéntica) a la primera.

Primero, recuperemos una representación de un punto de nuestra tabla nyc_subway_stations. Tomaremos solo la entrada de “Broad St”.

SELECT name, geom
FROM nyc_subway_stations
WHERE name = 'Broad St';
   name   |                      geom
----------+---------------------------------------------------
 Broad St | 0101000020266900000EEBD4CF27CF2141BC17D69516315141

Luego, volvemos a usar la representación de la geometría en una prueba ST_Equals:

SELECT name
FROM nyc_subway_stations
WHERE ST_Equals(
  geom,
  '0101000020266900000EEBD4CF27CF2141BC17D69516315141');
Broad St

Nota

La representación del punto no era muy legible para humanos (0101000020266900000EEBD4CF27CF2141BC17D69516315141) pero era una representación exacta de los valores de coordenadas. Para una prueba como la de igualdad, usar las coordenadas exactas es necesario.

11.2. ST_Intersects, ST_Disjoint, ST_Crosses y ST_Overlaps

ST_Intersects, ST_Crosses y ST_Overlaps prueban si los interiores de las geometrías se intersectan.

_images/st_intersects.png

ST_Intersects(geometry A, geometry B) devuelve t (TRUE) si las dos formas tienen algún espacio en común, es decir, si sus límites o interiores se intersectan.

_images/st_disjoint.png

El opuesto de ST_Intersects es ST_Disjoint(geometry A , geometry B). Si dos geometrías son disjuntas, no se intersectan, y viceversa. De hecho, a menudo es más eficiente probar «no intersecta» que probar «disjunta» porque las pruebas de intersección pueden estar indexadas espacialmente, mientras que la prueba de disjunción no.

_images/st_crosses.png

Para comparaciones multipunto/polígono, multipunto/linestring, linestring/linestring, linestring/polígono y linestring/multipolígono, ST_Crosses(geometry A, geometry B) devuelve t (TRUE) si la intersección da como resultado una geometría cuya dimensión es una menos que la dimensión máxima de las dos geometrías de origen y el conjunto de intersección está en el interior de ambas geometrías de origen.

_images/st_overlaps.png

ST_Overlaps(geometry A, geometry B) compara dos geometrías de la misma dimensión y devuelve TRUE si su conjunto de intersección da como resultado una geometría diferente de ambas pero de la misma dimensión.

Tomemos nuestra estación de metro Broad Street y determinemos su vecindario usando la función ST_Intersects:

SELECT name, ST_AsText(geom)
FROM nyc_subway_stations
WHERE name = 'Broad St';
POINT(583571 4506714)
SELECT name, boroname
FROM nyc_neighborhoods
WHERE ST_Intersects(geom, ST_GeomFromText('POINT(583571 4506714)',26918));
        name        | boroname
--------------------+-----------
 Financial District | Manhattan

11.3. ST_Touches

ST_Touches prueba si dos geometrías se tocan en sus límites, pero no se intersectan en sus interiores

_images/st_touches.png

ST_Touches(geometry A, geometry B) devuelve TRUE si los límites de cualquiera de las geometrías se intersectan o si solo el interior de una de las geometrías intersecta el límite de la otra.

11.4. ST_Within y ST_Contains

ST_Within y ST_Contains prueban si una geometría está completamente dentro de la otra.

_images/st_within.png

ST_Within(geometry A , geometry B) devuelve TRUE si la primera geometría está completamente dentro de la segunda geometría. ST_Within prueba exactamente el resultado opuesto de ST_Contains.

ST_Contains(geometry A, geometry B) devuelve TRUE si la segunda geometría está completamente contenida por la primera geometría.

11.5. ST_Distance y ST_DWithin

Una pregunta de SIG extremadamente común es «encontrar todas las cosas dentro de la distancia X de esta otra cosa».

La función ST_Distance(geometry A, geometry B) calcula la distancia más corta entre dos geometrías y la devuelve como un número de punto flotante. Esto es útil para informar realmente la distancia entre objetos.

SELECT ST_Distance(
  ST_GeometryFromText('POINT(0 5)'),
  ST_GeometryFromText('LINESTRING(-2 2, 2 2)'));
3

Para probar si dos objetos están dentro de una distancia entre sí, la función ST_DWithin proporciona una prueba de verdadero/falso acelerada por índice. Esto es útil para preguntas como «¿cuántos árboles están dentro de un buffer de 500 metros de la carretera?». No tienes que calcular un buffer real, solo tienes que probar la relación de distancia.

_images/st_dwithin.png

Usando nuevamente nuestra estación de metro Broad Street, podemos encontrar las calles cercanas (a menos de 10 metros) de la parada de metro:

SELECT name
FROM nyc_streets
WHERE ST_DWithin(
        geom,
        ST_GeomFromText('POINT(583571 4506714)',26918),
        10
      );
     name
--------------
   Wall St
   Broad St
   Nassau St

Y podemos verificar la respuesta en un mapa. La estación Broad St está realmente en la intersección de Wall, Broad y Nassau Streets.

_images/broad_st.jpg

11.6. Lista de funciones

ST_Contains(geometry A, geometry B): Devuelve true si y solo si ningún punto de B se encuentra en el exterior de A, y al menos un punto del interior de B se encuentra en el interior de A.

ST_Crosses(geometry A, geometry B): Devuelve TRUE si las geometrías suministradas tienen algunos, pero no todos, los puntos interiores en común.

ST_Disjoint(geometry A , geometry B): Devuelve TRUE si las geometrías no «intersectan espacialmente», es decir, si no comparten ningún espacio.

ST_Distance(geometry A, geometry B): Devuelve la distancia cartesiana bidimensional mínima (basada en la referencia espacial) entre dos geometrías en unidades proyectadas.

ST_DWithin(geometry A, geometry B, radius): Devuelve true si las geometrías están dentro de la distancia especificada (radio) una de la otra.

ST_Equals(geometry A, geometry B): Devuelve true si las geometrías dadas representan la misma geometría. Se ignora la direccionalidad.

ST_Intersects(geometry A, geometry B): Devuelve TRUE si las geometrías/geografías «intersectan espacialmente» (comparten alguna porción del espacio) y FALSE si no lo hacen (son disjuntas).

ST_Overlaps(geometry A, geometry B): Devuelve TRUE si las geometrías comparten espacio, son de la misma dimensión, pero no están completamente contenidas una por la otra.

ST_Touches(geometry A, geometry B): Devuelve TRUE si las geometrías tienen al menos un punto en común, pero sus interiores no se intersectan.

ST_Within(geometry A , geometry B): Devuelve true si la geometría A está completamente dentro de la geometría B