28. 3-D¶
28.1. 3-D geometrier¶
Hittills har vi arbetat med 2D-geometrier, med endast X- och Y-koordinater. Men PostGIS stöder ytterligare dimensioner för alla geometrityper, en ”Z”-dimension för att lägga till höjdinformation och en ”M”-dimension för ytterligare dimensionell information (vanligtvis tid, vägkilometer eller information om avstånd uppströms) för varje koordinat.
För 3D- och 4D-geometrier läggs de extra dimensionerna till som extra koordinater för varje vertex i geometrin, och geometritypen förbättras för att ange hur de extra dimensionerna ska tolkas. Genom att lägga till de extra dimensionerna skapas tre extra möjliga geometrityper för varje geometriprimitiv:
Point (en 2D-typ) får sällskap av typerna PointZ, PointM och PointZM.
Linestring (en 2D-typ) får sällskap av LinestringZ-, LinestringM- och LinestringZM-typerna.
Polygon (en 2D-typ) förenas med typerna PolygonZ, PolygonM och PolygonZM.
Och så vidare.
För välkänd text (WKT) representation, formatet för högre dimensionella geometrier ges av ISO SQL/MM specifikationen. Den extra dimensionalitetsinformationen läggs helt enkelt till i textsträngen efter typnamnet och de extra koordinaterna läggs till efter X/Y-informationen. Till exempel:
PUNKT 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, 0 0 0))
Funktionen ST_AsText() returnerar ovanstående representationer vid hantering av 3-D- och 4-D-geometrier.
För välkänd binär (WKB) representation ges formatet för högre dimensionella geometrier av ISO SQL/MM-specifikationen. BNF-formatet för formatet finns tillgängligt från https://git.osgeo.org/gitea/postgis/postgis/src/branch/master/doc/bnf-wkb.txt.
Förutom högre dimensionella former av standardtyperna innehåller PostGIS några nya typer som är meningsfulla i ett 3D-rum:
Med typen TIN kan du modellera triangulära maskor som rader i din databas.
Med POLYHEDRALSURFACE kan du modellera volymetriska objekt i din databas.
Eftersom båda dessa typer är avsedda för modellering av 3D-objekt är det egentligen bara Z-varianterna som är meningsfulla att använda. Ett exempel på en POLYHEDRALSURFACE Z skulle vara kuben med 1 enhet:
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. 3-D funktioner¶
Det finns ett antal funktioner som är konstruerade för att beräkna relationer mellan 3D-objekt:
ST_3DClosestPoint - Returnerar den 3-dimensionella punkt på g1 som ligger närmast g2. Detta är den första punkten på den kortaste 3D-linjen.
ST_3DDistance - För geometrityp Returnerar det 3-dimensionella cartesiska minimiavståndet (baserat på spatial ref) mellan två geometrier i projicerade enheter.
ST_3DDWithin - För geometrityp 3d (z) Returnerar sant om två geometriers 3d-avstånd ligger inom ett antal enheter.
ST_3DDFullyWithin - Returnerar true om alla 3D-geometrier ligger inom det angivna avståndet från varandra.
ST_3DIntersects - Returnerar TRUE om geometrierna ”spatialt korsar varandra” i 3d - endast för punkter och linjestrings
ST_3DLongestLine - Returnerar den 3-dimensionella längsta linjen mellan två geometrier
ST_3DMaxDistance - För geometrityp Returnerar det 3-dimensionella cartesiska maximala avståndet (baserat på spatial ref) mellan två geometrier i projicerade enheter.
ST_3DShortestLine - Returnerar den 3-dimensionella kortaste linjen mellan två geometrier
Vi kan t.ex. beräkna avståndet mellan vår kub och en punkt med hjälp av funktionen 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. N-D-index¶
När du har data i högre dimensioner kan det vara meningsfullt att indexera dem. Du bör dock noga tänka igenom fördelningen av dina data i alla dimensioner innan du använder ett flerdimensionellt index.
Index är bara användbara när de gör det möjligt för databasen att drastiskt minska antalet returrader som ett resultat av ett WHERE-villkor. För att ett index med en högre dimension ska vara användbart måste data täcka ett brett område av den dimensionen, i förhållande till de typer av frågor som du konstruerar.
En uppsättning DEM-punkter skulle förmodligen vara en dålig kandidat för ett 3D-index, eftersom frågorna vanligtvis skulle extrahera en 2D-box med punkter och sällan försöka välja en Z-skiva av punkter.
En uppsättning GPS-spår i X/Y/T-rymden kan vara en bra kandidat för ett 3D-index, om GPS-spåren ofta överlappar varandra i alla dimensioner (t.ex. om man kör samma rutt om och om igen vid olika tidpunkter), eftersom det skulle finnas stor variabilitet i alla dimensioner i datauppsättningen.
Du kan skapa ett flerdimensionellt index på data med vilken dimensionalitet som helst (även blandad dimensionalitet). Så här skapar du till exempel ett flerdimensionellt index på tabellen nyc_streets
,
CREATE INDEX nyc_streets_gix_nd ON nyc_streets
USING GIST (geom gist_geometry_ops_nd);
Parametern gist_geometry_ops_nd
säger till PostGIS att använda N-D index istället för standard 2-D index.
När du har byggt upp indexet kan du använda det i frågor med indexoperatorn &&&
. &&&
har samma semantik som &&
, ”bounding boxes interagerar”, men tillämpar denna semantik med hjälp av alla dimensioner i de ingående geometrierna. Geometrier med fel matchande dimensionalitet interagerar inte.
-- 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;
Om du vill söka i tabellen nyc_streets
med hjälp av N-D-index ersätter du bara den vanliga 2D-indexoperatorn &&
med operatorn &&&
.
-- 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);
Resultaten bör vara desamma. I allmänhet är N-D-indexet något långsammare än 2D-indexet, så använd N-D-indexet endast om du är säker på att N-D-frågorna kommer att förbättra selektiviteten i dina frågor.