Twórz mozaiki, takie jak Diagram Voronoi, z rozłącznych wielokątów


12

Poniższa ilustracja pokazuje problem :

wprowadź opis zdjęcia tutaj

jak w (a) Mam zestaw rozłącznych wielokątów, takich jak geometrie w PostGIS. Potrzebuję czegoś w rodzaju (b) , „mozaiki” tego zestawu wielokątów, budując ją według kryteriów „regionu wpływu” ... Jest jak konstrukcja Voronoi (zilustrowana przez (c) ): w rzeczywistości, jeśli wielokąty były punkty, regiony wpływu to Voronoi.

Podsumowując: Potrzebuję algorytmu SQL (lub jakiegoś specyficznego dla PostGIS), który generuje „mozaikę” zestawu rozłącznych wielokątów. (być może pętla małych operacji ST_Buffer i ST_Difference)

PS: Potrzebuję, podobnie jak Voronoi, aby delimitacja przestrzeni (kwadratowa ramka w (b) ) była ignorowana.


Ten problem jest podobny do tego dotyczącego linii .

EDYCJA (po komentarzu @FelixIP)

Wolę pozostać we wszechświecie wektorowym , aby nie stracić precyzji (np. Używając ST_DelaunayTriangles oraz dodając i odejmując wnętrza według oryginalnych wielokątów, dostosowując rozwiązanie do podwójnego wykresu ) ... Niektóre proste i automatyczne pakiety, takie jak pprepair (wspomagane jak narzędzia topologiczne QGIS nie są automatyczne). Ale raster jest być może prostszy i wymaga mniej procesora.

Ta ilustracja „procesu GRID” jest również słuszna jako rozwiązanie, zakładając, że może ona pozwolić na taką samą precyzję i „wzrost regionu wpływów euklidesowych”.

wprowadź opis zdjęcia tutaj

W ARCGIS istnieje narzędzie analizy przestrzennej znane jako alokacja euklidesowa , więc być może istnieje podobne rozwiązanie PostGIS , zaczynające się od zestawu wielokątów (klasyfikowanie, rasteryzacja i odzyskiwanie wielokątów).


Dzięki @Nir, przepraszam za pomyłkę z punktami, nie używam punktów, tylko wielokąty jako elementy (a) i (b) ilustracji ... Czy masz link do swojej wskazówki na temat rozwiązania?
Peter Krauss,

W Arcgis istnieje rozwiązanie rastrowe zwane alokacją eucledean lub bliskością
FelixIP

Dzięki @FelixIP, edytowałem do „well come raster solutions” ;-)
Peter Krauss,

Jeśli usuniesz wielokąty z ich zasięgu. Poligon, pozostaniesz z wielokątem. Szkielet tego gis.stackexchange.com/questions/177/… jest chyba tym, czego potrzebujesz. Wdrożenie jest jednak
duże

1
@ Cyryl, mogę przejrzeć twoje skrypty ... W przyszłym tygodniu. Umieszczenie czegoś, co wydaje się rozwiązaniem z nowoczesnymi funkcjami PostGIS, będzie dobrym pierwszym krokiem.
Peter Krauss,

Odpowiedzi:


2

Tak więc przygotuję dla ciebie ciasto - talerz z owocami, używając narzędzi PostGIS, tak jak prosiłeś, jeśli poprawnie zrozumiałem pytanie, i jak wspomniałem, odpowiedzialność za działanie piekarnika PostGIS spoczywa na jej zespole kreatywnym.

Poproszę, aby nikt mnie nie obraził w moim humorystycznym stylu i zrozumiałem to jako grę!

Oryginalny plik to pokrojone owoce i proste kształty (zwane dalej owocami), patrz rysunek 1 poniżej.

wprowadź opis zdjęcia tutaj

Oto mój przepis, w czym pomogą mi drodzy programiści, o których dowiecie się później. Zacznijmy, a do tego stworzymy ciasto, w którym zostaną złożone nasze owoce, dla którego uruchom skrypt:

create table poly_extent as SELECT ST_SetSRID(ST_Buffer(ST_Envelope(ST_Extent(geom)),0.05),4326) as geom FROM poly;

Zobacz wynik na ryc. 2 poniżej

wprowadź opis zdjęcia tutaj

Teraz, jeśli jest niewiele owoców, jak na moim zdjęciu, utwórz granicę zewnętrznego bufora na owocu, lub jeśli jest wiele owoców, utwórz granicę bufora ujemnego, dla którego uruchom skrypt:

create table poly_buff_dump as SELECT ((ST_Dump(ST_Boundary(ST_Union(ST_Buffer((geom),0.01, 'join=mitre mitre_limit=5.0'))))).geom) geom FROM poly;

I pokrój linie buforowe wokół każdego owocu

UPDATE poly_buff_dump SET geom=ST_RemovePoint(geom, ST_NPoints(geom)-1) WHERE ST_IsClosed(geom)=true; Zobacz wynik na ryc. 3 poniżej

wprowadź opis zdjęcia tutaj

(Właściwie myślałem, że w rezultacie dostanę linie przerywane (na przykład w kole), ale jeśli liczby są trudne, czasami uzyskuje się przerwy, nieprawidłowe, na przykład jedna strona prostokąta odpadła itp. )

Następnie musisz w wygodny sposób podzielić uzyskane linie na równe segmenty i wyodrębnić z nich punkty

create table poly_buff_dump_pt as SELECT (ST_DumpPoints((geom))).geom geom FROM poly_buff_segm;

Wynik, patrz rysunek 4 poniżej

wprowadź opis zdjęcia tutaj

Teraz uruchom narzędzie Voronoi, w tym miejscu użyłem narzędzia sugerowanego przez link MickyT: /gis//a/172246/120129 , w wyniku czego utworzysz tabele o nazwie „voronoi ”Za to, że„ mój pierwszy asystent ”jest niezależny od szefa kuchni dzięki szefowi kuchni! :-).

Drugim sposobem na tym etapie jest uruchomienie funkcji ST_VoronoiPolygons.

Wynik, patrz rysunek 5 poniżej

wprowadź opis zdjęcia tutaj

Teraz odetnij dodatkowe części, uruchamiając skrypt:

create table poly_voronoi_cut as SELECT ST_Intersection(a.geom, b.geom) geom FROM voronoi a INNER JOIN poly_extent b ON ST_Intersects(a.geom, b.geom); Wynik, patrz rysunek 6 poniżej.

wprowadź opis zdjęcia tutaj

Teraz uruchom skrypt, aby wyrównać typ danych geodezyjnych w LineString:

create table poly_voronoi_dump as SELECT (ST_Dump(geom)).geom as geom FROM poly_voronoi_cut; A teraz poproszę „mojego drugiego partnera”, aby podjął obowiązki i wymieszał tort wel (Jeff - /gis//a/785/120129 ), wyrównując go w jednej warstwie i do tego , dziękuję za to!

CREATE TABLE poly_overlay_cut AS SELECT geom FROM ST_Dump(( SELECT ST_Polygonize(geom) AS geom FROM ( SELECT ST_Union(geom) AS geom FROM ( SELECT ST_ExteriorRing(geom) AS geom FROM poly_voronoi_dump) AS lines ) AS noded_lines ) ); Teraz nadszedł czas, aby zabrać się do pracy, dla której uruchamiam skrypt:

create table poly_voronoi_union as SELECT b.id, (ST_ConvexHull(ST_Union(a.geom, b.geom))) geom FROM poly_overlay_cut a INNER JOIN poly_buff_dump b ON ST_Intersects(a.geom, b.geom) GROUP BY b.id, a.geom, b.geom; i inny skrypt:

create table poly_voronoi_union_area as SELECT ST_Union(ST_ConvexHull(ST_BuildArea(geom))) as geom FROM poly_voronoi_union GROUP BY id; patrz rysunek 7 poniżej

wprowadź opis zdjęcia tutaj

Jak widać na zdjęciu, nasze cięcia mają małe warstwy, które można usunąć, jako opcję za pomocą ST_SnapToGrid (lub w inny sposób):

I na koniec wycinamy nasze pieczone owoce z naszego ciasta, nawet trochę się zmęczyłem stojąc przy piekarniku :-)

create table polygon_voronoi_result as SELECT (ST_Dump(ST_Difference(a.geom, b.geom))).geom as geom FROM poly_voronoi_union_area_snap as a JOIN poly b ON ST_Intersects(a.geom, b.geom); Wynik patrz rysunek 8 wprowadź opis zdjęcia tutaj

Wszystko od tego dnia, teraz wszyscy nauczą się piec pyszne ciasta - talerz owoców. Pomóż sobie wszystkim i wybierz części, które lubisz dla wszystkich.

(Szkoda, że ​​tak naprawdę nie mogę nakarmić wszystkich ludzi, nie elektronicznymi ciastkami, ale prawdziwymi ciastkami, być może głód skończy się na Ziemi ...)

Edycja: Wiśnia na torcie może wyglądać tak :-):

WITH
tbla AS (SELECT (ST_DumpPoints(geom)).geom geom FROM poly),
tblb AS (SELECT ((ST_Dump(ST_VoronoiPolygons(ST_Collect(geom)))).geom) geom FROM tbla),
tblc AS (SELECT ST_Intersection(a.geom, b.geom) geom FROM tblb a JOIN poly_extent b ON ST_Intersects(a.geom,b.geom)),
tbld AS (SELECT id, ((ST_Dump(geom)).geom) geom FROM poly GROUP BY id, geom)
SELECT id, ST_Union(a.geom) as geom FROM tblc a JOIN tbld b ON ST_Intersects(a.geom, b.geom) GROUP BY id;

lub

WITH
tbla AS (SELECT (ST_DumpPoints(geom)).geom geom FROM polygons),
tblb AS (SELECT ((ST_Dump(ST_VoronoiPolygons(ST_Collect(geom)))).geom) geom FROM tbla),
tblc AS (SELECT id, ((ST_Dump(geom)).geom) geom FROM polygons GROUP BY id, geom)
SELECT id, ST_Union(a.geom) geom FROM tblb a JOIN tblc b ON ST_Intersects(a.geom, b.geom) GROUP BY id;

Popraw skrypt 01.04.2020:

WITH tbla AS (
WITH atbl AS (SELECT id, (ST_ExteriorRing(((ST_Dump(geom)).geom))) geom FROM polygons),
intervals AS (SELECT generate_series (0, 501) as steps)
SELECT steps AS stp, ST_LineInterpolatePoint(geom, steps/(SELECT count(steps)::float-1 FROM intervals)) geom FROM atbl, intervals GROUP BY id, intervals.steps, geom),
tblb AS (SELECT ((ST_Dump(ST_VoronoiPolygons(ST_Collect(geom)))).geom) geom FROM tbla),
tblc AS (SELECT id, ((ST_Dump(geom)).geom) geom FROM polygons GROUP BY id, geom)
SELECT id, ST_Union(a.geom) geom FROM tblb a JOIN tblc b ON ST_Intersects(a.geom, b.geom) GROUP BY id;

Z tobą był dobry i uczciwy Mr.Baker, dziękuję wszystkim i powodzenia: -) ...

Oryginalne rozwiązania.

Ten skrypt nazywa się: ST_VoronoiDiagramsFromPolygons.


1
Cześć, dobre ilustracje i wydaje się dobry wynik (!). Sugestia do krótkiej dyskusji, zobacz rozwiązanie @geogeek, kroki w QGis wydają się tutaj głównymi krokami PostGIS ... Dlaczego potrzebujemy ST_Bufferi ST_ConvexHull? Istnieje alternatywny algorytm?
Peter Krauss,

1) Patrz, ST_Buffer i na wielokątach są tworzone w celu zmniejszenia linii separacji między oryginalnymi liczbami podczas stosowania funkcji Voronoi, dlatego im większy rozmiar bufora można określić, tym bardziej płynnie linie separacji będą budowane jako funkcja Voronoi ... 2) ST_ConvexHull z mnóstwa liczb na każdym wielokącie, wielokąta, którego potrzebujemy ... 3) Dzisiaj jest to moja wizja rozwiązania twojego pytania, nie wiem co się stanie z nami wszystkimi i nasze decyzje w przyszłości ...
Cyryl Mikhalchenko

Inną ważną wartością linii buforowych jest to, że pomogą nam wybrać fragmenty z wyniku funkcji Voronoi, aby utworzyć połączone wielokąty dla każdego kształtu ...
Cyril Mikhalchenko

Nawiasem mówiąc, z zadowoleniem przyjmuję ulepszenie kodu i podejście, aby nie pogorszyły wyniku ...
Cyryl Mikhalchenko

1
Cześć Cyryl, Zgadzam się, że ST_Buffer to dobra opcja na normalizację linii konturu, idealna (!). O ST_ConvexHull, to tylko ciekawość, jakie wyniki możemy uzyskać po Figurze 6, poly_voronoi_unionbez ST_ConvexHull.
Peter Krauss,

8

Postgis nie mają dedykowanej funkcji dla voronoi, ale Qgis zawiera funkcję vornoi, która mogłaby tworzyć wielokąty voronoi z punktów, więc używając qgis wykonałem następujące kroki, aby uzyskać te wyniki:

- tworzyć punkty z wielokątów za pomocą extract nodesfunkcji.

-make wielokątów vornoi za pomocą funkcji voroi w Qgis.

-zrób połączenie przestrzenne w Qgis.

-rozpuszczać wyniki.

wprowadź opis zdjęcia tutaj


1
Ładne rozwiązanie (!) I dzięki ilustracji. Czy możesz to ulepszyć? Zobacz lewy prostokąt poniżej, w Voronoi było 4 punkty, a środek prostokąta nie ma reprezentacji, zniekształcając jego region (tracąc trójkąt) ... Być może możliwe jest ulepszenie poprzez regularne próbkowanie każdego wielokąta ... i być może także niektóre punkty wewnętrzne.
Peter Krauss

Używam narzędzia densify w ArcGIS. To znacznie poprawia wielokąty zbliżeniowe. +1
FelixIP

3

OK - Pomyślałem o tym trochę i odkryłem, że to było coś, na co ostatnio patrzyłem.

Weź swoje początkowe polisy:

wprowadź opis zdjęcia tutaj

Wygeneruj nowy atrybut z liczbą (w moim przypadku 100). Użyj narzędzia Wektor-> Narzędzia badawcze -> Losowe punkty wewnątrz wielokątów, to wygeneruje (100) punktów wewnątrz każdego wielokąta: wprowadź opis zdjęcia tutaj

Następnie Vector-> Narzędzia geometrii -> Voronoi, aby wygenerować polisy na podstawie tej warstwy punktowej.

wprowadź opis zdjęcia tutaj

Teraz możesz użyć narzędzia Wektor -> Zapytanie przestrzenne: Wybierz punkty, które należą do jednego wielokąta (lub jednego z wielokątów). Użyj narzędzia zapytań przestrzennych, aby wygenerować zaznaczenie wielokątów voronoi, które odnoszą się do tego wielokąta. Dodaj atrybut do wielokąta voroni, który odpowiada wielobokowi będącemu przedmiotem zainteresowania. (Właśnie użyłem 1,2,3,4)

Teraz możesz Wektor-> Narzędzia Geoprocessing-> rozpuścić na podstawie nowego atrybutu.

wprowadź opis zdjęcia tutaj


Dzięki @AAmes (!), Ilustracje są dobre, a metoda jest dobrą alternatywą ... Ale pytanie dotyczy „algorytmu SQL (lub niektórych specyficznych dla PostGIS)”, a teraz nagrody za korzystanie z funkcji ST_VoronoiPolygons () , które być może rozwiązują wszystkie problemy za pomocą jednego kliknięcia ;-)
Peter Krauss

@Ames Szybkie wyszukiwanie ujawnia, że ​​ta metoda może być rzeczywiście używana również w PostGIS. Jak tworzyć losowe punkty w wielokącie w postgisie wyjaśnia tworzenie punktów z wielokątów, a stamtąd powinno być dość proste.
Phil G

Moja nagroda była dla ciebie, jako zachęta (witaj tutaj!), Ale ODPOWIEDŹ JEST NIEDOPUSZCZALNA na pytania i wymagania dotyczące nagród.
Peter Krauss,

Dzięki Peter, widziałem twoje notatki, ale niestety nie miałem okazji wrócić i zająć się nimi. Nie mam jeszcze żadnego doświadczenia w PostGIS i zajęłoby mi to więcej czasu, niż miałbym do dyspozycji, aby udzielić jakiejkolwiek dobrej odpowiedzi. Mam nadzieję, że nasza eksploracja tej przestrzeni będzie pomocna dla ludzi w przyszłości, być może Jeśli wkrótce dostanę crack w PostGIS, wrócę i spróbuję jeszcze raz.
AA

2

Losowe punkty to dobry pomysł, aby wygenerować wielokąt voronoi z wielokątów, działa całkiem dobrze, ale jest całkiem zły dla wielokątów blisko siebie: wprowadź opis zdjęcia tutaj wprowadź opis zdjęcia tutaj

ST_ApproximateMedialAxis to kolejna dobra alternatywa, jeśli używa się PostGIS: Obliczanie diagramów Voronoi dla wielokątów

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.