Пример #1
0
        /* Function: deleteCircleEvent
         * ---------------------------
         * Deletes a potential circle event associated with a site event
         * from the event queue (it is no longer correct).
         */
        private void deleteCircleEvent(BeachArc arc)
        {
            CircleEvent ce = arc.circleEvent;

            arc.circleEvent = null;
            if (ce != null && sweepLine.Contains(ce))
            {
                sweepLine.Remove(ce);
                usedCircleEvents.Add(ce);
            }
        }
Пример #2
0
        /* Method: computeVoronoiDiagram
         * -----------------------------
         * Computes Fortune Voronoi digram and returns it.
         */
        public VoronoiDiagram computeVoronoiDiagram()
        {
            int   currSiteID = 0;
            float lastEventX, lastEventY;

            lastEventX = lastEventY = Mathf.Infinity;
            Event e = null;

            while (sweepLine.Count > 0)
            {
                e = sweepLine.Dequeue();  // remove event from queue with largest y-coord

                if (e.isSiteEvent && !isDuplicate(e, lastEventX, lastEventY))
                {
                    e.site.setId(currSiteID);
                    cells.Insert(e.site.id, new VoronoiCell(e.site)); // add new cell at id

                    // Add site to beach section
                    handleSiteEvent(e.site);

                    // Update for next event
                    currSiteID++;
                    lastEventX = e.site.x;
                    lastEventY = e.site.y;
                }
                else
                {
                    CircleEvent ce = (CircleEvent)e;
                    handleCircleEvent(ce.arc);
                }
            }

            // Terminate cell edges after queue empty on a bounding box (they go to infinite)
            clipEdgesOnBounds();
            closeCells();

            // Build Voronoi diagram
            VoronoiDiagram diagram = new VoronoiDiagram();

            diagram.sites = sites;
            diagram.cells = cells;
            diagram.edges = edges;
            reset();
            return(diagram);
        }
Пример #3
0
        /* Function: getTripleArcCircleEvent
         * ---------------------------------
         * Checks sites of three arcs for convergence of breakpoints, i.e. beach will
         * collapse giving rise to a circle event. If true, gets a circle event and
         * updates its fields on the receiving arc and event queue.
         *
         * Note: Calculation of circle event based on Jeremie St-Amand's:
         * https://github.com/jesta88/Unity-Voronoi/blob/master/Assets/Voronoi/FortuneVoronoi.cs
         */
        private void getTripleArcCircleEvent(Site left, ref BeachArc center, Site right)
        {
            float cx          = center.site.x;
            float cy          = center.site.y;
            float lx          = left.x - cx;
            float ly          = left.y - cy;
            float rx          = right.x - cx;
            float ry          = right.y - cy;
            float orientation = 2 * (lx * ry - ly * rx);

            // Points are CW, beach section does not collapse so no event
            if (orientation >= -2e-12)
            {
                return;
            }

            float lLengthSquared = lx * lx + ly * ly;
            float rLengthSquared = rx * rx + ry * ry;
            float x       = (ry * lLengthSquared - ly * rLengthSquared) / orientation;
            float y       = (lx * rLengthSquared - rx * lLengthSquared) / orientation;
            float yCenter = y + cy; // at or below sweepline

            // Get circle event to setup
            CircleEvent circleEvent = null;

            if (usedCircleEvents.Count > 0)
            {
                circleEvent = usedCircleEvents.Last();
                usedCircleEvents.Remove(circleEvent);
            }
            else
            {
                circleEvent = new CircleEvent();
            }

            // Update fields
            circleEvent.site = center.site;
            circleEvent.arc  = center;
            circleEvent.setPosition(x + cx, yCenter + Mathf.Sqrt(x * x + y * y), yCenter);
            center.circleEvent = circleEvent;

            // Add to event queue
            sweepLine.Enqueue(circleEvent, circleEvent);
        }
Пример #4
0
        /* Function: handleCircleEvent
         * ---------------------------
         * Handles circle event.
         */
        private void handleCircleEvent(BeachArc arc)
        {
            CircleEvent circleEvent = arc.circleEvent;
            Vertex      center      = new Vertex(circleEvent.x, circleEvent.yCircleCenter);
            BeachArc    prev        = arc.Prev;
            BeachArc    next        = arc.Next;

            LinkedList <BeachArc> disappearingTransitions = new LinkedList <BeachArc>();

            disappearingTransitions.AddLast(arc);

            deleteBeachArc(arc);

            // Handle collapse left
            BeachArc leftArc = prev;

            while (leftArc.circleEvent != null && Mathf.Abs(center.x - leftArc.circleEvent.x) < EPS &&
                   Mathf.Abs(center.y - leftArc.circleEvent.yCircleCenter) < EPS)
            {
                prev = leftArc.Prev;
                disappearingTransitions.AddFirst(leftArc);
                deleteBeachArc(leftArc);
                leftArc = prev;
            }

            // New left arc not dissappearing, but used in edge updates
            disappearingTransitions.AddFirst(leftArc);
            deleteCircleEvent(leftArc);

            // Hanlde collapse right
            BeachArc rightArc = next;

            while (rightArc.circleEvent != null && Mathf.Abs(center.x - rightArc.circleEvent.x) < EPS &&
                   Mathf.Abs(center.y - rightArc.circleEvent.yCircleCenter) < EPS)
            {
                next = rightArc.Next;
                disappearingTransitions.AddLast(rightArc);
                deleteBeachArc(rightArc);
                rightArc = next;
            }

            // New right arc not dissappearing, but used in edge updates
            disappearingTransitions.AddLast(rightArc);
            deleteCircleEvent(rightArc);

            // Link existing edges at start point
            int nArcs = disappearingTransitions.Count;

            for (int i = 1; i < nArcs; i++)
            {
                rightArc = disappearingTransitions.ElementAt(i);
                leftArc  = disappearingTransitions.ElementAt(i - 1);
                rightArc.edge.setStartVertex(leftArc.site, rightArc.site, center);
            }

            // Create new edge between previously non-adjacent arcs
            // New vertex defines end point relative to site on the left
            leftArc       = disappearingTransitions.ElementAt(0);
            rightArc      = disappearingTransitions.ElementAt(nArcs - 1);
            rightArc.edge = createNewEdge(leftArc.site, rightArc.site, null, center);

            // Update circle events for arcs
            findPotentialCircleEvent(leftArc);
            findPotentialCircleEvent(rightArc);
        }