Utwórz rozpuszczony bufor z wielu geometrii (Unia przez wspólny atrybut i przecięcie przestrzenne)


10

Muszę tworzyć rozpuszczone bufory z funkcji wprowadzania wielopunktowego. W poniższym przykładzie tabela wprowadzania zawiera 4 funkcje. Obiekt #2składa się z dwóch geometrii punktowych. Po utworzeniu bufora otrzymuję 4 geometrie wielokątów:

wprowadź opis zdjęcia tutaj

Czy istnieje sposób na pogrupowanie wyniku? Bufory punktów #1i #2są rozpuszczone i powinny być pojedynczą funkcją wielokąta ( a).

Co zrobiłem do tej pory:

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

EDYTOWAĆ:

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

Zbyt często używasz podkwerend. Eliminuje to twoją możliwość grupowania według atrybutu, na którym chcesz utworzyć klaster.
Vince

Musisz więc wykonać połączenie przestrzenne, a następnie połączenie na podstawie numeru cechy, dlatego oczekujesz 3 multipoligonów z powyższego schematu. Podejrzewam, że będzie to wymagało dwuetapowego procesu, ale chciałem tylko wyjaśnić pytanie, zanim zaoferuję odpowiedź.
John Powell,

Tak, chcę połączyć wieloboki bufora i zebrać wynik na podstawie liczby funkcji wejściowych.
eclipsed_by_the_moon

Czy to ma jakieś aktualizacje? Chciałbym wiedzieć, czy to dla ciebie działa, o ile widzę, odpowiedziałem na pytanie.
John Powell,

Przepraszam za spóźnioną odpowiedź, nie byłem online przez kilka dni.
eclipsed_by_the_moon

Odpowiedzi:


7

Zaczynając od kilku losowych punktów, w celu naśladowania tych na obrazie PO, gdzie pierwsze dwa przestrzennie przecinają się, następnie drugi i trzeci mają ten sam atrybut id (2), z kilkoma innymi punktami, które ani przecinają się przestrzennie, ani nie mają ten sam atrybut, następujące zapytanie tworzy 3 klastry:

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;

Tutaj jest kilka kroków:

  1. użyj ST_Union, pogrupuj według identyfikatora, aby najpierw pogrupować według atrybutu
  2. Użyj, ST_ClusterIntersectingaby połączyć te z tej samej grupy, które przecinają się przestrzennie
  3. dodaj identyfikator do każdego z klastrów (tabela multis) - próba zrobienia tego bezpośrednio w ClusterIntersecting prowadzi do uzyskania przez wszystkie geometrie id 1
  4. Połącz zrzucone geometrie z kroku 2, grupując według id z kroku 3 - jest to część rozpuszczania . Powoduje to, że dwa nakładające się wielokąty w klastrze A łączą się ze sobą, zamiast się nakładać, ponieważ znajdują się na końcu kroku 2.

Dość długo, ale działa (i jestem pewien, że jest krótsza droga).

Za pomocą narzędzia WKT w QGIS (i odkrywając, jak okropnie jestem z narzędziami do edycji), powstają klastry takie jak poniżej, w których widać klaster oznaczony jako a, wszystko razem - tzn. Jeden kolor.

wprowadź opis zdjęcia tutaj

Jeśli umieścisz ST_AsText w finale, ST_UNION (d.geom), możesz zobaczyć wyniki bezpośrednio.

EDYTUJ następujące informacje w komentarzach: Gdy zaczynasz od punktów, musisz włączyć bufor do mojego oryginalnego rozwiązania - które umieszczam w temp CTE na początku, aby naśladować twój schemat. Łatwiej byłoby dodać bufor w związkach CTE, dzięki czemu można wykonywać wszystkie geometrie jednocześnie. Tak więc, przykładowo, używając odległości bufora 1000, teraz zwraca 3 klastry, zgodnie z oczekiwaniami.

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;

Przepraszam, że tyle czasu zajęło mi skontaktowanie się z Tobą. Mam problem z wizualizacją geometrii buforów w QGIS. Próbowałem zmodyfikować zapytanie użyciu ST_SetSRID, ST_Multia ::geometry(Multipolygon, /*SRID*/), ale w tej chwili nie działa.
eclipsed_by_the_moon

OK, jeśli możesz opublikować swój kod, a jeszcze lepiej niektóre dane, mogę pomóc.
John Powell,

Dodałem trochę SQL, aby utworzyć przykładowe punkty.
eclipsed_by_the_moon

Trochę dziś związany, wrócę tak szybko, jak to możliwe. Będzie musiał również wprowadzić wielopunkt do zapytania.
John Powell,

3

Jednym ze sposobów, aby to zrobić, jest połączenie ST_Unionwszystkich buforów razem, ST_Dumpaby uzyskać składniki wynikowego wielokąta i połączyć się z ST_Intersectspowrotem z punktami wejściowymi, aby dowiedzieć się, ile / które punkty tworzyły każdy klaster.

Można to zrobić bez konieczności łączenia, grupując punkty przed połączeniem ST_Buffer. Aby dwa punkty znajdowały się w tym samym rozpuszczonym buforze, muszą być osiągalne przez przeskok między punktami na odległość mniejszą niż eps. Jest to tylko problem klastrowania minimalnego powiązania, który można rozwiązać za pomocą 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;

Zauważ, że nie da to dokładnie takiego samego wyniku, jak metoda polegająca na pierwszym buforowaniu, ponieważ bufory PostGIS nie są idealnymi okręgami, a dwa punkty w odległości 1000 m nie mogą być połączone dwoma buforami 500m.


Wygląda na to, że mieliśmy podobny pomysł. Nie testowałem twojego, ale jestem pewien, że to działa i jest czystsze niż moje.
John Powell

Wygląda na to, że PostGIS 2.2.1 nie obsługuje ST_ClusterDBSCAN. Zainstalowałem PostGIS 2.3.2, ale nowe rozszerzenia postgis w pgAdmin są nadal w wersji 2.2.1.
eclipsed_by_the_moon

0

Zgodnie z tą odpowiedzią chcesz wykonać ST_DUMP w swoim podzapytaniu.

Coś takiego:

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

Powodem tego jest to, że ST_UNIONzwraca rozpuszczony ST_DUMPwielobok wszystkich cech i dzieli je na poszczególne cechy wielokąta (które zostały rozwiązane).


1
To faktycznie nie zadziała, ponieważ wszelkie atrybuty, które byłyby potrzebne do klastrowania pożądanego wielokąta wieloczęściowego, zostaną utracone.
Vince

Próbowałem ST_Multi((ST_Dump(ST_Union(ST_Buffer(geom, 1000, 8)))).geom)::geometry(MultiPolygon, /*SRID*/) AS geom, ale powoduje to utworzenie 4 funkcji zamiast 3.
eclipsed_by_the_moon

Och, prawda, chcesz pogrupować według numeru? Musisz to zrobić GROUP_BYprzed sobą ST_UNION.
Alex Leith
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.