Voronoi आरेख बनाने के लिए ST_DelaunayTriangles का उपयोग कैसे करें?


13

(पोस्ट 2019 को संपादित करें) ST_VoronoiPolygons PostGIS v2.3 के बाद से उपलब्ध है !


PostGIS 2.1+ के साथ हम एक Delaunay त्रिकोण उत्पन्न करने के लिए ST_DelaunayTriangles () का उपयोग कर सकते हैं , जो कि इसके वोरोनोई आरेख का दोहरा ग्राफ है , और, सिद्धांत रूप में, उनके पास एक सटीक और प्रतिवर्ती रूपांतरण है।

इस PostGIS2 Delaunay-to-Voronoi रूपांतरण के लिए एक अनुकूलित एल्गोरिथ्म के साथ कोई सुरक्षित SQL-मानक स्क्रिप्ट मौजूद है ?


अन्य रेफरी: 1 , 2


क्या gist.github.com/djq/4714788 आपके बाद की चीज़ है?
मिकी टीटी

मुझे लगता है कि वह ST_DelaunayTriangles () का उपयोग करके विशुद्ध रूप से SQL कार्यान्वयन चाहता है
राफेल

ST_DelaunayTrianglesलिनक्स डेबियन स्टेबल में स्थापित करने के लिए यह उत्तर देखें
पीटर क्रस

! ST_VoronoiPolygons PostGIS 2.3 के बाद से उपलब्ध है
पीटर क्रूस

जवाबों:


23

निम्न क्वेरी डेलोरुन त्रिकोण से शुरू होने वाले वोरोनोई पॉलीगोन का एक उचित सेट करने के लिए प्रतीत होता है।

मैं एक बड़ा 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

इनपुट जियोमेट्री से डेलुनाय त्रिकोण बनाएं

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

यहाँ छवि विवरण दर्ज करें

EdgesCTE त्रिकोण यह के अंतर्गत आता है में से प्रत्येक के किनारे और आईडी (पथ) आउटपुट।

चरण 4

'आउटर जॉइन' 'एग्स' टेबल अपने आप में जहां विभिन्न त्रिकोणों (आंतरिक किनारों) के बराबर किनारे हैं।

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

यहाँ छवि विवरण दर्ज करें


अच्छा सुराग, शायद एक समाधान (!)। मुझे परीक्षण करने की आवश्यकता है, लेकिन अब नहीं कर सकता ... विश्लेषण: आप उपयोग करते हैं ST_ConvexHullऔर ST_Centroidइसके बजाय "सीधा द्विभाजक" जैसा कि सीधे मेरे एल्गोरिथ्म में मेरे ref1 / केनेथ स्लोए द्वारा सुझाया गया है ... प्रत्यक्ष समाधान क्यों नहीं?
पीटर क्रस 20

मैं बहुत बाहरी किनारों के लिए लंबवत द्विभाजक कर रहा हूं, बस सभी गणित के बिना :) मैं उन कदमों की व्याख्या
जोड़ूंगा

अच्छा चित्रण और स्पष्टीकरण, बहुत उपदेशात्मक!   आपने वह सब पोस्ट किया जिसकी मुझे आवश्यकता है (!), लेकिन इस दिन मेरे पास Postgis2.1 का परीक्षण करने के लिए नहीं है ... क्या मैं यहां जांच कर सकता हूं (टिप्पणी के रूप में) कुछ प्रश्न जो किसी भी परीक्षण द्वारा उत्तर दे सकते हैं?   1) ST_Polygonize "संभव पॉलीगोन युक्त एक ज्यामिति का निर्माण करता है", वे सभी वोरोनोई कोशिकाएं हैं, सही है?   2) प्रदर्शन के बारे में, आपको लगता है कि आपके सेंट्रोइड-आधारित समाधान में "लंबवत द्विभाजक गणना के सभी गणित" की तुलना में समान सीपीयू-समय है?
पीटर क्रूस

@PeterKrauss 1) ST_polygonize लाइन के काम से वोरोनोई सेल बनाता है। इसके साथ चाल यह सुनिश्चित करने के लिए है कि सभी लाइन काम नोड्स में विभाजित हैं। 2) मुझे नहीं लगता कि लाइन पर bisection की गणना और ST_Centroid का उपयोग करने के बीच बहुत अंतर होगा। लेकिन इसका परीक्षण करने की आवश्यकता होगी।
18

ST_DelaunayTrianglesलिनक्स डेबियन स्टेबल में स्थापित करने के लिए यह उत्तर देखें
पीटर क्रस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.