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.
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
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
(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
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
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.
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
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
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.