PostGIS ST_Intersection von Polygonen kann Zeilen zurückgeben


9

Wenn Sie die Polygone einer Tabelle mit Polygonen in einer anderen beschneiden, kann ST_Intersection eine Reihe von Ergebnissen zurückgeben, die mit ST_Dump verarbeitet werden können. Die zurückgegebenen Mehrfachgeometrien sind nicht unbedingt ST_Polygon, sondern auch ST_LineString (wahrscheinlich auch ein Punkt). Also beim Ausführen einer Abfrage

INSERT INTO c (geom)
  (SELECT (ST_Dump(ST_Intersection(a.geom,b.geom))).geom
  FROM a INNER JOIN b ON ST_Intersects(a.geom, b.geom));

Beim Versuch, die Tabelle "c" mit abgeschnittenen Polygonen zu füllen, schlägt dies mit ERROR fehl: Der Geometrietyp (LineString) stimmt nicht mit dem Spaltentyp (Polygon) überein.

Ich habe eine weitere verschachtelte SELECT-Anweisung ausgeführt, sodass nur die Polygongeometrien durchgekommen sind, z.

INSERT INTO c (geom)
  (SELECT geom FROM
    (SELECT (ST_Dump(ST_Intersection(a.geom,b.geom))).geom
    FROM a INNER JOIN b ON ST_Intersects(a.geom, b.geom))) AS cl
    WHERE ST_GeometryType(cl.geom)='ST_Polygon');

Da dies etwas umständlich ist, frage ich mich, ob es eine elegantere Lösung gibt, um ungültige Geometrien zu löschen.


Übrigens habe ich <! - language: lang-sql -> vor die Codeblöcke gesetzt, aber es gibt immer noch keine Hervorhebung. Irgendwelche Hinweise für einen Noob?
Robert Špendl

Um Code zu formatieren, fügen Sie ihn einfach ein, wählen Sie ihn aus und verwenden Sie die Schaltfläche Codebeispiel {}über dem Fenster zum Bearbeiten von Fragen.
PolyGeo

Hm, ich habe das gemacht, der Code ist als "Code" markiert, aber die Schlüsselwörter sind immer noch nicht farbig.
Robert Špendl

Normalerweise versuche ich hier nicht, SQL-Code zu verschönern, aber ich habe gerade einen Meta-Beitrag gefunden, der unter meta.stackexchange.com/questions/90521/… nützlich aussieht. Haben Sie eine "leere Zeile zwischen dem Kommentar und dem Code" hinterlassen?
PolyGeo

Ein Schnittpunkt zweier Geometrien kann jede Art von Geometrie ergeben. Ich denke, Ihre aktuelle Lösung ist die direkteste.
Mike T

Antworten:


9

Dies ist möglicherweise ein guter Ort, um eine SQL-Sprachfunktion zu verwenden. Hier ist eine kurze, die für diese Situation funktionieren sollte:

CREATE OR REPLACE FUNCTION PolygonalIntersection(a geometry, b geometry)
RETURNS geometry AS $$
SELECT ST_Collect(geom)
FROM 
(SELECT (ST_Dump(ST_Intersection(a, b))).geom 
UNION ALL
-- union in an empty polygon so we get an 
-- empty geometry instead of NULL if there
-- is are no polygons in the intersection
SELECT ST_GeomFromText('POLYGON EMPTY')) SQ
WHERE ST_GeometryType(geom) = 'ST_Polygon';
$$ LANGUAGE SQL;

Dadurch bleiben die polygonalen Komponenten einer Kreuzung erhalten, aber alles andere wird weggeworfen. Es wird immer ein MultiPolygon zurückgegeben, auch wenn Sie eine oder keine Komponenten haben.

WITH 
      square   as (SELECT ST_GeomFromText('POLYGON ((0 0, 0  1,  1  1,  1  0, 0 0))') AS geom),
biggersquare   as (SELECT ST_GeomFromText('POLYGON ((0 0, 0 10, 10 10, 10  0, 0 0))') AS geom),
adjacentsquare as (SELECT ST_GeomFromText('POLYGON ((0 0, 1  0,  1 -1, -1 -1, 0 0))') AS geom)   

SELECT ST_AsText(PolygonalIntersection(square.geom, biggersquare.geom))
  FROM square, biggersquare;
--"MULTIPOLYGON(((0 0,0 1,1 1,1 0,0 0)))"

SELECT ST_AsText(PolygonalIntersection(square.geom, adjacentsquare.geom))
  FROM square, adjacentsquare;
--"MULTIPOLYGON(EMPTY)"

3

Sehr gute Antwort von @dbaston. Die Rückgabe einer leeren Geometrie anstelle von null kann jedoch zu Problemen führen, da die zurückgegebene leere Geometrie kein srid enthält. St_Intersection gibt möglicherweise auch MultiPolygon zurück. Diese aktualisierte Funktion war wirklich nützlich für mich:

CREATE OR REPLACE FUNCTION PolygonalIntersection(a geometry, b geometry)
RETURNS geometry AS $$
SELECT ST_Collect(geom)
FROM 
(SELECT (ST_Dump(ST_Intersection(a, b))).geom 
) SQ
WHERE ST_GeometryType(geom) = 'ST_Polygon' OR ST_GeometryType(geom) = 'ST_MultiPolygon';
$$ LANGUAGE SQL;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.