/* 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); } }
/* 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); }
/* 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); }
/* 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); }