लागू करने के लिए वोरोनोई आरेख का सबसे आसान एल्गोरिथ्म? [बन्द है]


88

वोरोनोई आरेख को लागू करने के लिए आसान एल्गोरिदम क्या हैं?

मुझे छद्म रूप में कोई एल्गोरिथ्म नहीं मिला। कृपया वोरोनोई आरेख एल्गोरिदम, ट्यूटोरियल आदि के कुछ लिंक साझा करें।


जवाबों:


32

एक बिंदु सेट के Delaunay त्रिभुज की गणना करने के लिए एक आसान एल्गोरिथ्म किनारों को फ़्लिप कर रहा है । चूंकि डेलौनाय त्रिकोण एक वोरोनोई आरेख का दोहरा ग्राफ है, इसलिए आप रैखिक समय में त्रिभुज से आरेख का निर्माण कर सकते हैं।

दुर्भाग्य से, फ़्लिपिंग दृष्टिकोण का सबसे खराब समय चल रहा है O (n ^ 2)। फॉर्च्यून की लाइन स्वीप जैसे बेहतर एल्गोरिदम मौजूद हैं, जो ओ (एन लॉग एन) समय लेते हैं। हालांकि यह लागू करने के लिए कुछ मुश्किल है। यदि आप आलसी हैं (जैसा कि मैं हूं), तो मैं सुझाव दूंगा कि एक Delaunay त्रिकोण के मौजूदा कार्यान्वयन की तलाश है, इसका उपयोग करें, और फिर दोहरे ग्राफ़ की गणना करें।

सामान्य तौर पर, डे बर्ग एट अल द्वारा कम्प्यूटेशनल ज्यामिति विषय पर एक अच्छी किताब है ।


19

सबसे आसान? यह ब्रूट-बल दृष्टिकोण है: आपके आउटपुट में प्रत्येक पिक्सेल के लिए, सभी बिंदुओं के माध्यम से पुनरावृति, दूरी की गणना, निकटतम का उपयोग करें। धीमा हो सकता है, लेकिन बहुत सरल है। यदि प्रदर्शन महत्वपूर्ण नहीं है, तो यह काम करता है। मैं खुद एक दिलचस्प परिशोधन पर काम कर रहा हूं, लेकिन फिर भी यह देखने के लिए कि क्या किसी और के पास भी (बल्कि स्पष्ट) विचार है।


14

बाउयर-वाटसन एल्गोरिदम समझने में काफी आसान है। यहाँ एक कार्यान्वयन है: http://paulbourke.net/papers/triangulate/ । यह बिंदुओं के एक समूह के लिए एक विलंबित त्रिभुज है, लेकिन आप इसका उपयोग delaunay के दोहरीकरण के लिए कर सकते हैं, अर्थात एक वोरोनोई-आरेख। Btw। न्यूनतम फैले हुए वृक्ष डेलुनाय त्रिभुज का एक सबसेट है।


12

वोरोनोई आरेख के निर्माण के लिए सबसे कुशल एल्गोरिथम फॉर्च्यून का एल्गोरिदम है । यह O (n log n) में चलता है।

यहाँ सी में उनके संदर्भ कार्यान्वयन के लिए एक कड़ी है

वास्तव में मुझे बिल सिमंस और कार्सन किसान द्वारा अजगर के कार्यान्वयन को वास्तव में पसंद है , क्योंकि मुझे इसका विस्तार करना आसान लगा।


सी-कार्यान्वयन के लिए लिंक अब और काम नहीं कर रहा है :(
FutureCake

1
@FutureCake इंटरनेट पुरालेख को बचाव के लिए: web.archive.org/web/2018101822424943/http://ect.bell-labs.com/who/…
polettix


9

स्टेफ़न फॉर्च्यून / शेन ओ'सुल्लिवन से सी और सी ++ में 2-डी ग्राफ़ के लिए एक स्वतंत्र रूप से उपलब्ध वोरोनोई कार्यान्वयन है:

VoronoiDiagramGenerator.cpp 

VoronoiDiagramGenerator.h 

आप इसे कई स्थानों पर पाएंगे। यानी http://www.skynet.ie/~sos/masters/ पर


4
व्यापक रूप से संदर्भित, अनिर्दिष्ट, और लगभग हर पुन: कार्यान्वयन जो मैंने इस कोड के आधार पर देखा है वह गलत है (विभिन्न भाषाओं में, कई लोगों को वोरोनोई की आवश्यकता है, कुछ इसे सही ढंग से पोर्ट करने के लिए अच्छी तरह से समझ सकते हैं)। एकमात्र कामकाजी बंदरगाह जो मैंने देखा है वे विज्ञान / शिक्षा समुदाय से हैं और बड़े पैमाने पर अधिक जटिल फ़ंक्शन हस्ताक्षर हैं - या बड़े पैमाने पर अनुकूलित (ताकि वे अधिकांश उद्देश्यों के लिए उपयोग नहीं किए जा सकें) उन्हें सामान्य प्रोग्रामर द्वारा अनुपयोगी बना दिया जाता है।
एडम

VoronoiDiagramGenerator.cpp में सीमित कार्यक्षमता है। यह किनारों के एक अनियंत्रित सेट का उत्पादन करेगा। इससे वास्तविक बहुभुज निकालने के लिए गैर-तुच्छ है। प्लस-साइड पर, यह एक बाउंडिंग आयत के खिलाफ एक क्लिप की सुविधा देता है, इसलिए कोई अनन्तता अंक उत्पन्न नहीं होता है।
ब्रैम


6

जबकि मूल प्रश्न यह बताता है कि वोरोनोई को कैसे लागू किया जाए, क्या मुझे एक पोस्ट मिली थी जिसमें कहा गया था कि जब मैं इस विषय पर जानकारी खोज रहा था तो इससे मुझे बहुत समय बचा होगा:

वोरोनोई आरेखों को लागू करने के लिए इंटरनेट पर बहुत सारे "लगभग सही" सी ++ कोड है। जब बीज अंक बहुत सघन हो जाते हैं, तो ज्यादातर ने शायद ही कभी विफलताओं को ट्रिगर किया है। मैं किसी भी कोड का परीक्षण करने की सलाह दूंगा, जो आपके द्वारा अपनी तैयार परियोजना में उपयोग किए जाने वाले अंकों की संख्या के साथ बड़े पैमाने पर ऑनलाइन मिल जाए, इससे पहले कि आप बहुत अधिक समय बर्बाद करें।

मेरे द्वारा ऑनलाइन लागू किए गए सर्वोत्तम कार्यान्वयन यहाँ से जुड़े MapManager कार्यक्रम का हिस्सा थे: http://www.skynet.ie/~sos/mapviewer/voronoi.php यह ज्यादातर काम करता है, लेकिन जब मैं काम कर रहा हूं तो रुक-रुक कर आरेख प्राप्त कर रहा हूं आदेश 10 ^ 6 अंक। मैं ठीक से काम नहीं कर पाया कि भ्रष्टाचार किस तरह से चरमरा रहा है।

कल रात मुझे यह पता चला: http://www.boost.org/doc/libs/1_53_0_beta1/libs/polygon/doc/voronoi_main.htm "Boost.Polygon Vononoi पुस्तकालय"। यह बहुत ही आशाजनक लग रहा है। यह सटीकता साबित करने के लिए बेंचमार्क परीक्षणों के साथ आता है और इसमें शानदार प्रदर्शन है। पुस्तकालय में एक उचित इंटरफ़ेस और प्रलेखन है। मुझे आश्चर्य है कि मुझे अब से पहले यह लाइब्रेरी नहीं मिली, इसलिए इसके बारे में यहाँ मेरा लेखन। (मैंने अपने शोध में इस पोस्ट को जल्दी पढ़ा।)


4

वास्तव में https://rosettacode.org/wiki/Voronoi_diagram पर 25 विभिन्न भाषाओं के लिए कार्यान्वयन उपलब्ध हैं

जैसे जावा के लिए:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.swing.JFrame;

public class Voronoi extends JFrame {
    static double p = 3;
    static BufferedImage I;
    static int px[], py[], color[], cells = 100, size = 1000;

    public Voronoi() {
        super("Voronoi Diagram");
        setBounds(0, 0, size, size);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        int n = 0;
        Random rand = new Random();
        I = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
        px = new int[cells];
        py = new int[cells];
        color = new int[cells];
        for (int i = 0; i < cells; i++) {
            px[i] = rand.nextInt(size);
            py[i] = rand.nextInt(size);
            color[i] = rand.nextInt(16777215);

        }
        for (int x = 0; x < size; x++) {
            for (int y = 0; y < size; y++) {
                n = 0;
                for (byte i = 0; i < cells; i++) {
                    if (distance(px[i], x, py[i], y) < distance(px[n], x, py[n], y)) {
                        n = i;

                    }
                }
                I.setRGB(x, y, color[n]);

            }
        }

        Graphics2D g = I.createGraphics();
        g.setColor(Color.BLACK);
        for (int i = 0; i < cells; i++) {
            g.fill(new Ellipse2D .Double(px[i] - 2.5, py[i] - 2.5, 5, 5));
        }

        try {
            ImageIO.write(I, "png", new File("voronoi.png"));
        } catch (IOException e) {

        }

    }

    public void paint(Graphics g) {
        g.drawImage(I, 0, 0, this);
    }

    static double distance(int x1, int x2, int y1, int y2) {
        double d;
        d = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); // Euclidian
    //  d = Math.abs(x1 - x2) + Math.abs(y1 - y2); // Manhattan
    //  d = Math.pow(Math.pow(Math.abs(x1 - x2), p) + Math.pow(Math.abs(y1 - y2), p), (1 / p)); // Minkovski
        return d;
    }

    public static void main(String[] args) {
        new Voronoi().setVisible(true);
    }
}

3

सरलतम एल्गोरिथ्म एक वोरोनोई आरेख की परिभाषा से आता है: "उत्तल बहुभुज में n बिंदुओं के साथ एक विमान का विभाजन ऐसा है कि प्रत्येक बहुभुज में बिल्कुल एक उत्पन्न बिंदु होता है और किसी दिए गए बहुभुज में प्रत्येक बिंदु किसी अन्य की तुलना में इसके उत्पादन बिंदु के करीब होता है। । "भेड़िया से परिभाषा।

यहां महत्वपूर्ण भाग किसी भी अन्य की तुलना में उत्पादन बिंदु के करीब होने के बारे में है, यहां से एल्गोरिथ्म बहुत सरल है:

  1. अंक बनाने की एक सरणी है।
  2. अपने कैनवास पर हर पिक्सेल के माध्यम से लूप करें।
  3. प्रत्येक पिक्सेल के लिए इसके लिए निकटतम उत्पादक बिंदु के लिए देखें।
  4. पिक्सेल को रंगीन करने के लिए आप किस आरेख पर निर्भर करते हैं। यदि आप एक सीमा के साथ अलग आरेख चाहते हैं, तो दूसरे से निकटतम बिंदु तक जांच करें, फिर कुछ अंतर से छोटे होने पर सीमा के रंग के साथ उनके अंतर और रंग की जांच करें।

यदि आप एक रंग आरेख चाहते हैं, तो प्रत्येक उत्पादक बिंदु के साथ एक रंग जुड़ा हुआ है और प्रत्येक पिक्सेल को निकटतम उत्पादन बिंदु से संबंधित रंग के साथ रंग दें। और यह इसके बारे में है, यह कुशल नहीं है लेकिन इसे लागू करना बहुत आसान है।


3

यह सबसे तेज़ संभव है - यह एक साधारण वोरोनोई है लेकिन यह बहुत अच्छा लगता है। यह एक ग्रिड में रिक्त स्थान को विभाजित करता है, प्रत्येक ग्रिड सेल में एक बिंदु को बेतरतीब ढंग से रखा जाता है और ग्रिड के साथ 3x3 कोशिकाओं की जांच करता है ताकि यह पता लगा सके कि यह आसन्न कोशिकाओं से कैसे संबंधित है।

यह ढाल के बिना तेज है।

आप पूछ सकते हैं कि सबसे आसान 3 डी वोरोनोई क्या होगा। यह जानना आकर्षक होगा। संभवतः 3x3x3 कोशिकाएं और ग्रेडिएंट की जाँच।

http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm

float voronoi( in vec2 x )
{
    ivec2 p = floor( x );
    vec2  f = fract( x );

    float res = 8.0;
    for( int j=-1; j<=1; j++ )
    for( int i=-1; i<=1; i++ )
    {
        ivec2 b = ivec2( i, j );
        vec2  r = vec2( b ) - f + random2f( p + b );
        float d = dot( r, r );

        res = min( res, d );
    }
    return sqrt( res );
}

और यहाँ chebychev दूरी के साथ भी ऐसा ही है। आप यहां से एक random2f 2d फ्लोट शोर का उपयोग कर सकते हैं:

https://www.shadertoy.com/view/Msl3DM

संपादित करें: मैंने इसे C की तरह कोड में बदल दिया है

यह कुछ समय पहले था, उन लोगों के लाभ के लिए जो इसे कहते हैं, मेरा मानना ​​है कि यह अच्छा है:

 function rndng ( n: float ): float
 {//random number -1, 1
     var e = ( n *321.9)%1;
     return  (e*e*111.0)%2-1;
 }

 function voronoi(  vtx: Vector3  )
 {
     var px = Mathf.Floor( vtx.x );
     var pz = Mathf.Floor( vtx.z );
     var fx = Mathf.Abs(vtx.x%1);
     var fz = Mathf.Abs(vtx.z%1);

     var res = 8.0;
     for( var j=-1; j<=1; j++ )
     for( var i=-1; i<=1; i++ )
     {
         var rx = i - fx + nz2d(px+i ,pz + j ) ;
         var rz = j - fz + nz2d(px+i ,pz + j ) ;
         var d = Vector2.Dot(Vector2(rx,rz),Vector2(rx,rz));
         res = Mathf.Min( res, d );
     }
     return Mathf.Sqrt( res );
 }

आप इतने सारे एक अक्षर वाले चरों का उपयोग क्यों करते हैं जो स्वयं व्याख्यात्मक नहीं हैं? और क्या है ivec2? या vec2? यह अपठनीय है।
शिंज़ौ

अच्छा बिंदु, मुझे लगता है कि मैं भी इसके साथ पूरे दिन संघर्ष करना पड़ा: answers.unity3d.com/questions/638662/... कोड के साथ इस पाठ अद्यतन
aliential

1

सवाल पर अपने जवाब में रिचर्ड फ्रैंक्स द्वारा छद्म कोड के साथ प्रस्तुत ब्रूट-बल समाधान की जांच करें मैं अपने बिंदु सेट और इसकी Delaunay त्रिकोणता को देखते हुए वोरोनोई आरेख कैसे प्राप्त करूं?


0

फॉर्च्यून के एल्गोरिथ्म / स्वीप लाइन एल्गोरिथ्म के आधार पर गूगल कोड पर इस उत्कृष्ट सी # लाइब्रेरी को मिला

https://code.google.com/p/fortune-voronoi/

आपको बस एक सूची बनाने की आवश्यकता है। एक वेक्टर को दो संख्याओं (निर्देशांक) में फ्लोट के रूप में पास करके बनाया जा सकता है। इसके बाद फॉर्च्यूनर में सूची पास करें ।ComputeVoronoiGraph ()

आप इन विकिपीडिया पृष्ठों से एल्गोरिथ्म की अवधारणा को थोड़ा और समझ सकते हैं:

http://en.wikipedia.org/wiki/Fortune%27s_algorithm

http://en.wikipedia.org/wiki/Sweep_line_algorithm

हालांकि एक बात जो मैं समझ नहीं पा रहा था, वह यह है कि आंशिक रूप से अनंत किनारों के लिए एक पंक्ति कैसे बनाई जाए (समन्वय ज्यामितीय के बारे में बहुत कुछ नहीं जानते)। अगर कोई जानता है, तो कृपया मुझे भी बताएं।


2
हालांकि ये लिंक प्रश्न का उत्तर दे सकते हैं, लेकिन उत्तर के आवश्यक भागों को शामिल करना और संदर्भ के लिए लिंक प्रदान करना बेहतर है। लिंक-केवल उत्तर अमान्य हो सकते हैं यदि लिंक किए गए पृष्ठ बदल जाते हैं।
कैमिक्नर

0

यदि आप इसे एक छवि के लिए आकर्षित करने की कोशिश कर रहे हैं, तो आप एक कतार-आधारित बाढ़-भरने वाले एल्गोरिथ्म का उपयोग कर सकते हैं।

Voronoi::draw(){
    // define colors for each point in the diagram;
    // make a structure to hold {pixelCoords,sourcePoint} queue objects
    // initialize a struct of two closest points for each pixel on the map
    // initialize an empty queue;

    // for each point in diagram:
        // for the push object, first set the pixelCoords to pixel coordinates of point;
        // set the sourcePoint of the push object to the current point;
        // push the queue object;

    // while queue is not empty:
        // dequeue a queue object;
        // step through cardinal neighbors n,s,e,w:
            // if the current dequeued source point is closer to the neighboring pixel than either of the two closest:
                // set a boolean doSortAndPush to false;
                // if only one close neighbor is set:
                    // add sourcePoint to closestNeighbors for pixel;
                    // set doSortAndPush to true;
                // elif sourcePoint is closer to pixel than it's current close neighbor points:
                    // replace the furthest neighbor point with sourcePoint;
                    // set doSortAndPush to true;
                // if flag doSortAndPush is true:
                    // re-sort closest neighbors; 
                    // enqueue object made of neighbor pixel coordinates and sourcePoint;

    // for each pixel location:
        // if distance to closest point within a radius for point drawing:
            // color pixel the point color;
        // elif distances to the two closest neighbors are roughly equal:
            // color the pixel to your border color;
        // else 
            // color the pixel the color of the point's region; 

}

एक कतार का उपयोग यह सुनिश्चित करेगा कि क्षेत्र समानांतर में फैलते हैं, पिक्सेल विज़िट की कुल संख्या को कम करते हैं। यदि आप एक स्टैक का उपयोग करते हैं तो पहला बिंदु पूरी छवि को भर देगा, फिर दूसरा किसी भी पिक्सेल को पहले बिंदु की तुलना में उसके करीब भर देगा। यह जारी रहेगा, बहुत अधिक दौरा मायने रखता है। एक FIFO कतार का उपयोग करके पिक्सेल को उस क्रम में संसाधित किया जाता है जिसे वे धकेले जाते हैं। परिणामी छवियां लगभग समान होंगी चाहे आप स्टैक या कतार का उपयोग करें, लेकिन कतार के लिए बिग-ओ स्टैक एल्गोरिटम के बिग-ओ की तुलना में रैखिक (छवि पिक्सल की संख्या के संबंध में) के करीब है। सामान्य विचार यह है कि क्षेत्र समान दर पर फैलेंगे और टकराव आमतौर पर उन बिंदुओं पर होगा जो क्षेत्र की सीमाओं के अनुरूप हैं।

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