Створення розчиненого буфера з мультигеометрії (об'єднання спільним атрибутом та просторовим перетином)


10

Мені потрібно створити розчинені буфери з багатоточкових функцій введення. У наведеному нижче прикладі таблиця введення містить 4 функції. Особливість #2складається з двох точкових геометрій. Після створення буфера я отримую 4 геометрії багатокутника:

введіть тут опис зображення

Чи є спосіб згрупувати результат? Буфери точок #1і #2розчинилися і повинні бути єдиною багатокутною ознакою ( a).

Що я робив до цього часу:

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

Редагувати:

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

Ви занадто багато використовуєте підзапити. Це виключає вашу здатність до GROUP BY за атрибутом, на якому потрібно кластеризувати.
Вінс

Отже, вам потрібно зробити просторовий об'єднання, а потім і об'єднання на основі номера функції, саме тому ви очікуєте 3 мультиполігона від наведеної вище схеми. Я підозрюю, що для цього знадобиться двоетапний процес, але просто хотілося зрозуміти питання, перш ніж запропонувати відповідь.
Джон Пауелл

Так, я хочу об'єднати буферні полігони і зібрати результат, виходячи з кількості вхідних функцій.
eclipsed_by_the_moon

Будь-яке оновлення щодо цього? Я хотів би знати, чи працює це для вас, наскільки я бачу, я відповів на питання.
Джон Пауелл

Вибачте за пізню відповідь, я не був у мережі вже пару днів.
eclipsed_by_the_moon

Відповіді:


7

Починаючи з якихось випадкових точок, у посвідченні імітувати ті, на зображенні ОП, де перші два просторово перетинаються, потім 2-й та 3-й мають однаковий ідентифікаційний атрибут (2), з парою інших точок, які ні просторово не перетинаються, ні мають той же атрибут, наступний запит створює 3 кластери:

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;

Тут є кілька кроків:

  1. використання ST_Union, групування за id, до першої групи за атрибутом
  2. використовувати ST_ClusterIntersectingдля об'єднання тих, хто з однієї групи, які перетинаються просторово
  3. додайте ідентифікатор до кожного з кластерів (таблиця multis) - спроба зробити це безпосередньо в ClusterIntersecting призводить до того, що всі геометрії отримують ідентифікатор 1
  4. Об'єднайте геометрию, що скидається з кроку 2, групуючи за ідентифікатором з кроку 3 - це частина, що розпускається . Це призводить до того, що два полігони, що перекриваються у вашому кластері A, повинні бути з'єднані разом, а не перекриваються, як вони є в кінці кроку 2.

Досить довго, але це працює (і, я впевнений, є коротший шлях).

Використовуючи інструмент WKT в QGIS (і виявляючи, як мені страшно за допомогою інструментів редагування), створюються кластери на зразок наступного, де ви бачите кластер, позначений як ", - це все разом, тобто один колір.

введіть тут опис зображення

Якщо ви поставите ST_AsText навколо фіналу, ST_UNION (d.geom), то ви можете бачити результати безпосередньо.

ЗРЕДИТИ наступну інформацію в коментарях: Оскільки ви починаєте з пунктів, вам потрібно буде включити буфер у моє оригінальне рішення - яке я поставив у темп CTE на початку, щоб імітувати вашу діаграму. Простіше було б додати буфер до об'єднань CTE, так що ви можете робити всі геометрії одночасно. Отже, використовуючи буферну відстань 1000, як приклад, наступне тепер повертає 3 кластери, як очікувалося.

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;

Вибачте, що пройшло так довго, щоб повернутися до вас. У мене є проблеми з візуалізацією геометрії буфера в QGIS. Я спробував змінити ваш запит, використовуючи ST_SetSRID, ST_Multiі ::geometry(Multipolygon, /*SRID*/), але на даний момент він не працює.
eclipsed_by_the_moon

Гаразд, якщо ви можете опублікувати свій код, а ще краще деякі дані, я можу допомогти.
Джон Пауелл

Я додав кілька SQL для створення вибіркових очок.
eclipsed_by_the_moon

Трохи зав’язаний сьогодні, я повернуся, як тільки зможу. До запиту також доведеться попрацювати багатоточку.
Джон Пауелл

3

Один із способів зробити це - ST_Unionвсі буфери разом, ST_Dumpрезультат - отримати компоненти результуючого багатокутника і з'єднатися ST_Intersectsназад до вхідних точок, щоб дізнатися, скільки / які точки складають кожен кластер.

Це можна зробити, не вимагаючи приєднання, групуючи точки разом перед викликом ST_Buffer. Для того, щоб дві точки розташовувалися в межах одного розчиненого буфера, вони повинні бути доступними стрибками між точками відстані менше eps. Це лише проблема кластеризації мінімальних зв'язків, яку можна вирішити, використовуючи 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;

Зауважте, що це не дасть абсолютно такого ж результату, як буфер-перший метод, оскільки буфери PostGIS не є ідеальними колами, а дві точки, розташовані на відстані 1000 м, не можуть бути з'єднані двома 500-метровими буферами.


Здається, у нас була схожа ідея. Я не перевіряв вашу, але я впевнений, що вона працює, і більш чисто, ніж моя.
Джон Пауелл

Схоже, PostGIS 2.2.1 не підтримує ST_ClusterDBSCAN. Я встановив PostGIS 2.3.2, але нові розширення postgis у pgAdmin все ще є версією 2.2.1.
eclipsed_by_the_moon

0

Відповідно до цієї відповіді, ви хочете зробити ST_DUMP у своєму підзапиті.

Щось на зразок цього:

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

Причина полягає в тому, що ST_UNIONповертає розчинений багатополігон усіх ознак і ST_DUMPрозбиває їх на окремі ознаки багатокутника (які були розпущені).


1
Насправді це не спрацює, оскільки будь-які атрибути, необхідні для кластеризації бажаного багаточастинного багатокутника, будуть втрачені.
Вінс

Я намагався ST_Multi((ST_Dump(ST_Union(ST_Buffer(geom, 1000, 8)))).geom)::geometry(MultiPolygon, /*SRID*/) AS geom, але це створює 4 функції замість 3.
eclipsed_by_the_moon

О, так, ви хочете згрупуватися за номером? Вам потрібно буде GROUP_BYперед вами ST_UNION.
Алекс Лейт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.