Ich möchte Adjazenztests für eine Parzellenebene (Polygone) durchführen und diese zusammenführen, wenn sie bestimmten Kriterien entsprechen (möglicherweise Größe). In der folgenden Abbildung möchte ich die Polygone 1, 2, 3 und 4 zusammenführen, nicht jedoch 5.
Ich habe zwei Probleme:
ST_TOUCHES
Gibt TRUE zurück, wenn sich nur die Ecken berühren und kein Liniensegment. Ich glaube, ich brauche ST_RELATE, um nach gemeinsam genutzten Liniensegmenten zu suchen.- Idealerweise möchte ich ALLE benachbarten Polygone zu einem zusammenführen, aber ich bin nicht sicher, wie ich über zwei hinaus skalieren soll - wie in, füge 1,2,3 und 4 (und möglicherweise mehr zu tatsächlichen Daten) in einer Runde zusammen.
Die Struktur, die ich jetzt habe, basiert auf einem Self-Join ST_TOUCHES
.
Spielzeugdaten
CREATE TABLE testpoly AS
SELECT
1 AS id, ST_PolyFromText('POLYGON ((0 0, 10 0, 10 20, 00 20, 0 0 ))') AS geom UNION SELECT
2 AS id, ST_PolyFromText('POLYGON ((10 0, 20 0, 20 20, 10 20, 10 0 ))') AS geom UNION SELECT
3 AS id, ST_PolyFromText('POLYGON ((10 -20, 20 -20, 20 0, 10 0, 10 -20 ))') AS geom UNION SELECT
4 AS id, ST_PolyFromText('POLYGON ((20 -20, 30 -20, 30 0, 20 0, 20 -20 ))') AS geom UNION SELECT
5 AS id, ST_PolyFromText('POLYGON ((30 0, 40 0, 40 20, 30 20, 30 0 ))') AS geom ;
Auswahl
SELECT
gid, adj_gid,
st_AStext(st_union(l2.g1,l2.g2)) AS geo_combo
from (
--level 2
SELECT
t1.id AS gid,
t1.geom AS g1,
t2.id AS adj_gid,
t2.geom AS g2
from
testpoly t1,
testpoly t2
where
ST_Touches( t1.geom, t2.geom )
AND t1.geom && t2.geom
)
l2
Hier ist die Ausgabe:
+-----+---------+-------------------------------------------------------------------------------+
| gid | adj_gid | geo_combo |
+-----+---------+-------------------------------------------------------------------------------+
| 1 | 2 | POLYGON((10 0,0 0,0 20,10 20,20 20,20 0,10 0)) |
+-----+---------+-------------------------------------------------------------------------------+
| 1 | 3 | MULTIPOLYGON(((10 0,0 0,0 20,10 20,10 0)),((10 0,20 0,20 -20,10 -20,10 0))) |
+-----+---------+-------------------------------------------------------------------------------+
| 2 | 1 | POLYGON((10 20,20 20,20 0,10 0,0 0,0 20,10 20)) |
+-----+---------+-------------------------------------------------------------------------------+
| 2 | 3 | POLYGON((10 0,10 20,20 20,20 0,20 -20,10 -20,10 0)) |
+-----+---------+-------------------------------------------------------------------------------+
| 2 | 4 | MULTIPOLYGON(((20 0,10 0,10 20,20 20,20 0)),((20 0,30 0,30 -20,20 -20,20 0))) |
+-----+---------+-------------------------------------------------------------------------------+
| 3 | 1 | MULTIPOLYGON(((10 0,20 0,20 -20,10 -20,10 0)),((10 0,0 0,0 20,10 20,10 0))) |
+-----+---------+-------------------------------------------------------------------------------+
| 3 | 2 | POLYGON((20 0,20 -20,10 -20,10 0,10 20,20 20,20 0)) |
+-----+---------+-------------------------------------------------------------------------------+
| 3 | 4 | POLYGON((20 -20,10 -20,10 0,20 0,30 0,30 -20,20 -20)) |
+-----+---------+-------------------------------------------------------------------------------+
| 4 | 2 | MULTIPOLYGON(((20 0,30 0,30 -20,20 -20,20 0)),((20 0,10 0,10 20,20 20,20 0))) |
+-----+---------+-------------------------------------------------------------------------------+
| 4 | 3 | POLYGON((20 0,30 0,30 -20,20 -20,10 -20,10 0,20 0)) |
+-----+---------+-------------------------------------------------------------------------------+
| 4 | 5 | MULTIPOLYGON(((30 0,30 -20,20 -20,20 0,30 0)),((30 0,30 20,40 20,40 0,30 0))) |
+-----+---------+-------------------------------------------------------------------------------+
| 5 | 4 | MULTIPOLYGON(((30 0,30 20,40 20,40 0,30 0)),((30 0,30 -20,20 -20,20 0,30 0))) |
+-----+---------+-------------------------------------------------------------------------------+
Beachten Sie, dass das Polygon id = 3 einen Punkt mit id = 1 teilt und daher als positives Ergebnis zurückgegeben wird. Wenn ich die WHERE-Klausel in ändere, ST_Touches( t1.geom, t2.geom ) AND t1.geom && t2.geom AND ST_Relate(t1.geom, t2.geom ,'T*T***T**');
erhalte ich überhaupt keine Datensätze.
Wie kann ich also zuerst ST_Relate angeben, um sicherzustellen, dass nur Pakete berücksichtigt werden, die ein Liniensegment gemeinsam nutzen.
Und wie würde ich dann die Polygone 1, 2, 3, 4 in einer Runde zusammenführen und dabei die Ergebnisse des obigen Aufrufs zusammenfassen und gleichzeitig erkennen, dass die Angrenzungen 1 bis 2 die gleichen sind wie die umgekehrten?
Aktualisieren
Wenn ich dies zu der where
Klausel hinzufüge, erhalte ich offensichtlich nur Polygone und keine Multipolygone, wodurch falsche Positive für meine Zwecke ausgesondert werden - Eckberührungen werden ignoriert.
GeometryType(st_union(t1.geom,t2.geom)) != 'MULTIPOLYGON'
Dies ist zwar nicht ideal (ich würde eher Topologieprüfungen ST_RELATE
als allgemeinere Lösung verwenden), aber es ist ein Weg nach vorn. Dann bleibt die Frage der Enttäuschung und Vereinigung dieser. Wenn ich eine Sequenz nur für Polygone erzeugen könnte, die sich berühren, könnte ich mich darauf einigen.
Update II
Dieser scheint für die Auswahl von Polygonen zu funktionieren, die Linien (aber keine Ecken) teilen, und ist daher eine allgemeinere Lösung als der obige MULTIPOLYGON
Test. Meine where-Klausel sieht jetzt so aus:
WHERE
ST_Touches( t1.geom, t2.geom )
AND t1.geom && t2.geom
-- 'overlap' relation
AND ST_Relate(t1.geom, t2.geom)='FF2F11212') t2
Jetzt bleibt nur noch, wie Sie die Zusammenführung für mehr als nur ein Paar Polygone, sondern für eine beliebige Zahl, die den Kriterien entspricht, auf einmal durchführen.
ST_IntersectionArray
Funktion [1] so ändern , dass sie mit ST_Union [1] zusammenarbeitet: gis.stackexchange.com/a/60295/36886