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/36886Antworten:
Ich konnte nicht anders, als zu denken, dass Ihr Beispiel tatsächlich ein Raster ist, und obwohl Sie erwähnt haben, dass Sie basierend auf "bestimmten Kriterien (möglicherweise Größe)" zusammenführen möchten, möchte ich es mit einer Rasterumwandlung versuchen.
Für Ihr spezielles Beispiel würde dies funktionieren:
Da Ihre Polygone perfekt ausgerichtete Zellen sind, werden sie in ein Raster (10 x 20 Zellen) umgewandelt. Die dumpaspolygons helfen Ihnen dabei, indem Sie alle benachbarten Zellen zu einer zusammenführen und durch Vergleich mit den ursprünglichen Polygonen sogar die ID für nicht zusammengeführte Polygone zurückerhalten.
Nachdem ich das erklärt habe, bin ich sehr gespannt, wie sich das skalieren lässt und wie groß Ihr Datensatz ist: D
quelle
Hier ist ein Beispiel, wie dies im prozeduralen Stil mit mehreren Durchgängen unter der Haube durchgeführt wird.
Sie sollten in der Lage sein, mehr Spalten mitzunehmen und zusätzliche Kriterien für den Beitritt anzuwenden, indem Sie die Funktionsweise der folgenden
LIMIT 1
Auswahl ändern:Führe das Ding aus:
Richtige Gewerkschaften, keine Multipolygone:
quelle
Hier ist eine andere (nicht funktionierende) Strategie als Referenz (die ich nicht ausschließen konnte, wenn es nur um Berührungspunkte ging). Es sollte schneller sein als meine andere Antwort, da es nur einen Durchgang dauert.
(Fühlen Sie sich frei, eine andere Antwort zu ändern und zu posten, wenn jemand die Geometrie id = 5 in seiner eigenen Gruppe erhalten kann.)
Um die Liste der IDs usw. zurückzugewinnen,
st_contains
müssten Sie sich wie in der folgenden Antwort beschrieben erneut für die Testpoly-Tabelle anmelden: /programming//a/37486732/6691, aber ich konnte das nicht zum Laufen bringen für Polygone aus irgendeinem Grund.quelle
Hier ist ein kleiner Vorgeschmack auf Ihre ursprüngliche Abfrage:
Referenzen: https://postgis.net/docs/using_postgis_dbmanagement.html#DE-9IM
quelle