Eu gostaria de fazer testes de adjacência em uma camada de parcelas (polígonos) e mesclá-los se eles se encaixarem em determinados critérios (pode ser o tamanho). Conforme a figura abaixo, eu gostaria de mesclar polígonos 1,2,3 e 4, mas não 5.
Eu tenho dois problemas:
ST_TOUCHES
retorna VERDADEIRO se apenas os cantos tocarem e não um segmento de linha. Acho que preciso ST_RELATE para verificar segmentos de linha compartilhados.- Idealmente, eu gostaria de mesclar TODOS os polígonos adjacentes em um, mas não sei como escalar além de dois - como em, mesclar 1,2,3 e 4 (e possivelmente mais em dados reais) em uma rodada.
A estrutura que tenho agora é baseada em uma auto-junção ST_TOUCHES
.
Dados do brinquedo
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 ;
Seleção
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
Aqui está a saída:
+-----+---------+-------------------------------------------------------------------------------+
| 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))) |
+-----+---------+-------------------------------------------------------------------------------+
Observe que o id do polígono = 3 compartilha um ponto com o id = 1 e, portanto, é retornado como um resultado positivo. Se eu alterar a cláusula WHERE para ST_Touches( t1.geom, t2.geom ) AND t1.geom && t2.geom AND ST_Relate(t1.geom, t2.geom ,'T*T***T**');
não obter nenhum registro.
Então , primeiro , como faço para especificar ST_Relate para garantir que apenas os pacotes que compartilham um segmento de linha sejam considerados.
E então, como eu mesclaria polígonos 1,2,3,4 em uma rodada, recolhendo os resultados da chamada acima, reconhecendo o tempo todo que a adjacência 1 a 2 é a mesma do inverso?
Atualizar
Se eu adicionar isso à where
cláusula, obviamente obtenho apenas polígonos e não multipolígonos, eliminando assim falsos positivos para meus propósitos - os toques nos cantos serão ignorados.
GeometryType(st_union(t1.geom,t2.geom)) != 'MULTIPOLYGON'
Embora isso não seja o ideal (prefiro usar verificações de topologia ST_RELATE
como uma solução mais geral), é um caminho a seguir. Resta, então, a questão de enganar e uni-los. Possivelmente, se eu pudesse gerar uma sequência apenas para tocar polígonos, eu poderia se unir a isso.
Atualização II
Este parece funcionar para selecionar polígonos que compartilham linhas (mas não cantos) e, portanto, é uma solução mais geral que o MULTIPOLYGON
teste acima . Minha cláusula where agora se parece com isso:
WHERE
ST_Touches( t1.geom, t2.geom )
AND t1.geom && t2.geom
-- 'overlap' relation
AND ST_Relate(t1.geom, t2.geom)='FF2F11212') t2
Agora, o que resta ainda é como fazer a mesclagem para mais do que apenas um par de polígonos, mas para um número arbitrário que atenda aos critérios, de uma só vez.
ST_IntersectionArray
[função] [1] para o trabalho com ST_Union [1]: gis.stackexchange.com/a/60295/36886