Vorrei fare test di adiacenza su uno strato di pacchi (poligoni) e unirli se si adattano a determinati criteri (potrebbero essere le dimensioni). Per l'immagine qui sotto, vorrei unire i poligoni 1,2,3 e 4, ma non 5.
Ho due problemi:
ST_TOUCHES
restituisce VERO se solo gli angoli toccano e non un segmento di linea. Penso di aver bisogno di ST_RELATE per verificare la presenza di segmenti di linea condivisi.- Idealmente, vorrei unire TUTTI i poligoni adiacenti in uno, ma non sono sicuro di come scalare oltre due - come in, unire 1,2,3 e 4 (e possibilmente più su dati reali) in un round.
La struttura che ho ora si basa su un self join ST_TOUCHES
.
Dati del giocattolo
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 ;
Selezione
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
Ecco l'output:
+-----+---------+-------------------------------------------------------------------------------+
| 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))) |
+-----+---------+-------------------------------------------------------------------------------+
Si noti che il poligono id = 3 condivide un punto con id = 1 e quindi viene restituito come risultato positivo. Se cambio la clausola WHERE in ST_Touches( t1.geom, t2.geom ) AND t1.geom && t2.geom AND ST_Relate(t1.geom, t2.geom ,'T*T***T**');
non ottengo alcun record.
Quindi , in primo luogo , come specificare ST_Relate per assicurarsi che vengano considerati solo i pacchi che condividono un segmento di linea.
E poi, come unirei i poligoni 1,2,3,4 in un round, comprimendo i risultati della chiamata precedente, riconoscendo nel contempo che l'adiacenza da 1 a 2 è la stessa del contrario?
Aggiornare
Se aggiungo questo alla where
clausola ovviamente ottengo solo poligoni e non multipoligoni, eliminando così i falsi positivi per i miei scopi: i tocchi d'angolo verranno ignorati.
GeometryType(st_union(t1.geom,t2.geom)) != 'MULTIPOLYGON'
Sebbene ciò non sia ideale (preferirei utilizzare i controlli di topologia ST_RELATE
come soluzione più generale), è una via da seguire. Resta quindi la questione del de-duping e dell'unione di questi. Forse, se potessi generare una sequenza solo per i poligoni toccanti, potrei unirmi a questo.
Aggiornamento II
Questo sembra funzionare per selezionare i poligoni che condividono le linee (ma non gli angoli) ed è quindi una soluzione più generale rispetto al MULTIPOLYGON
test sopra . La mia clausola Where ora appare così:
WHERE
ST_Touches( t1.geom, t2.geom )
AND t1.geom && t2.geom
-- 'overlap' relation
AND ST_Relate(t1.geom, t2.geom)='FF2F11212') t2
Ora ciò che rimane è ancora come fare l'unione per più di una coppia di poligoni, ma per un numero arbitrario che si adatta ai criteri, in una volta sola.
ST_IntersectionArray
[funzione] [1] per lavorare con ST_Union [1]: gis.stackexchange.com/a/60295/36886