คำถามต่อไปนี้ดูเหมือนว่าจะทำชุดรูปหลายเหลี่ยมที่สมเหตุสมผลของ voronoi โดยเริ่มจากรูปสามเหลี่ยม Delaunay
ฉันไม่ใช่ผู้ใช้ Postgres ใหญ่ดังนั้นจึงอาจปรับปรุงได้บ้าง
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;
สิ่งนี้สร้างชุดรูปหลายเหลี่ยมต่อไปนี้สำหรับจุดตัวอย่างที่รวมอยู่ในแบบสอบถาม
คำอธิบายแบบสอบถาม
ขั้นตอนที่ 1
สร้าง Delaunay Triangles จากรูปทรงเรขาคณิตอินพุต
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
ขั้นตอนที่ 2
สลายโหนดสามเหลี่ยมและทำให้ขอบสามารถทำได้ ฉันคิดว่าควรมีวิธีที่ดีกว่าในการรับขอบ แต่ฉันไม่พบ
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
ขั้นตอนที่ 3
สร้างวงกลมที่ถูก จำกัด สำหรับแต่ละสามเหลี่ยมแล้วหาเซนทรอยด์
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
Edges
CTE outputs ขอบแต่ละและ ID (เส้นทาง) ของรูปสามเหลี่ยมที่มันเป็น
ขั้นตอนที่ 4
'Outer Join' ตาราง 'ขอบ' กับตัวเองที่มีขอบเท่ากันสำหรับรูปสามเหลี่ยมที่แตกต่างกัน (ขอบด้านใน)
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)
ในกรณีที่มีขอบร่วมกันลากเส้นระหว่างเซนทรอยด์ที่เกี่ยวข้อง
ในกรณีที่ขอบไม่ได้เข้าร่วม (ภายนอก) วาดเส้นจากเซนทรอยด์ผ่านศูนย์กลางของขอบ ทำเช่นนี้ต่อเมื่อเซนทรอยด์ของวงกลมอยู่ภายในชุดของสามเหลี่ยม
ขั้นตอนที่ 5
รับฮัลล์นูนสำหรับเส้นที่วาดเป็นเส้น รวมกันและรวมทุกบรรทัด โหนดชุดเส้นเพื่อให้เรามีชุดทอพอโลยีที่สามารถเป็นรูปหลายเหลี่ยม
SELECT ST_Polygonize(ST_Node(ST_LineMerge(ST_Union(v, ST_ExteriorRing(ST_ConvexHull(v))))))