Các truy vấn sau đây dường như thực hiện một tập hợp đa giác voronoi hợp lý bắt đầu từ Tam giác Delaunay.
Tôi không phải là người dùng Postgres lớn, vì vậy nó có thể được cải thiện khá nhiều.
WITH
-- Sample set of points to work with
Sample AS (SELECT ST_GeomFromText('MULTIPOINT (12 5, 5 7, 2 5, 19 6, 19 13, 15 18, 10 20, 4 18, 0 13, 0 6, 4 1, 10 0, 15 1, 19 6)') geom),
-- Build edges and circumscribe points to generate a centroid
Edges AS (
SELECT id,
UNNEST(ARRAY['e1','e2','e3']) EdgeName,
UNNEST(ARRAY[
ST_MakeLine(p1,p2) ,
ST_MakeLine(p2,p3) ,
ST_MakeLine(p3,p1)]) Edge,
ST_Centroid(ST_ConvexHull(ST_Union(-- Done this way due to issues I had with LineToCurve
ST_CurveToLine(REPLACE(ST_AsText(ST_LineMerge(ST_Union(ST_MakeLine(p1,p2),ST_MakeLine(p2,p3)))),'LINE','CIRCULAR'),15),
ST_CurveToLine(REPLACE(ST_AsText(ST_LineMerge(ST_Union(ST_MakeLine(p2,p3),ST_MakeLine(p3,p1)))),'LINE','CIRCULAR'),15)
))) ct
FROM (
-- Decompose to points
SELECT id,
ST_PointN(g,1) p1,
ST_PointN(g,2) p2,
ST_PointN(g,3) p3
FROM (
SELECT (gd).Path id, ST_ExteriorRing((gd).Geom) g -- ID andmake triangle a linestring
FROM (SELECT (ST_Dump(ST_DelaunayTriangles(geom))) gd FROM Sample) a -- Get Delaunay Triangles
)b
) c
)
SELECT ST_Polygonize(ST_Node(ST_LineMerge(ST_Union(v, ST_ExteriorRing(ST_ConvexHull(v))))))
FROM (
SELECT -- Create voronoi edges and reduce to a multilinestring
ST_LineMerge(ST_Union(ST_MakeLine(
x.ct,
CASE
WHEN y.id IS NULL THEN
CASE WHEN ST_Within(
x.ct,
(SELECT ST_ConvexHull(geom) FROM sample)) THEN -- Don't draw lines back towards the original set
-- Project line out twice the distance from convex hull
ST_MakePoint(ST_X(x.ct) + ((ST_X(ST_Centroid(x.edge)) - ST_X(x.ct)) * 2),ST_Y(x.ct) + ((ST_Y(ST_Centroid(x.edge)) - ST_Y(x.ct)) * 2))
END
ELSE
y.ct
END
))) v
FROM Edges x
LEFT OUTER JOIN -- Self Join based on edges
Edges y ON x.id <> y.id AND ST_Equals(x.edge,y.edge)
) z;
Điều này tạo ra tập hợp đa giác sau cho các điểm mẫu có trong truy vấn
Giải thích truy vấn
Bước 1
Tạo Tam giác Delaunay từ hình học đầu vào
SELECT (gd).Path id, ST_ExteriorRing((gd).Geom) g -- ID and make triangle a linestring
FROM (SELECT (ST_Dump(ST_DelaunayTriangles(geom))) gd FROM Sample) a -- Get Delaunay Triangles
Bước 2
Phân tách các nút tam giác và làm cho các cạnh có thể được thực hiện. Tôi nghĩ rằng nên có một cách tốt hơn để có được các cạnh, nhưng tôi đã không tìm thấy một.
SELECT ...
ST_MakeLine(p1,p2) ,
ST_MakeLine(p2,p3) ,
ST_MakeLine(p3,p1)
...
FROM (
-- Decompose to points
SELECT id,
ST_PointN(g,1) p1,
ST_PointN(g,2) p2,
ST_PointN(g,3) p3
FROM (
... Step 1...
)b
) c
Bước 3
Xây dựng các vòng tròn được đăng ký cho mỗi tam giác và tìm tâm
SELECT ... Step 2 ...
ST_Centroid(ST_ConvexHull(ST_Union(-- Done this way due to issues I had with LineToCurve
ST_CurveToLine(REPLACE(ST_AsText(ST_LineMerge(ST_Union(ST_MakeLine(p1,p2),ST_MakeLine(p2,p3)))),'LINE','CIRCULAR'),15),
ST_CurveToLine(REPLACE(ST_AsText(ST_LineMerge(ST_Union(ST_MakeLine(p2,p3),ST_MakeLine(p3,p1)))),'LINE','CIRCULAR'),15)
))) ct
FROM (
-- Decompose to points
SELECT id,
ST_PointN(g,1) p1,
ST_PointN(g,2) p2,
ST_PointN(g,3) p3
FROM (
... Step 1...
)b
) c
Các Edges
CTE kết quả đầu ra mỗi cạnh và id (đường dẫn) của tam giác nó thuộc về.
Bước 4
'Tham gia bên ngoài' bảng 'Cạnh' với chính nó, nơi có các cạnh bằng nhau cho các hình tam giác khác nhau (các cạnh bên trong).
SELECT
...
ST_MakeLine(
x.ct, -- Circumscribed Circle centroid
CASE
WHEN y.id IS NULL THEN
CASE WHEN ST_Within( -- Don't draw lines back towards the original set
x.ct,
(SELECT ST_ConvexHull(geom) FROM sample)) THEN
-- Project line out twice the distance from convex hull
ST_MakePoint(
ST_X(x.ct) + ((ST_X(ST_Centroid(x.edge)) - ST_X(x.ct)) * 2),
T_Y(x.ct) + ((ST_Y(ST_Centroid(x.edge)) - ST_Y(x.ct)) * 2)
)
END
ELSE
y.ct -- Centroid of triangle with common edge
END
))) v
FROM Edges x
LEFT OUTER JOIN -- Self Join based on edges
Edges y ON x.id <> y.id AND ST_Equals(x.edge,y.edge)
Trường hợp có một cạnh chung vẽ một đường giữa các tâm tương ứng
Trường hợp cạnh không được nối (bên ngoài) vẽ một đường thẳng từ tâm qua tâm của cạnh. Chỉ làm điều này nếu tâm của hình tròn nằm trong tập hợp các hình tam giác.
Bước 5
Lấy thân tàu lồi cho các đường được vẽ dưới dạng đường. Liên minh và hợp nhất tất cả các dòng. Nút nút dòng để chúng ta có một bộ tô pô có thể được đa giác hóa.
SELECT ST_Polygonize(ST_Node(ST_LineMerge(ST_Union(v, ST_ExteriorRing(ST_ConvexHull(v))))))