private static void CheckCircle(RedBlackTreeNode <BeachSection> section, MinHeap <FortuneEvent> eventQueue) { RedBlackTreeNode <BeachSection> left = section.previous; RedBlackTreeNode <BeachSection> right = section.next; if (left == null || right == null) { return; } FortuneSite leftSite = left.data.site; FortuneSite centerSite = section.data.site; FortuneSite rightSite = right.data.site; if (leftSite == rightSite) { return; } double bX = centerSite.x; double bY = centerSite.y; double aX = leftSite.x - bX; double aY = leftSite.y - bY; double cX = rightSite.x - bX; double cY = rightSite.y - bY; double delta = aX * cY - aY * cX; if (delta.ApproxGreaterThanOrEqualTo(0)) { return; } double magnitudeA = aX * aX + aY * aY; double magnitudeC = cX * cX + cY * cY; double x = (cY * magnitudeA - aY * magnitudeC) / (2 * delta); double y = (aX * magnitudeC - cX * magnitudeA) / (2 * delta); double yCenter = y + bY; FortuneCircleEvent circleEvent = new FortuneCircleEvent( new Point(x + bX, yCenter + Math.Sqrt(x * x + y * y)), yCenter, section ); section.data.circleEvent = circleEvent; eventQueue.Insert(circleEvent); }
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 Point(x + bx, ycenter + Math.Sqrt(x * x + y * y)), ycenter, section ); section.Data.CircleEvent = circleEvent; eventQueue.Insert(circleEvent); }
internal void RemoveBeachSection(FortuneCircleEvent circle, MinHeap <FortuneEvent> eventQueue, HashSet <FortuneCircleEvent> deleted, LinkedList <VoronoiEdge> edges) { var section = circle.ToDelete; var x = circle.X; var y = circle.YCenter; var vertex = new Point(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.EndPoint = vertex; section.Next.Data.Edge.EndPoint = 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.EndPoint = vertex; remove.Next.Data.Edge.EndPoint = 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 VoronoiEdge(vertex, next.Data.Site, prev.Data.Site); next.Data.Edge = newEdge; edges.AddFirst(newEdge); //add neighbors for delaunay prev.Data.Site.Neighbours.Add(next.Data.Site); next.Data.Site.Neighbours.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); }
internal BeachSection(FSite site) { Site = site; CircleEvent = null; }
public void RemoveBeachSection(FortuneCircleEvent circle, MinHeap <FortuneEvent> eventQueue, HashSet <FortuneCircleEvent> deleted, LinkedList <Edge> edges) { RedBlackTreeNode <BeachSection> section = circle.toDelete; double x = circle.x; double y = circle.yCenter; Point vertex = new Point(x, y); List <RedBlackTreeNode <BeachSection> > toBeRemoved = new List <RedBlackTreeNode <BeachSection> >(); RedBlackTreeNode <BeachSection> previous = section.previous; while (previous.data.circleEvent != null && (x - previous.data.circleEvent.x).ApproxEqual(0) && (y - previous.data.circleEvent.y).ApproxEqual(0)) { toBeRemoved.Add(previous); previous = previous.previous; } RedBlackTreeNode <BeachSection> 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; foreach (RedBlackTreeNode <BeachSection> toRemove in toBeRemoved) { toRemove.data.edge.end = vertex; toRemove.next.data.edge.end = vertex; deleted.Add(toRemove.data.circleEvent); toRemove.data.circleEvent = null; } if (previous.data.circleEvent != null) { deleted.Add(previous.data.circleEvent); previous.data.circleEvent = null; } if (next.data.circleEvent != null) { deleted.Add(next.data.circleEvent); next.data.circleEvent = null; } Edge newEdge = new Edge(vertex, next.data.site, previous.data.site); next.data.edge = newEdge; edges.AddFirst(newEdge); previous.data.site.neighbours.Add(next.data.site); next.data.site.neighbours.Add(previous.data.site); sections.Remove(section); foreach (RedBlackTreeNode <BeachSection> toRemove in toBeRemoved) { sections.Remove(toRemove); } CheckCircle(previous, eventQueue); CheckCircle(next, eventQueue); }
public BeachSection(FortuneSite site) { this.site = site; this.circleEvent = null; }