Buat buffer terlarut dari multi-geometri (Persatuan dengan atribut bersama dan persimpangan spasial)

10

Saya sudah membuat buffer terlarut dari fitur input multi-point. Dalam contoh di bawah ini, tabel input berisi 4 fitur. Fitur #2terdiri dari dua titik geometri. Setelah membuat buffer, saya mendapatkan 4 geometri poligon:

masukkan deskripsi gambar di sini

Apakah ada cara untuk mengelompokkan hasilnya? Buffer titik #1dan #2dilarutkan dan harus menjadi fitur multi-poligon tunggal ( a).

Apa yang telah saya lakukan sejauh ini:

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

EDIT:

-- 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
sumber
Anda menggunakan terlalu banyak subkueri. Ini menghilangkan kemampuan Anda untuk GROUP BY pada atribut yang ingin Anda klaster.
Vince
Jadi Anda perlu melakukan penyatuan spasial dan kemudian juga penyatuan berdasarkan nomor fitur, itulah sebabnya Anda mengharapkan 3 multipoligon dari diagram di atas. Saya menduga ini akan membutuhkan proses dua langkah, tetapi hanya ingin menjelaskan pertanyaannya, sebelum menawarkan jawaban.
John Powell
Ya, saya ingin menyatukan poligon penyangga dan mengumpulkan hasilnya berdasarkan jumlah fitur input.
eclipsed_by_the_moon
Adakah pembaruan tentang ini? Saya ingin tahu apakah ini bekerja untuk Anda, sejauh yang saya bisa lihat, saya telah menjawab pertanyaan itu.
John Powell
Maaf atas jawaban yang terlambat, saya belum online selama beberapa hari.
eclipsed_by_the_moon

Jawaban:

7

Dimulai dengan beberapa titik acak, dalam upaya meniru orang-orang di gambar OP, di mana dua spasial pertama berpotongan, kemudian ke-2 dan ke-3 memiliki atribut id yang sama (2), dengan beberapa titik lain yang tidak berpotongan secara spasial atau memiliki atribut yang sama, permintaan berikut menghasilkan 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;

Ada beberapa langkah di sini:

  1. gunakan ST_Union, pengelompokan berdasarkan id, ke grup pertama berdasarkan atribut
  2. gunakan ST_ClusterIntersectinguntuk menggabungkan mereka dari kelompok yang sama yang bersinggungan secara spasial
  3. tambahkan id ke masing-masing cluster (tabel multis) - mencoba melakukan ini secara langsung di mengarah ClusterIntersecting ke semua geometri mendapatkan id 1
  4. Menyatukan geometri yang dibuang dari langkah 2, pengelompokan berdasarkan id dari langkah 3 - ini adalah bagian terlarut . Ini menyebabkan dua poligon yang tumpang tindih di gugus A Anda, untuk digabungkan bersama, bukannya tumpang tindih, karena mereka berada di akhir langkah 2.

Agak panjang, tapi berhasil (dan, saya yakin ada jalan yang lebih pendek).

Menggunakan alat WKT di QGIS, (dan menemukan betapa buruknya saya dengan alat pengeditan) menghasilkan cluster seperti berikut, di mana Anda dapat melihat cluster yang Anda beri label sebagai, semuanya bersama-sama - yaitu satu warna.

masukkan deskripsi gambar di sini

Jika Anda meletakkan ST_AsText di babak final, ST_UNION (d.geom), maka Anda dapat melihat hasilnya secara langsung.

Sunting berikut informasi lebih lanjut di komentar: Ketika Anda mulai dengan poin Anda akan perlu memasukkan buffer ke dalam solusi asli saya - yang saya masukkan ke dalam CTE temp di awal untuk meniru diagram Anda. Akan lebih mudah untuk menambahkan buffer di CTE serikat pekerja, sehingga Anda dapat melakukan semua geometri sekaligus. Jadi, dengan menggunakan jarak buffer 1000, sebagai contoh, yang berikut sekarang mengembalikan 3 cluster, seperti yang diharapkan.

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
sumber
Maaf butuh waktu lama untuk kembali kepada Anda. Saya memiliki beberapa masalah untuk memvisualisasikan geometri buffer di QGIS. Saya telah mencoba mengubah kueri Anda menggunakan ST_SetSRID, ST_Multidan ::geometry(Multipolygon, /*SRID*/), tetapi saat ini tidak berfungsi.
eclipsed_by_the_moon
OK, jika Anda dapat memposting kode Anda, dan bahkan beberapa data yang lebih baik, saya mungkin bisa membantu.
John Powell
Saya telah menambahkan beberapa SQL untuk membuat titik sampel.
eclipsed_by_the_moon
Agak diikat hari ini, saya akan kembali secepatnya. Harus mengerjakan multipoint ke dalam kueri juga.
John Powell
3

Salah satu cara untuk melakukan ini adalah untuk ST_Unionsemua buffer bersama-sama, ST_Dumphasil untuk mendapatkan komponen dari poligon yang dihasilkan, dan bergabung dengan ST_Intersectskembali ke titik input untuk menemukan berapa banyak / poin mana yang membentuk setiap cluster.

Ini bisa dilakukan tanpa perlu bergabung dengan mengelompokkan poin bersama sebelum menelepon ST_Buffer. Untuk dua titik yang terletak di dalam buffer terlarut yang sama, mereka harus dapat dicapai dengan melompat antara titik-titik yang jaraknya kurang dari eps. Ini hanya masalah pengelompokan tautan minimum, yang dapat diselesaikan menggunakan 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;

Perhatikan bahwa ini tidak akan menghasilkan hasil yang sama persis dengan metode buffer-first, karena buffer PostGIS tidak lingkaran sempurna dan terpisah dua poin 1000m mungkin tidak terhubung oleh dua buffer 500m.

dbaston
sumber
Sepertinya kami punya ide serupa. Saya belum menguji milik Anda, tetapi saya yakin itu berhasil, dan lebih bersih dari milik saya.
John Powell
Tampaknya PostGIS 2.2.1 tidak mendukung ST_ClusterDBSCAN. Saya telah menginstal PostGIS 2.3.2, tetapi ekstensi postgis baru di pgAdmin masih versi 2.2.1.
eclipsed_by_the_moon
0

Menurut jawaban ini, Anda ingin melakukan ST_DUMP dalam subquery Anda.

Sesuatu seperti ini:

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

Alasan mengapa hal itu ST_UNIONmengembalikan multipoligon terlarut dari semua fitur, dan ST_DUMPmemecah ini menjadi fitur poligon individu (yang dibubarkan).

Alex Leith
sumber
1
Ini tidak akan berhasil, karena atribut apa pun yang diperlukan untuk mengelompokkan poligon multi-bagian yang diinginkan akan hilang.
Vince
Saya sudah mencoba ST_Multi((ST_Dump(ST_Union(ST_Buffer(geom, 1000, 8)))).geom)::geometry(MultiPolygon, /*SRID*/) AS geom, tetapi ini membuat 4 fitur bukannya 3.
eclipsed_by_the_moon
Oh, benar, Anda ingin mengelompokkan berdasarkan nomor? Anda harus melakukannya GROUP_BYsebelum Anda ST_UNION.
Alex Leith