28. 3-D¶
28.1. Geometrías 3-D¶
Hasta ahora hemos trabajado con geometrías bidimensionales, con coordenadas X e Y únicamente. Pero PostGIS soporta dimensiones adicionales en todos los tipos de geometría, una dimensión «Z» para añadir información de altura y una dimensión «M» para información dimensional adicional (comúnmente información de tiempo, o millas de carretera, o distancia río arriba) para cada coordenada.
Para las geometrías 3D y 4D, las dimensiones adicionales se añaden como coordenadas adicionales para cada vértice de la geometría, y el tipo de geometría se mejora para indicar cómo interpretar las dimensiones adicionales. La adición de las dimensiones adicionales da como resultado tres tipos de geometría adicionales posibles para cada primitiva geométrica:
Point (un tipo 2-D ) es complementada por los tipos PointM y PointZM .
Linestring (un tipo 2-D) es complementado con los tipos LinestringZ, LinestringM y LinestringZM.
Polygon (un tipo 2D) se une a los tipos PolygonZ, PolygonM y PolygonZM.
Y así sucesivamente.
Para el formato de texto bien conocido (WKT), el formato para geometrías de mayor dimensionalidad viene dado por la especificación ISO SQL/MM. La información sobre la dimensionalidad adicional simplemente se añade a la cadena de texto después del nombre del tipo, y las coordenadas adicionales se añaden después de la información X/Y. Por ejemplo:
POINT ZM (1 2 3 4)
LINESTRING M (1 1 0, 1 2 0, 1 3 1, 2 2 0)
POLYGON Z ((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0))
La función ST_AsText() devolverá las representaciones mostradas anteriormente cuando se trate de geometrías 3D y 4D.
Para la representación binaria (WKB), el formato para geometrías de mayor dimensión viene dado por la especificación ISO SQL/MM. La forma BNF del formato está disponible en https://git.osgeo.org/gitea/postgis/postgis/src/branch/master/doc/bnf-wkb.txt.
Además de las formas de mayor dimensión, PostGIS incluye algunos tipos nuevos que tienen sentido en un espacio tridimensional:
El tipo TIN permite modelar mallas triangulares como filas en la base de datos.
El POLYHEDRALSURFACE permite modelar objetos volumétricos en su base de datos.
Dado que ambos tipos sirven para modelar objetos tridimensionales, en realidad sólo tiene sentido utilizar las variantes Z. Un ejemplo de POLYHEDRALSURFACE Z sería el cubo de 1 unidad:
POLYHEDRALSURFACE Z (
((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),
((0 0 0, 0 1 0, 0 1 1, 0 0 1, 0 0 0)),
((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)),
((1 1 1, 1 0 1, 0 0 1, 0 1 1, 1 1 1)),
((1 1 1, 1 0 1, 1 0 0, 1 1 0, 1 1 1)),
((1 1 1, 1 1 0, 0 1 0, 0 1 1, 1 1 1))
)
28.2. Funciones 3D¶
Hay una serie de funciones creadas para calcular relaciones entre objetos tridimensionales:
ST_3DClosestPoint - Devuelve el punto tridimensional de g1 más cercano a g2. Es el primer punto de la línea 3D más corta.
ST_3DDistance - Para datos tipo geometría. Devuelve la distancia cartesiana mínima tridimensional (basada en la referencia espacial) entre dos geometrías en unidades proyectadas.
ST_3DDWithin - Para el tipo de geometría 3D (z). Devuelve verdadero si la distancia 3D de dos geometrías está dentro de un número de unidades.
ST_3DDFullyWithin - Devuelve verdadero si todas las geometrías 3D se encuentran a la distancia especificada entre sí.
ST_3DIntersects - Devuelve TRUE si las geometrías se «intersectan espacialmente» en 3D - sólo para puntos y cadenas de líneas
ST_3DLongestLine - Devuelve la línea tridimensional más larga entre dos geometrías
ST_3DMaxDistance - Para tipo geometría. Devuelve la distancia cartesiana máxima tridimensional (basada en ref. espacial) entre dos geometrías en unidades proyectadas.
ST_3DShortestLine - Devuelve la línea tridimensional más corta entre dos geometrías
Por ejemplo, podemos calcular la distancia entre nuestro cubo unitario y un punto utilizando la función ST_3DDistance:
-- This is really the distance between the top corner
-- and the point.
SELECT ST_3DDistance(
'POLYHEDRALSURFACE Z (
((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),
((0 0 0, 0 1 0, 0 1 1, 0 0 1, 0 0 0)),
((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)),
((1 1 1, 1 0 1, 0 0 1, 0 1 1, 1 1 1)),
((1 1 1, 1 0 1, 1 0 0, 1 1 0, 1 1 1)),
((1 1 1, 1 1 0, 0 1 0, 0 1 1, 1 1 1))
)'::geometry,
'POINT Z (2 2 2)'::geometry
);
-- So here's a shorter form.
SELECT ST_3DDistance(
'POINT Z (1 1 1)'::geometry,
'POINT Z (2 2 2)'::geometry
);
-- Both return 1.73205080756888 == sqrt(3) as expected
28.3. Índices N-D¶
Una vez que tenga datos en dimensiones superiores, puede tener sentido indexarlos. Sin embargo, antes de aplicar un índice multidimensional se debe pensar detenidamente en la distribución de los datos en todas las dimensiones.
Los índices sólo son útiles cuando permiten a la base de datos reducir drásticamente el número de filas devueltas como resultado de una condición WHERE. Para que un índice de dimensión superior sea útil, los datos deben cubrir una amplia gama de esa dimensión, en relación con los tipos de consultas que se están construyendo.
Un conjunto de puntos MDE sería probablemente un candidato pobre para un índice 3D, ya que las consultas normalmente extraerían una caja 2D de puntos, y raramente intentarían seleccionar un conjunto Z de puntos.
Un conjunto de trazas de GPS en el espacio X/Y/T podría ser un buen candidato para un índice tridimensional, si las trazas de GPS se solaparan entre sí con frecuencia en todas las dimensiones (por ejemplo, recorriendo la misma ruta una y otra vez en diferentes momentos), ya que habría una gran variabilidad en todas las dimensiones del conjunto de datos.
Se puede crear un índice multidimensional sobre datos de cualquier dimensionalidad (incluso de dimensionalidad mixta). Por ejemplo, para crear un índice multidimensional en la tabla nyc_streets
,
CREATE INDEX nyc_streets_gix_nd ON nyc_streets
USING GIST (geom gist_geometry_ops_nd);
El parámetro gist_geometry_ops_nd
indica a PostGIS que utilice el índice N-D en lugar del índice estándar 2-D.
Una vez construido el índice, puedes utilizarlo en las consultas con el operador de índice &&&
. &&&
tiene la misma semántica que &&
, «los bbox interactúan», pero aplica esa semántica utilizando todas las dimensiones de las geometrías de entrada. Las geometrías cuya dimensionalidad no coincide no interactúan.
-- Returns true (both 3-D on the zero plane)
SELECT 'POINT Z (1 1 0)'::geometry &&&
'POLYGON ((0 0 0, 0 2 0, 2 2 0, 2 0 0, 0 0 0))'::geometry;
-- Returns false (one 2-D one 3-D)
SELECT 'POINT Z (3 3 3)'::geometry &&&
'POLYGON ((0 0, 0 2, 2 2, 2 0, 0 0))'::geometry;
-- Returns true (the volume around the linestring interacts with the point)
SELECT 'LINESTRING Z(0 0 0, 1 1 1)'::geometry &&&
'POINT(0 1 1)'::geometry;
Para buscar en la tabla nyc_streets
utilizando el índice N-D, basta con sustituir el operador habitual de índice 2D &&
por el operador &&&
.
-- N-D index operator
SELECT gid, name
FROM nyc_streets
WHERE geom &&&
ST_SetSRID('LINESTRING(586785 4492901,587561 4493037)'::geometry,26918);
-- 2-D index operator
SELECT gid, name
FROM nyc_streets
WHERE geom &&
ST_SetSRID('LINESTRING(586785 4492901,587561 4493037)'::geometry,26918);
Los resultados deberían ser los mismos. En general, el índice N-D es ligeramente más lento que el índice 2-D, por lo que sólo debe utilizar el índice N-D cuando esté seguro de que las consultas N-D mejorarán la selectividad de sus consultas.