Je voudrais faire des tests d'adjacence sur une couche parcellaire (polygones) et les fusionner s'ils correspondent à certains critères (peut être la taille). Par l'image ci-dessous, je voudrais fusionner les polygones 1, 2, 3 et 4, mais pas 5.
J'ai deux problèmes:
ST_TOUCHES
renvoie VRAI si seulement les coins se touchent et non un segment de ligne. Je pense que j'ai besoin de ST_RELATE pour vérifier les segments de ligne partagés.- Idéalement, je voudrais fusionner TOUS les polygones adjacents en un seul, mais je ne sais pas comment évoluer au-delà de deux - comme dans, fusionner 1,2,3 et 4 (et peut-être plus sur les données réelles) en un seul tour.
La structure que j'ai maintenant est basée sur une auto-jointure ST_TOUCHES
.
Données sur les jouets
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 ;
Sélection
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
Voici la sortie:
+-----+---------+-------------------------------------------------------------------------------+
| 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))) |
+-----+---------+-------------------------------------------------------------------------------+
Notez que le polygone id = 3 partage un point avec id = 1 et est donc retourné comme résultat positif. Si je change la clause WHERE en ST_Touches( t1.geom, t2.geom ) AND t1.geom && t2.geom AND ST_Relate(t1.geom, t2.geom ,'T*T***T**');
je n'obtiens aucun enregistrement.
Donc, tout d' abord , comment spécifier ST_Relate pour vous assurer que seules les parcelles partageant un segment de ligne sont prises en compte.
Et puis, comment fusionnerais-je les polygones 1, 2, 3, 4 en un tour, en regroupant les résultats de l'appel ci-dessus, tout en reconnaissant que la contiguïté 1 à 2 est identique à l'inverse?
Mise à jour
Si j'ajoute ceci à la where
clause, je n'obtiens évidemment que des polygones et non des multipolygones, éliminant ainsi les faux positifs à mes fins - les touches de coin seront ignorées.
GeometryType(st_union(t1.geom,t2.geom)) != 'MULTIPOLYGON'
Bien que ce ne soit pas idéal (je préfère utiliser les vérifications de topologie avec ST_RELATE
comme solution plus générale), c'est une voie à suivre. Reste alors la question de leur déduplication et de leur union. Peut-être, si je pouvais générer une séquence pour que seuls les polygones se touchent, je pourrais l'union là-dessus.
Mise à jour II
Celui-ci semble fonctionner pour sélectionner des polygones partageant des lignes (mais pas des coins) et est donc une solution plus générale que le MULTIPOLYGON
test ci-dessus . Ma clause where ressemble maintenant à ceci:
WHERE
ST_Touches( t1.geom, t2.geom )
AND t1.geom && t2.geom
-- 'overlap' relation
AND ST_Relate(t1.geom, t2.geom)='FF2F11212') t2
Maintenant, ce qui reste est de savoir comment faire la fusion pour plus qu'une paire de polygones, mais pour un nombre arbitraire correspondant aux critères, en une seule fois.
ST_IntersectionArray
[fonction] [1] pour qu'elle fonctionne avec ST_Union [1]: gis.stackexchange.com/a/60295/36886