Crea buffer dissolto da multi-geometria (Unione per attributo condiviso e intersezione spaziale)


10

Devo creare buffer disciolti dalle funzionalità di input multipunto. Nell'esempio seguente, la tabella di input contiene 4 funzionalità. La funzione è #2composta da due geometrie puntiformi. Dopo aver creato un buffer, ottengo 4 geometrie poligonali:

inserisci qui la descrizione dell'immagine

C'è un modo per raggruppare il risultato? I buffer dei punti #1e #2sono dissolti e dovrebbero essere una singola funzione multi-poligono ( a).

Quello che ho fatto finora:

-- 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;

MODIFICARE:

-- 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));

Usi troppe query. Ciò elimina la tua capacità di Raggruppare per l'attributo su cui vuoi raggruppare.
Vince il

Quindi devi fare un'unione spaziale e poi anche un'unione basata sul numero di funzione, motivo per cui ti aspetti 3 multipoligoni dal diagramma sopra. Sospetto che ciò richiederà un processo in due fasi, ma volevo solo essere chiaro sulla domanda, prima di offrire una risposta.
John Powell,

Sì, voglio unire i poligoni del buffer e raccogliere il risultato in base al numero delle funzionalità di input.
eclipsed_by_the_moon il

Qualche aggiornamento a questo proposito? Vorrei sapere se questo funziona per te, per quanto posso vedere, ho risposto alla domanda.
John Powell,

Ci scusiamo per la risposta tardiva, non sono online da un paio di giorni.
eclipsed_by_the_moon

Risposte:


7

A partire da alcuni punti casuali, in un atteggiamento di imitazione di quelli nell'immagine del PO, in cui i primi due si intersecano spazialmente, quindi il 2 ° e il 3 ° hanno lo stesso attributo id (2), con un paio di altri punti che non si intersecano né spazialmente né hanno lo stesso attributo, la seguente query produce 3 cluster:

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;

Ci sono diversi passaggi qui:

  1. utilizzare ST_Union, raggruppando per ID, per primo gruppo per attributo
  2. usare ST_ClusterIntersectingper combinare quelli dello stesso gruppo che si intersecano nello spazio
  3. aggiungi un id a ciascuno dei cluster (tabella multis) - provando a farlo direttamente in ClusterIntersecting porta tutte le geometrie a ottenere un id di 1
  4. Unisci le geometrie scaricate dal passaggio 2, raggruppando per l'id dal passaggio 3: questa è la parte dissolta . Questo fa sì che i due poligoni sovrapposti nel cluster A vengano uniti, anziché essere sovrapposti, come si trovano alla fine del passaggio 2.

Piuttosto a lungo, ma funziona (e, sono sicuro che c'è un modo più breve).

L'uso dello strumento WKT in QGIS (e scoprire quanto sono terribile con gli strumenti di modifica) produce cluster come il seguente, in cui puoi vedere il cluster etichettato come un, è tutto insieme - cioè, un colore.

inserisci qui la descrizione dell'immagine

Se aggiungi un testo ST_AsText alla finale, ST_UNION (d.geom), puoi vedere direttamente i risultati.

MODIFICA seguendo ulteriori informazioni nei commenti: Poiché inizi con i punti, dovrai incorporare il buffer nella mia soluzione originale, che ho inserito nel CTE temporaneo all'inizio per imitare il diagramma. Sarebbe più semplice aggiungere il buffer nel CTE dei sindacati, in modo da poter eseguire tutte le geometrie contemporaneamente. Quindi, usando una distanza del buffer di 1000, come esempio, il seguente ora restituisce 3 cluster, come previsto.

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;

Mi dispiace che ci sia voluto tanto tempo per risponderti. Ho qualche problema a visualizzare le geometrie del buffer in QGIS. Ho cercato di modificare la query utilizzando ST_SetSRID, ST_Multie ::geometry(Multipolygon, /*SRID*/), ma al momento non sta funzionando.
eclipsed_by_the_moon

OK, se riesci a pubblicare il tuo codice, e ancora meglio alcuni dati, potrei essere in grado di aiutarti.
John Powell,

Ho aggiunto un po 'di SQL per creare punti di esempio.
eclipsed_by_the_moon

Un po 'legato oggi, tornerò appena posso. Dovrà lavorare anche il multipunto nella query.
John Powell

3

Un modo per farlo è quello ST_Uniondi riunire tutti i buffer, ST_Dumpil risultato per ottenere i componenti del poligono risultante e unire ST_Intersectsnuovamente i punti di input per scoprire quanti / quali punti costituivano ciascun cluster.

Questo può essere fatto senza richiedere un join raggruppando i punti insieme prima di chiamare ST_Buffer. Affinché due punti si trovino all'interno dello stesso buffer disciolto, devono essere raggiungibili con salti tra punti di una distanza inferiore a eps. Questo è solo un problema di clustering con collegamento minimo, che può essere risolto 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;

Si noti che questo non produrrà esattamente lo stesso risultato del metodo buffer-first, poiché i buffer PostGIS non sono cerchi perfetti e due punti distanti 1000 m potrebbero non essere collegati da due buffer da 500 m.


Sembra che abbiamo avuto un'idea simile. Non ho testato il tuo, ma sono sicuro che funzioni e in modo più pulito del mio.
John Powell,

Sembra che PostGIS 2.2.1 non supporti ST_ClusterDBSCAN. Ho installato PostGIS 2.3.2, ma le nuove estensioni postgis in pgAdmin sono ancora la versione 2.2.1.
eclipsed_by_the_moon

0

Secondo questa risposta , vuoi fare ST_DUMP nella tua subquery.

Qualcosa come questo:

-- 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;

Il motivo è che ST_UNIONrestituisce un multipoligono disciolto di tutte le funzioni e lo ST_DUMPsuddivide nelle singole funzioni poligonali (che sono state sciolte).


1
In realtà non funzionerà, perché tutti gli attributi che sarebbero necessari per raggruppare il poligono multipart desiderato saranno andati persi.
Vince il

Ci ho provato ST_Multi((ST_Dump(ST_Union(ST_Buffer(geom, 1000, 8)))).geom)::geometry(MultiPolygon, /*SRID*/) AS geom, ma questo crea 4 funzioni invece di 3.
eclipsed_by_the_moon il

Oh, giusto, vuoi raggruppare per il numero? Dovrai GROUP_BYprima di te ST_UNION.
Alex Leith,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.