internal void RemoveBeachSection(FortuneCircleEvent circle, MinHeap <FortuneEvent> eventQueue, HashSet <FortuneCircleEvent> deleted, LinkedList <VEdge> edges) { var section = circle.ToDelete; var x = circle.X; var y = circle.YCenter; var vertex = new VPoint(x, y); //multiple edges could end here var toBeRemoved = new List <RBTreeNode <BeachSection> >(); //look left var prev = section.Previous; while (prev.Data.CircleEvent != null && (x - prev.Data.CircleEvent.X).ApproxEqual(0) && (y - prev.Data.CircleEvent.Y).ApproxEqual(0)) { toBeRemoved.Add(prev); prev = prev.Previous; } var next = section.Next; while (next.Data.CircleEvent != null && (x - next.Data.CircleEvent.X).ApproxEqual(0) && (y - next.Data.CircleEvent.Y).ApproxEqual(0)) { toBeRemoved.Add(next); next = next.Next; } section.Data.Edge.End = vertex; section.Next.Data.Edge.End = vertex; section.Data.CircleEvent = null; //odds are this double writes a few edges but this is clean... foreach (var remove in toBeRemoved) { remove.Data.Edge.End = vertex; remove.Next.Data.Edge.End = vertex; deleted.Add(remove.Data.CircleEvent); remove.Data.CircleEvent = null; } //need to delete all upcoming circle events with this node if (prev.Data.CircleEvent != null) { deleted.Add(prev.Data.CircleEvent); prev.Data.CircleEvent = null; } if (next.Data.CircleEvent != null) { deleted.Add(next.Data.CircleEvent); next.Data.CircleEvent = null; } //create a new edge with start point at the vertex and assign it to next var newEdge = new VEdge(vertex, next.Data.Site, prev.Data.Site); next.Data.Edge = newEdge; edges.AddFirst(newEdge); //add neighbors for delaunay prev.Data.Site.Neighbors.Add(next.Data.Site); next.Data.Site.Neighbors.Add(prev.Data.Site); //remove the sectionfrom the tree beachLine.RemoveNode(section); foreach (var remove in toBeRemoved) { beachLine.RemoveNode(remove); } CheckCircle(prev, eventQueue); CheckCircle(next, eventQueue); }
private static void CheckCircle(RBTreeNode <BeachSection> section, MinHeap <FortuneEvent> eventQueue) { //if (section == null) // return; var left = section.Previous; var right = section.Next; if (left == null || right == null) { return; } var leftSite = left.Data.Site; var centerSite = section.Data.Site; var rightSite = right.Data.Site; //if the left arc and right arc are defined by the same //focus, the two arcs cannot converge if (leftSite == rightSite) { return; } // http://mathforum.org/library/drmath/view/55002.html // because every piece of this program needs to be demoed in maple >.< //MATH HACKS: place center at origin and //draw vectors a and c to //left and right respectively double bx = centerSite.X, by = centerSite.Y, ax = leftSite.X - bx, ay = leftSite.Y - by, cx = rightSite.X - bx, cy = rightSite.Y - by; //The center beach section can only dissapear when //the angle between a and c is negative var d = ax * cy - ay * cx; if (d.ApproxGreaterThanOrEqualTo(0)) { return; } var magnitudeA = ax * ax + ay * ay; var magnitudeC = cx * cx + cy * cy; var x = (cy * magnitudeA - ay * magnitudeC) / (2 * d); var y = (ax * magnitudeC - cx * magnitudeA) / (2 * d); //add back offset var ycenter = y + by; //y center is off var circleEvent = new FortuneCircleEvent( new VPoint(x + bx, ycenter + Math.Sqrt(x * x + y * y)), ycenter, section ); section.Data.CircleEvent = circleEvent; eventQueue.Insert(circleEvent); }
internal BeachSection(FortuneSite site) { Site = site; CircleEvent = null; }