Criar buffer dissolvido a partir de multi-geometria (União por atributo compartilhado e interseção espacial)

10

Eu tenho que criar buffers dissolvidos a partir de recursos de entrada multiponto. No exemplo abaixo, a tabela de entrada contém 4 recursos. O recurso #2consiste em duas geometrias de pontos. Depois de criar um buffer, recebo 4 geometrias de polígono:

insira a descrição da imagem aqui

Existe uma maneira de agrupar o resultado? Os buffers dos pontos #1e #2são dissolvidos, e deverá ser uma única característica multi-polígono ( a).

O que eu fiz até agora:

-- collect all buffers to a single multi-polygon feature
-- dissolve overlapping polygon geometries
CREATE TABLE public.pg_multibuffer AS SELECT
    row_number() over() AS gid,
    sub_qry.*
FROM (SELECT
    ST_Union(ST_Buffer(geom, 1000, 8))::geometry(MultiPolygon, /*SRID*/) AS geom
FROM
public.multipoints)
AS sub_qry;

EDITAR:

-- create sample geometries

CREATE TABLE public.multipoints (
gid serial NOT NULL,
geom geometry(MultiPoint, 31256),
CONSTRAINT multipoints_pkey PRIMARY KEY (gid)
);

CREATE INDEX sidx_multipoints_geom
ON public.multipoints
USING gist
(geom);

INSERT INTO public.multipoints (gid, geom) VALUES
(1, ST_SetSRID(ST_GeomFromText('MultiPoint(12370 361685)'), 31256)),
(2, ST_SetSRID(ST_GeomFromText('MultiPoint(13520 360880, 19325 364350)'), 31256)),
(3, ST_SetSRID(ST_GeomFromText('MultiPoint(11785 367775)'), 31256)),
(4, ST_SetSRID(ST_GeomFromText('MultiPoint(19525 356305)'), 31256));
eclipsed_by_the_moon
fonte
Você usa subconsultas demais. Isso elimina sua capacidade de GROUP BY no atributo no qual você deseja agrupar.
Vince
Então, você precisa fazer uma união espacial e também uma união com base no número do recurso, e é por isso que você espera três multipolígonos no diagrama acima. Suspeito que isso exija um processo de duas etapas, mas só quero esclarecer a questão antes de oferecer uma resposta.
John Powell
Sim, quero unir os polígonos do buffer e coletar o resultado com base no número dos recursos de entrada.
eclipsed_by_the_moon
alguma atualização disso? Gostaria de saber se isso funciona para você. Até onde posso ver, respondi à pergunta.
John Powell
Desculpe pela resposta tardia, não estou online há alguns dias.
eclipsed_by_the_moon

Respostas:

7

Começando com alguns pontos aleatórios, em uma tentativa de imitar aqueles na imagem do OP, onde os dois primeiros se cruzam espacialmente, o segundo e o terceiro têm o mesmo atributo id (2), com alguns outros pontos que não se cruzam nem têm o mesmo atributo, a seguinte consulta produz 3 clusters:

WITH 
  temp (id, geom) AS 
     (VALUES (1, ST_Buffer(ST_Makepoint(0, 0), 2)),
        (2, ST_Buffer(ST_MakePoint(-0.7,0.5), 2)),
        (2, ST_Buffer(ST_MakePoint(10, 10), 2)), 
        (3, ST_Buffer(ST_MakePoint(-2, 12), 2)), 
        (4, ST_Buffer(ST_MakePoint(5, -6), 2))),
 unions(geoms) AS 
      (SELECT ST_Union(geom) FROM temp GROUP BY id),
 clusters(geoms) AS 
      (SELECT ST_CollectionExtract(unnest(ST_ClusterIntersecting(geoms)), 3) 
         FROM unions),
 multis(id, geoms) AS 
      (SELECT row_number() over() as id, geoms FROM clusters)
 SELECT ST_UNION(d.geom) FROM 
      (SELECT id, (ST_DUMP(geoms)).geom FROM multis) d GROUP BY id;

Existem várias etapas aqui:

  1. use ST_Union, agrupando por ID, para agrupar primeiro por atributo
  2. use ST_ClusterIntersectingpara combinar aqueles do mesmo grupo que se cruzam espacialmente
  3. adicione um ID a cada um dos clusters (tabela multis) - tentar fazer isso diretamente no ClusterIntersecting leva todas as geometrias a obter um ID de 1
  4. Unir as geometrias despejadas da etapa 2, agrupando pelo ID da etapa 3 - esta é a parte de dissolução . Isso faz com que os dois polígonos sobrepostos no cluster A sejam unidos, em vez de sobrepostos, pois estão no final da etapa 2.

Bastante longo, mas funciona (e, tenho certeza, há um caminho mais curto).

O uso da ferramenta WKT no QGIS (e a descoberta do quão péssimo sou com as ferramentas de edição) produz agrupamentos como os seguintes, onde você pode ver o agrupamento rotulado como a, todos juntos - ou seja, uma cor.

insira a descrição da imagem aqui

Se você colocar um ST_AsText na final, ST_UNION (d.geom), poderá ver os resultados diretamente.

EDITE seguindo mais informações nos comentários: Como você está começando com os pontos, precisará incorporar o buffer na minha solução original - que eu coloquei no temp CTE no início para imitar seu diagrama. Seria mais fácil adicionar o buffer nos uniões CTE, para que você possa fazer todas as geometrias de uma só vez. Portanto, usando uma distância do buffer de 1000, como exemplo, o seguinte agora retorna 3 clusters, conforme o esperado.

WITH temp(id, geom) AS 
  (VALUES 
      (1, ST_SetSRID(ST_GeomFromText('MultiPoint(12370 361685)'), 31256)),   
      (2, ST_SetSRID(ST_GeomFromText('MultiPoint(13520 360880, 19325 364350)'), 31256)),                                                
      (3, ST_SetSRID(ST_GeomFromText('MultiPoint(11785 367775)'), 31256)),
      (4, ST_SetSRID(ST_GeomFromText('MultiPoint(19525 356305)'), 31256))
),                                              
unions(geoms) AS 
  (SELECT st_buffer(ST_Union(geom), 1000) FROM temp GROUP BY id),
clusters(geoms) AS 
  (SELECT ST_CollectionExtract(unnest(ST_ClusterIntersecting(geoms)), 3) 
     FROM unions),
multis(id, geoms) AS 
  (SELECT row_number() over() as id, geoms FROM clusters)
SELECT id, ST_UNION(d.geom) FROM 
  (SELECT id, (ST_DUMP(geoms)).geom FROM multis) d GROUP BY id;
John Powell
fonte
Desculpe, demorou tanto tempo para voltar para você. Estou com alguns problemas para visualizar as geometrias do buffer no QGIS. Eu tentei modificar sua consulta usando ST_SetSRID, ST_Multie ::geometry(Multipolygon, /*SRID*/), mas no momento não está funcionando.
eclipsed_by_the_moon
OK, se você puder postar seu código e, ainda melhor, alguns dados, talvez eu possa ajudar.
John Powell #
Eu adicionei um pouco de SQL para criar pontos de amostra.
eclipsed_by_the_moon
Um pouco amarrado hoje, vou reverter o mais rápido possível. Também terá que trabalhar o multiponto na consulta.
John
3

Uma maneira de fazer isso é ST_Unionreunir todos os buffers, ST_Dumpo resultado para obter os componentes do polígono resultante e juntar ST_Intersects-se aos pontos de entrada para descobrir quantos / quais pontos compunham cada cluster.

Isso pode ser feito sem a necessidade de uma junção, agrupando os pontos antes da chamada ST_Buffer. Para que dois pontos sejam localizados no mesmo buffer dissolvido, eles devem ser alcançados por saltos entre pontos com uma distância menor que eps. Este é apenas um problema de agrupamento de ligação mínima, que pode ser resolvido usando ST_ClusterDBSCAN:

SELECT
  cluster_id,
  ST_Union(ST_Buffer(geom, 1000)) AS geom,
  count(*)                        AS num_points,
  array_agg(point_id)             AS point_ids
FROM (
  SELECT
    point_id,
    ST_ClusterDBSCAN(geom, eps := 2000, minpoints := 1) OVER() AS cluster_id ,
    geom
  FROM points) sq
 GROUP BY cluster_id;

Observe que isso não produzirá exatamente o mesmo resultado que o método buffer-first, porque os buffers PostGIS não são círculos perfeitos e dois pontos a 1000m de distância podem não estar conectados por dois buffers de 500m.

dbaston
fonte
Parece que tivemos uma ideia semelhante. Não testei o seu, mas tenho certeza de que funciona e de forma mais limpa que a minha.
John Powell
Parece que o PostGIS 2.2.1 não suporta ST_ClusterDBSCAN. Instalei o PostGIS 2.3.2, mas as novas extensões do postgis no pgAdmin ainda são a versão 2.2.1.
eclipsed_by_the_moon
0

De acordo com esta resposta, você deseja executar ST_DUMP em sua subconsulta.

Algo assim:

-- collect all buffers to a single multi-polygon feature
-- dissolve overlapping polygon geometries
CREATE TABLE public.pg_multibuffer AS SELECT
    row_number() over() AS gid,
    sub_qry.*
FROM (SELECT
    ST_Dump(ST_Union(ST_Buffer(geom, 1000, 8))::geometry(MultiPolygon, /*SRID*/)) AS geom
FROM
public.multipoints)
AS sub_qry;

A razão disso é que ST_UNIONretorna um multipolígono dissolvido de todos os recursos e ST_DUMPdivide isso nos recursos poligonais individuais (que foram dissolvidos).

Alex Leith
fonte
1
Na verdade, isso não funcionará, porque quaisquer atributos que seriam necessários para agrupar o polígono de várias partes desejado serão perdidos.
Vince
Eu tentei ST_Multi((ST_Dump(ST_Union(ST_Buffer(geom, 1000, 8)))).geom)::geometry(MultiPolygon, /*SRID*/) AS geom, mas isso cria 4 recursos em vez de 3. #
26917
Ah, certo, você quer agrupar pelo número? Você precisará GROUP_BYantes de você ST_UNION.
Alex Leith