public DCEL ComputeVoronoiDiagram(IEnumerable<Site> sites) { var state = new State { BeachLine = null, EventQueue = CreateEventQueueWithSiteEvents(sites), SweepLineY = double.MaxValue, Faces = new Dictionary<Site, Face>(), HalfEdges = new List<HalfEdge>(), Vertexes = new List<Vertex>() }; DrainEvents(state); throw new System.NotImplementedException(); }
/// <summary> /// Processes all events from the event queue, including any /// discovered circle events. /// </summary> private void DrainEvents(State state) { while(state.EventQueue.Count > 0) { var currentEvent = state.EventQueue.Dequeue(); // The sweep line should always decrease monotonically. if (currentEvent.YCoordinate > state.SweepLineY) throw new SanityCheckFailedException(string.Format( "Retrieved a {0} from the event queue whose y-coordinate ({1}) was greater than the sweep line's y-coordinate ({2}). The sweep line's y coordinate should monotonically decrease as the algorithm progresses.", currentEvent.GetType().Name, currentEvent.YCoordinate, state.SweepLineY)); // Advance the sweep line to the y-coordinate of the current event. state.SweepLineY = currentEvent.YCoordinate; // Handle the event based on its type. if (currentEvent is SiteEvent) HandleSiteEvent((SiteEvent)currentEvent, state); else HandleCircleEvent((CircleEvent)currentEvent, state); } }
private void HandleSiteEvent(SiteEvent ev, State state) { // If the beach line data structure is empty, initialize // it with the arc created by the new site into it and return. if (state.BeachLine == null) { state.BeachLine = new ArcNode(ev.Site); return; } // Find the arc split by the new site. var splitArcNode = Helpers.FindArcSplitByNewSite(ev.Site.Position, state.BeachLine); // If the arc being split has a circle event, it is a false alarm, // so delete it from the event queue. if (splitArcNode.DisappearanceEvent != null) state.EventQueue.Remove(splitArcNode.DisappearanceEvent.Index); // The following pieces of the final Voronoi diagram are created // during a site event: // - The Face defined by the new site. // - Both HalfEdges of the edge that will be traced out by the // two new breakpoints. var newFace = new Face {UserData = ev.Site.UserData}; var halfEdgeFacingOldSite = new HalfEdge(); var halfEdgeFacingNewSite = new HalfEdge(); state.Faces.Add(ev.Site, newFace); state.HalfEdges.Add(halfEdgeFacingOldSite); state.HalfEdges.Add(halfEdgeFacingNewSite); // Link all the diagram pieces together that can be linked at this time. halfEdgeFacingOldSite.Interior = state.Faces[splitArcNode.DefiningSite]; halfEdgeFacingNewSite.Interior = newFace; halfEdgeFacingOldSite.Twin = halfEdgeFacingNewSite; halfEdgeFacingNewSite.Twin = halfEdgeFacingOldSite; // During a site event, an existing arc is split into two // new arcs with an additional arc in the middle. We reflect // this change in beach line status tree data structure by // replacing the split arc node with a new subtree with five // nodes total: two for the two new breakpoints, and three // for the three new arcs on the beach line. var leftBP = new BreakpointNode(ev.Site, splitArcNode.DefiningSite, halfEdgeFacingOldSite, true); var rightBP = new BreakpointNode(ev.Site, splitArcNode.DefiningSite, halfEdgeFacingNewSite, false); var leftArc = new ArcNode(splitArcNode.DefiningSite); var middleArc = new ArcNode(ev.Site); var rightArc = new ArcNode(splitArcNode.DefiningSite); // Set up new subtree. leftBP.LeftChild = leftArc; leftBP.RightChild = rightBP; rightBP.LeftChild = middleArc; rightBP.RightChild = rightArc; rightBP.Parent = leftBP; leftArc.Parent = leftBP; middleArc.Parent = rightBP; rightArc.Parent = rightBP; // Graft new subtree into existing beach line status tree data structure. // First check for the special case where the split arc node was the // root element of the tree (aka the only element). if (splitArcNode.Parent == null) { if (state.BeachLine != splitArcNode) throw new SanityCheckFailedException( "The splitArcNode's parent was null, but it was not the root of the beach line status tree data structure."); state.BeachLine = leftBP; } // Otherwise, graft into existing tree. Here is where // we would perform rebalancing operations on the tree. else { if (splitArcNode.Parent.LeftChild == splitArcNode) { splitArcNode.Parent.LeftChild = leftBP; leftBP.Parent = splitArcNode.Parent; } else { splitArcNode.Parent.RightChild = leftBP; leftBP.Parent = splitArcNode.Parent; } } }
private void HandleCircleEvent(CircleEvent ev, State state) { }