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/36886Respostas:
Não pude deixar de pensar que seu exemplo é realmente uma varredura e, embora você tenha mencionado que gostaria de mesclar com base em "certos critérios (pode ser o tamanho)", gostaria de tentar com uma conversão de varredura.
Para o seu exemplo específico, isso funcionaria:
O que acontece é que, uma vez que seus polígonos são células perfeitamente alinhadas, eles se convertem muito bem em uma varredura (tamanho de célula 10x20). Os dumpaspolygons ajudam você aqui, mesclando todas as células adjacentes em uma e comparando com os polígonos originais, você poderá recuperar o ID de polígonos não mesclados.
Tendo explicado isso, estou muito curioso sobre como isso seria dimensionado e qual o tamanho do seu conjunto de dados: D
fonte
Aqui está um exemplo de como fazer isso no estilo processual com várias passagens sob o capô.
Você deve poder carregar mais colunas e aplicar critérios extras para ingressar, modificando como a
LIMIT 1
seleção abaixo funciona:Execute a coisa:
Uniões apropriadas, sem multipolígonos:
fonte
Aqui está outra estratégia (que não está funcionando) para referência (que eu não conseguia excluir o caso de um único ponto de contato). Deve ser mais rápido do que minha outra resposta, pois leva apenas um passe.
(fique à vontade para alterar e postar outra resposta se alguém puder obter a geometria id = 5 em seu próprio grupo)
Para voltar à lista de IDs, etc., você precisaria
st_contains
voltar à tabela testpoly, conforme detalhado na resposta a seguir: /programming//a/37486732/6691, mas não consegui fazer isso funcionar por polígonos por algum motivo.fonte
Aqui está uma rápida facada nele usando sua consulta original ajustada um pouco:
Referências: https://postgis.net/docs/using_postgis_dbmanagement.html#DE-9IM
fonte