Trennen Sie Polygone anhand der Schnittmenge mit PostGIS


36

Ich habe eine PostGIS-Tabelle mit Polygonen, in denen sich einige überschneiden. Das versuche ich zu tun:

  • Geben Sie mir für ein bestimmtes, durch id ausgewähltes Polygon alle Polygone, die sich schneiden. Grundsätzlich gilt,select the_geom from the_table where ST_Intersects(the_geom, (select the_geom from the_table where source_id = '123'))
  • Aus diesen Polygonen muss ein neues Polygon erstellt werden, sodass die Schnittmenge zu einem neuen Polygon wird. Wenn sich also Polygon A mit Polygon B schneidet, erhalte ich drei neue Polygone: A minus AB, AB und B minus AB.

Irgendwelche Ideen?


1
Hmmm, ich denke, Sie sehen, worauf Sie hinaus wollen, aber eine einfache Grafik kann Wunder bewirken, dass ich (und andere) genau sehen, was Sie wollen.
— Jason

Fügte einige in meiner Antwort hinzu.
— Adam Matan

Antworten:


29

Da Sie angegeben haben, dass Sie für jedes Polygon, an dem Sie interessiert sind, eine Gruppe sich überschneidender Polygone erhalten, möchten Sie möglicherweise ein sogenanntes "Polygon-Overlay" erstellen.

Dies ist nicht genau das, was Adams Lösung tut. Schauen Sie sich dieses Bild einer ABC-Kreuzung an, um den Unterschied zu erkennen:

ABC-Kreuzung

Ich glaube, Adams Lösung wird ein "AB" -Polygon erzeugen, das sowohl den Bereich von "AB! C" und "ABC" abdeckt, als auch ein "AC" -Polygon, das "AC! B" und "ABC" abdeckt, und ein " BC "Polygon, das" BC! A "und" ABC "ist. Die Ausgabepolygone "AB", "AC" und "BC" überlappen also alle den Bereich "ABC".

Eine Polygon-Überlagerung erzeugt nicht überlappende Polygone, also wäre AB! C ein Polygon und ABC ein Polygon.

Das Erstellen eines Polygon-Overlays in PostGIS ist eigentlich ganz einfach.

Grundsätzlich gibt es drei Schritte.

Schritt 1 ist das Extrahieren der Linien [Beachten Sie, dass ich den äußeren Ring des Polygons verwende, es wird etwas komplizierter, wenn Sie Löcher richtig handhaben möchten]:

SELECT ST_ExteriorRing(polygon_col) AS the_geom FROM my_table) AS lines

Schritt 2 besteht darin, die Linien zu "knoten" (an jeder Kreuzung einen Knoten zu erzeugen). Einige Bibliotheken wie JTS haben "Noder" -Klassen, mit denen Sie dies tun können, aber in PostGIS erledigt die ST_Union- Funktion dies für Sie:

SELECT ST_Union(the_geom) AS the_geom FROM (...your lines...) AS noded_lines

Schritt 3 besteht darin, alle möglichen nicht überlappenden Polygone zu erstellen, die aus all diesen Zeilen stammen können. Dies geschieht mit der Funktion ST_Polygonize :

SELECT ST_Polygonize(the_geom) AS the_geom FROM (...your noded lines...)

Sie können die Ausgabe jedes dieser Schritte in einer temporären Tabelle speichern oder sie alle in einer einzigen Anweisung kombinieren:

CREATE TABLE my_poly_overlay AS
SELECT geom FROM ST_Dump((
    SELECT ST_Polygonize(the_geom) AS the_geom FROM (
        SELECT ST_Union(the_geom) AS the_geom FROM (
            SELECT ST_ExteriorRing(polygon_col) AS the_geom FROM my_table) AS lines
        ) AS noded_lines
    )
)

Ich verwende ST_Dump, weil die Ausgabe von ST_Polygonize eine Geometriesammlung ist und es (normalerweise) praktischer ist, eine Tabelle zu haben, in der jede Zeile eines der Polygone ist, aus denen die Polygonüberlagerung besteht.


Beachten Sie, dass ST_ExteriorRingkeine Löcher fallen. ST_Boundarybewahrt die inneren Ringe, erzeugt aber auch ein Polygon in ihnen.
— jpmc26

Die Vereinigung der Außenringe stürzt ab, wenn zu viele Polygone vorhanden sind. Leider funktioniert diese "unkomplizierte" Lösung nur bei kleinen Netzabdeckungen.
— Pierre Racine

13

Wenn ich richtig verstehe, möchten Sie nehmen (A ist die linke Geometrie, B ist die rechte):

Bild von A∪B http://img838.imageshack.us/img838/3996/intersectab1.png

Und extrahieren:

A ∖ AB

Bild von A ∖ AB http://img830.imageshack.us/img830/273/intersectab2.png

AB

Bild von AB http://img828.imageshack.us/img828/7413/intersectab3.png

und B ∖ AB

Bild von B ∖ AB http://img839.imageshack.us/img839/5458/intersectab4.png

Das heißt - drei verschiedene Geometrien für jedes sich überschneidende Paar.

Zunächst erstellen wir eine Ansicht aller sich überschneidenden Geometrien. Angenommen, Ihr Tabellenname lautet polygons_table:

CREATE OR REPLACE VIEW p_intersections AS    -- Create a view with the 
SELECT t1.the_geom as t1_geom,               -- intersecting geoms. Each pair
       t2.the_geom as t2_geom                -- appears once (t2.id<t2.id)
    FROM polygons_table t1, polygons_table t2  
         WHERE t1.id<t2.id AND t1.the_geom && t2.the_geom 
                           AND intersects t1.the_geom, t2.the_geom;

Jetzt haben wir eine Ansicht (praktisch eine Nur-Lese-Tabelle), in der Paare sich überschneidender Geoms gespeichert sind, wobei jedes Paar aufgrund der t1.id<t2.idBedingung nur einmal angezeigt wird .

Jetzt sammeln wir Ihre Kreuzungen - A∖AB, ABund B∖ABunter Verwendung von SQL ist UNIONauf allen drei Abfragen:

--AB:
SELECT ST_intersection(t1.the_geom, t2.the_geom) 
    AS geom 
    FROM p_intersections

UNION 

--A∖AB:
SELECT ST_Difference(t1.the_geom, t2.the_geom) 
    AS geom 
    FROM p_intersections

UNION

--B∖AB:
SELECT ST_Difference(t2.the_geom, t1.the_geom) 
    AS geom 
    FROM p_intersections;

Anmerkungen:

  1. Der &&Bediener wird als Filter vor dem intersectsBediener verwendet, um die Leistung zu verbessern.
  2. Ich habe mich dafür entschieden, eine VIEWstatt einer einzigen riesigen Abfrage zu erstellen . Dies dient nur der Vereinfachung.
  3. Wenn Sie gemeint haben, ABist dies die Vereinigung und nicht die Kreuzung von Aund B- Verwenden Sie ST_Union anstelle von st_intersection bei der UNIONAbfrage an den entsprechenden Stellen.
  4. Das ∖Zeichen ist ein Unicode-Zeichen für Set difference. Entfernen Sie es aus dem Code, wenn es Ihre Datenbank verwirrt.
  5. Bilder mit freundlicher Genehmigung von Wikimedia Commons in der Kategorie nette Mengenlehre .


Schöne Erklärung! Die Ergebnisse sind die gleichen wie in der SCW-Lösung, aber sein Weg sollte schneller sein (berechnet / oder speichert / speichert keine zusätzlichen Schnittpunkte von A und B)
— Stachu

Vielen Dank! Ich glaube, ich speichere keine zusätzlichen Informationen, da ich nur SQL VIEWs und keine Tabellen erstelle.
— Adam Matan

Ja, das ist wahr, aber Sie berechnen zusätzliche Schnittmenge von A und B, die nicht erforderlich ist
— Stachu

5
Die Bilder in dieser Antwort funktionieren nicht mehr.
— Fezter

8

Was Sie beschreiben, ist die Art und Weise, wie der Union-Operator in ArcGIS arbeitet, jedoch ein wenig anders als Union oder Intersection in der GEOS-Welt. Das Shapely-Handbuch enthält Beispiele für die Funktionsweise von Sets in GEOS . Das PostGIS-Wiki bietet jedoch ein gutes Beispiel für die Verwendung von Linien, die den Trick für Sie tun sollten.

Alternativ können Sie drei Dinge berechnen:

  1. ST_Interection (geom_a, geom_b)
  2. ST_Differenz (geom_a, geom_b)
  3. ST_Differenz (geom_b, geom_a)

Dies sollten die drei Polygone sein, die Sie in Ihrem zweiten Aufzählungspunkt erwähnt haben.


2
Das PostGIS Wiki Beispiel ist gut
— fmark 23.07.10

Würde ST_Intersects nicht einen Booleschen Wert zurückgeben, wenn sie sich schneiden oder nicht? Ich denke, ST_Intersection würde funktionieren.
— Jason

Ja, Tippfehler meinerseits - jetzt im Original behoben, danke Jason!
— scw

-2

So etwas wie:

INSERT INTO new_table VALUES ((wähle id, the_geom aus old_table wo st_intersects (the_geom, (wähle the_geom aus old_table wo id = '123')) = true

BEARBEITEN: Sie benötigen die tatsächliche Schnittmenge des Polygons.

INSERT INTO new_table-Werte ((select id, ST_Intersection (the_geom, (select the_geom from old where id = 123))

Mal sehen, ob das klappt.

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.