/// <summary> /// Circles the check data node. /// </summary> /// <returns> /// The check data node. /// </returns> /// <param name='n'> /// N. /// </param> /// <param name='ys'> /// Ys. /// </param> public static VCircleEvent CircleCheckDataNode(VDataNode n, double ys) { VDataNode l = VNode.LeftDataNode(n); VDataNode r = VNode.RightDataNode(n); if (l == null || r == null || l.DataPoint == r.DataPoint || l.DataPoint == n.DataPoint || n.DataPoint == r.DataPoint) { return(null); } if (MathTools.ccw(l.DataPoint.X, l.DataPoint.Y, n.DataPoint.X, n.DataPoint.Y, r.DataPoint.X, r.DataPoint.Y, false) <= 0) { return(null); } Vector2D Center = Fortune.CircumCircleCenter(l.DataPoint, n.DataPoint, r.DataPoint); VCircleEvent VC = new VCircleEvent(); VC.NodeN = n; VC.NodeL = l; VC.NodeR = r; VC.Center = Center; VC.Valid = true; if (VC.Y >= ys) { return(VC); } return(null); }
/// <summary> /// Computes the voronoi graph. /// </summary> /// <returns> /// The voronoi graph. /// </returns> /// <param name='Datapoints'> /// Datapoints. /// </param> /// <exception cref='Exception'> /// Represents errors that occur during application execution. /// </exception> public static VoronoiGraph ComputeVoronoiGraph(IEnumerable Datapoints) { PriorityQueue <VEvent> PQ = new PriorityQueue <VEvent>(PriorityQueueType.Minimum); Hashtable CurrentCircles = new Hashtable(); VoronoiGraph VG = new VoronoiGraph(); VNode RootNode = null; foreach (Vector2D V in Datapoints) { PQ.Enqueue(new VDataEvent(V)); } while (PQ.Count > 0) { VEvent VE = PQ.Dequeue() as VEvent; VDataNode[] CircleCheckList; if (VE is VDataEvent) { RootNode = VNode.ProcessDataEvent(VE as VDataEvent, RootNode, VG, VE.Y, out CircleCheckList); } else if (VE is VCircleEvent) { CurrentCircles.Remove(((VCircleEvent)VE).NodeN); if (!((VCircleEvent)VE).Valid) { continue; } RootNode = VNode.ProcessCircleEvent(VE as VCircleEvent, RootNode, VG, VE.Y, out CircleCheckList); } else { throw new Exception("Got event of type " + VE.GetType().ToString() + "!"); } foreach (VDataNode VD in CircleCheckList) { if (CurrentCircles.ContainsKey(VD)) { ((VCircleEvent)CurrentCircles[VD]).Valid = false; CurrentCircles.Remove(VD); } VCircleEvent VCE = VNode.CircleCheckDataNode(VD, VE.Y); if (VCE != null) { PQ.Enqueue(VCE); CurrentCircles[VD] = VCE; } } if (VE is VDataEvent) { Vector2D DP = ((VDataEvent)VE).DataPoint; foreach (VCircleEvent VCE in CurrentCircles.Values) { if (MathTools.Dist(DP.X, DP.Y, VCE.Center.X, VCE.Center.Y) < VCE.Y - VCE.Center.Y && Math.Abs(MathTools.Dist(DP.X, DP.Y, VCE.Center.X, VCE.Center.Y) - (VCE.Y - VCE.Center.Y)) > 1e-10) { VCE.Valid = false; } } } } return(VG); }
/// <summary> /// Circles the check data node. /// </summary> /// <returns> /// The check data node. /// </returns> /// <param name='n'> /// N. /// </param> /// <param name='ys'> /// Ys. /// </param> public static VCircleEvent CircleCheckDataNode( VDataNode n, double ys ) { VDataNode l = VNode.LeftDataNode( n ); VDataNode r = VNode.RightDataNode( n ); if( l == null || r == null || l.DataPoint == r.DataPoint || l.DataPoint == n.DataPoint || n.DataPoint == r.DataPoint ) { return null; } if( MathTools.ccw( l.DataPoint.X, l.DataPoint.Y, n.DataPoint.X, n.DataPoint.Y, r.DataPoint.X, r.DataPoint.Y, false ) <= 0 ) { return null; } Vector2D Center = Fortune.CircumCircleCenter( l.DataPoint, n.DataPoint, r.DataPoint ); VCircleEvent VC = new VCircleEvent(); VC.NodeN = n; VC.NodeL = l; VC.NodeR = r; VC.Center = Center; VC.Valid = true; if( VC.Y >= ys ) { return VC; } return null; }
/// <summary> /// Processes the circle event. /// </summary> /// <returns> /// The circle event. /// </returns> /// <param name='e'> /// E. /// </param> /// <param name='Root'> /// Root. /// </param> /// <param name='VG'> /// V. /// </param> /// <param name='ys'> /// Ys. /// </param> /// <param name='CircleCheckList'> /// Circle check list. /// </param> public static VNode ProcessCircleEvent(VCircleEvent e, VNode Root, VoronoiGraph VG, double ys, out VDataNode[] CircleCheckList) { VDataNode a; VDataNode b; VDataNode c; VEdgeNode eu; VEdgeNode eo; b = e.NodeN; a = VNode.LeftDataNode(b); c = VNode.RightDataNode(b); if (a == null || b.Parent == null || c == null || !a.DataPoint.Equals(e.NodeL.DataPoint) || !c.DataPoint.Equals(e.NodeR.DataPoint)) { CircleCheckList = new VDataNode[] {}; return(Root); // Abbruch da sich der Graph ver 0/00ndert hat } eu = b.Parent as VEdgeNode; CircleCheckList = new VDataNode[] { a, c }; //1. Create the new Vertex Vector2D VNew = new Vector2D(e.Center.X, e.Center.Y); VG.Vertizes.Add(VNew); //2. Find out if a or c are in a distand part of the tree (the other is then b's sibling) and assign the new vertex if (eu.Left == b) // c is sibling { eo = VNode.EdgeToRightDataNode(a); // replace eu by eu's Right eu.Parent.Replace(eu, eu.Right); } else // a is sibling { eo = VNode.EdgeToRightDataNode(b); // replace eu by eu's Left eu.Parent.Replace(eu, eu.Left); } eu.Edge.AddVertex(VNew); eo.Edge.AddVertex(VNew); //2. Replace eo by new Edge VoronoiEdge VE = new VoronoiEdge(); VE.LeftData = a.DataPoint; VE.RightData = c.DataPoint; VE.AddVertex(VNew); VG.Edges.Add(VE); VEdgeNode VEN = new VEdgeNode(VE, false); VEN.Left = eo.Left; VEN.Right = eo.Right; if (eo.Parent == null) { return(VEN); } eo.Parent.Replace(eo, VEN); return(Root); }
/// <summary> /// Processes the circle event. /// </summary> /// <returns> /// The circle event. /// </returns> /// <param name='e'> /// E. /// </param> /// <param name='Root'> /// Root. /// </param> /// <param name='VG'> /// V. /// </param> /// <param name='ys'> /// Ys. /// </param> /// <param name='CircleCheckList'> /// Circle check list. /// </param> public static VNode ProcessCircleEvent( VCircleEvent e, VNode Root, VoronoiGraph VG, double ys, out VDataNode[] CircleCheckList ) { VDataNode a; VDataNode b; VDataNode c; VEdgeNode eu; VEdgeNode eo; b = e.NodeN; a = VNode.LeftDataNode( b ); c = VNode.RightDataNode( b ); if( a == null || b.Parent == null || c == null || !a.DataPoint.Equals( e.NodeL.DataPoint ) || !c.DataPoint.Equals( e.NodeR.DataPoint ) ) { CircleCheckList = new VDataNode[]{}; return Root; // Abbruch da sich der Graph ver 0/00ndert hat } eu = b.Parent as VEdgeNode; CircleCheckList = new VDataNode[] {a,c}; //1. Create the new Vertex Vector2D VNew = new Vector2D( e.Center.X, e.Center.Y ); VG.Vertizes.Add( VNew ); //2. Find out if a or c are in a distand part of the tree (the other is then b's sibling) and assign the new vertex if( eu.Left == b ) { // c is sibling eo = VNode.EdgeToRightDataNode( a ); // replace eu by eu's Right eu.Parent.Replace( eu, eu.Right ); } else { // a is sibling eo = VNode.EdgeToRightDataNode( b ); // replace eu by eu's Left eu.Parent.Replace( eu, eu.Left ); } eu.Edge.AddVertex( VNew ); eo.Edge.AddVertex( VNew ); //2. Replace eo by new Edge VoronoiEdge VE = new VoronoiEdge(); VE.LeftData = a.DataPoint; VE.RightData = c.DataPoint; VE.AddVertex( VNew ); VG.Edges.Add( VE ); VEdgeNode VEN = new VEdgeNode( VE, false ); VEN.Left = eo.Left; VEN.Right = eo.Right; if( eo.Parent == null ) { return VEN; } eo.Parent.Replace( eo, VEN ); return Root; }