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.Equals(r.DataPoint) || l.DataPoint.Equals(n.DataPoint) || n.DataPoint.Equals(r.DataPoint)) { return(null); } if (ccw(l.DataPoint.X, l.DataPoint.Y, n.DataPoint.X, n.DataPoint.Y, r.DataPoint.X, r.DataPoint.Y, false) <= 0) { return(null); } Vector2 Center = 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 || Math.Abs(VC.Y - ys) < 1e-10) { return(VC); } return(null); }
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[0], l.DataPoint[1], n.DataPoint[0], n.DataPoint[1], r.DataPoint[0], r.DataPoint[1], false) <= 0) { return(null); } Vector Center = CircleCentre(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); }
public static VNode ProcessCircleEvent(VCircleEvent e, VNode root, VoronoiGraph vg, out VDataNode[] circleCheckList) { VEdgeNode eo; var b = e.NodeN; var a = LeftDataNode(b); var c = 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ändert hat } var eu = (VEdgeNode)b.Parent; circleCheckList = new[] { a, c }; //1. Create the new Vertex var vNew = new Vector2((float)e.CenterX, (float)e.CenterY); vg.AddVertex(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 = EdgeToRightDataNode(a); // replace eu by eu's Right eu.Parent.Replace(eu, eu.Right); } else // a is sibling { eo = 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 var ve = new VoronoiEdge { LeftData = a.DataPoint, RightData = c.DataPoint }; ve.AddVertex(vNew); vg.AddEdge(ve); var ven = new VEdgeNode(ve, false) { Left = eo.Left, Right = eo.Right }; if (eo.Parent == null) { return(ven); } eo.Parent.Replace(eo, ven); return(root); }
private static VNode ProcessCircleEvent(VCircleEvent e, VNode Root, VoronoiGraph VG, double ys, out VDataNode[] CircleCheckList) { VDataNode a, b, c; VEdgeNode e1, e2; 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); // повертаємось, бо графік змінився } e1 = (VEdgeNode)b.Parent; CircleCheckList = new VDataNode[] { a, c }; //Створюємо нову вершину Vector VNew = new Vector(e.Center[0], e.Center[1]); VG.Vertizes.Add(VNew); //2. виясняємо, чи а або с знаходяться у віддаленій частині дерева (інший - брат b), і призначаємо нову вершину if (e1.Left == b) // c - брат { e2 = VNode.EdgeToRightDataNode(a); // замінюємо e1 правим нащадком e1.Parent.Replace(e1, e1.Right); } else // a - брат { e2 = VNode.EdgeToRightDataNode(b); // замінюємо e1 лівим нащадком e1.Parent.Replace(e1, e1.Left); } e1.Edge.AddVertex(VNew); e2.Edge.AddVertex(VNew); //Замінюємо e2 новим ребром 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 = e2.Left; VEN.Right = e2.Right; if (e2.Parent == null) { return(VEN); } e2.Parent.Replace(e2, VEN); return(Root); }
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[0], l.DataPoint[1], n.DataPoint[0], n.DataPoint[1], r.DataPoint[0], r.DataPoint[1], false) <= 0) return null; Vector Center = CircleCentre(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; }
public static VCircleEvent CircleCheckDataNode(VDataNode n, double ys) { VDataNode l = NodeHandler.LeftDataNode(n); VDataNode r = NodeHandler.RightDataNode(n); if (l == null || r == null || l.DataPoint == r.DataPoint || l.DataPoint == n.DataPoint || n.DataPoint == r.DataPoint) { return(null); } if (Ccw(l.DataPoint[0], l.DataPoint[1], n.DataPoint[0], n.DataPoint[1], r.DataPoint[0], r.DataPoint[1], false) <= 0) { return(null); } var center = CircumCircleCenter(l.DataPoint, n.DataPoint, r.DataPoint); var vc = new VCircleEvent(); vc.NodeN = n; vc.NodeL = l; vc.NodeR = r; vc.Center = center; vc.Valid = true; return(vc.Y >= ys ? vc : null); }
public static VCircleEvent CircleCheckDataNode(VDataNode n, double ys) { var l = LeftDataNode(n); var r = RightDataNode(n); if (l == null || r == null || l.DataPoint.Equals(r.DataPoint) || l.DataPoint.Equals(n.DataPoint) || n.DataPoint.Equals(r.DataPoint)) { return(null); } if (Fortune.Ccw(l.DataPoint[0], l.DataPoint[1], n.DataPoint[0], n.DataPoint[1], r.DataPoint[0], r.DataPoint[1], false) <= 0) { return(null); } var center = Fortune.CircumCircleCenter(l.DataPoint, n.DataPoint, r.DataPoint); var vc = new VCircleEvent { NodeN = n, NodeL = l, NodeR = r, CenterX = center[0], CenterY = center[1], Valid = true }; if (vc.Y > ys || Math.Abs(vc.Y - ys) < 1e-10) { return(vc); } return(null); }
public static VNode ProcessCircleEvent(VCircleEvent e, VNode Root, VoronoiDiagram VG, double ys, out VDataNode[] CircleCheckList) { VDataNode a, b, c; VEdgeNode eu, 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ändert hat } eu = (VEdgeNode)b.Parent; CircleCheckList = new VDataNode[] { a, c }; //1. Create the new Vertex Vector2 VNew = new Vector2(e.Center.X, e.Center.Y); // VNew[0] = Fortune.ParabolicCut(a.DataPoint[0],a.DataPoint[1],c.DataPoint[0],c.DataPoint[1],ys); // VNew[1] = (ys + a.DataPoint[1])/2 - 1/(2*(ys-a.DataPoint[1]))*(VNew[0]-a.DataPoint[0])*(VNew[0]-a.DataPoint[0]); 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); // ///////////////////// uncertain // if(eo==eu) // return Root; // ///////////////////// //complete & cleanup eo eo.Edge.AddVertex(VNew); //while(eo.Edge.VVertexB == Fortune.VVUnkown) //{ // eo.Flipped = !eo.Flipped; // eo.Edge.AddVertex(Fortune.VVInfinite); //} //if(eo.Flipped) //{ // Vector2 T = eo.Edge.LeftData; // eo.Edge.LeftData = eo.Edge.RightData; // eo.Edge.RightData = T; //} //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); }
public static VoronoiDiagram ComputeForPoints(IEnumerable <Vector2> Datapoints) { var PQ = new MinHeap <VEvent>(); var CurrentCircles = new Dictionary <VDataNode, VCircleEvent>(); VoronoiDiagram VG = new VoronoiDiagram(); VNode RootNode = null; foreach (Vector2 V in Datapoints) { PQ.Add(new VDataEvent(V)); } while (PQ.Count > 0) { VEvent VE = PQ.ExtractDominating() 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.Add(VCE); CurrentCircles[VD] = VCE; } } if (VE is VDataEvent) { Vector2 DP = ((VDataEvent)VE).DataPoint; foreach (VCircleEvent VCE in CurrentCircles.Values) { if (Vector2.DistanceBetweenPoints(DP, VCE.Center) < VCE.Y - VCE.Center.Y && Math.Abs(Vector2.DistanceBetweenPoints(DP, VCE.Center) - (VCE.Y - VCE.Center.Y)) > 1e-10) { VCE.Valid = false; } } } } VNode.CleanUpTree(RootNode); foreach (VoronoiEdge VE in VG.Edges) { if (VE.Done) { continue; } if (VE.VVertexB.IsNaN) { VE.AddVertex(VVInfinite); if (Math.Abs(VE.LeftData.Y - VE.RightData.Y) < 1e-10 && VE.LeftData.X < VE.RightData.X) { Vector2 T = VE.LeftData; VE.LeftData = VE.RightData; VE.RightData = T; } } } var MinuteEdges = new List <VoronoiEdge>(); foreach (VoronoiEdge VE in VG.Edges) { if (!VE.IsPartlyInfinite && VE.VVertexA.Equals(VE.VVertexB)) { MinuteEdges.Add(VE); // prevent rounding errors from expanding to holes foreach (VoronoiEdge VE2 in VG.Edges) { if (VE2.VVertexA.Equals(VE.VVertexA)) { VE2.VVertexA = VE.VVertexA; } if (VE2.VVertexB.Equals(VE.VVertexA)) { VE2.VVertexB = VE.VVertexA; } } } } foreach (VoronoiEdge VE in MinuteEdges) { VG.Edges.Remove(VE); } return(VG); }
private static VNode ProcessCircleEvent(VCircleEvent e, VNode Root, VoronoiGraph VG, double ys, out VDataNode[] CircleCheckList) { VDataNode a, b, c; VEdgeNode e1, e2; 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; // повертаємось, бо графік змінився } e1 = (VEdgeNode)b.Parent; CircleCheckList = new VDataNode[] { a, c }; //Створюємо нову вершину Vector VNew = new Vector(e.Center[0], e.Center[1]); VG.Vertizes.Add(VNew); //2. виясняємо, чи а або с знаходяться у віддаленій частині дерева (інший - брат b), і призначаємо нову вершину if (e1.Left == b) // c - брат { e2 = VNode.EdgeToRightDataNode(a); // замінюємо e1 правим нащадком e1.Parent.Replace(e1, e1.Right); } else // a - брат { e2 = VNode.EdgeToRightDataNode(b); // замінюємо e1 лівим нащадком e1.Parent.Replace(e1, e1.Left); } e1.Edge.AddVertex(VNew); e2.Edge.AddVertex(VNew); //Замінюємо e2 новим ребром 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 = e2.Left; VEN.Right = e2.Right; if (e2.Parent == null) return VEN; e2.Parent.Replace(e2, VEN); return Root; }
public static VoronoiGraph FortuneAlgo(List <Vector> points) { BinaryPriorityQueue PQ = new BinaryPriorityQueue(); Hashtable CurrentCircles = new Hashtable(); VoronoiGraph VG = new VoronoiGraph(); VNode RootNode = null; for (int i = 0; i < points.Count; ++i) { PQ.Push(new VDataEvent(points[i])); } while (PQ.Count > 0) { VEvent VE = PQ.Pop() as VEvent; VDataNode[] CircleCheckList; if (VE is VDataEvent) { RootNode = 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 = 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 = CircleCheckDataNode(VD, VE.Y); if (VCE != null) { PQ.Push(VCE); CurrentCircles[VD] = VCE; } } if (VE is VDataEvent) { Vector DP = ((VDataEvent)VE).DataPoint; foreach (VCircleEvent VCE in CurrentCircles.Values) { if (MathTools.Dist(DP[0], DP[1], VCE.Center[0], VCE.Center[1]) < VCE.Y - VCE.Center[1] && Math.Abs(MathTools.Dist(DP[0], DP[1], VCE.Center[0], VCE.Center[1]) - (VCE.Y - VCE.Center[1])) > 1e-10) { VCE.Valid = false; } } } } VNode.CleanUpTree(RootNode); foreach (VoronoiEdge VE in VG.Edges) { if (VE.Done) { continue; } if (VE.VVertexB == Fortune.VVUnkown) { VE.AddVertex(Fortune.VVInfinite); if (Math.Abs(VE.LeftData[1] - VE.RightData[1]) < 1e-10 && VE.LeftData[0] < VE.RightData[0]) { Vector T = VE.LeftData; VE.LeftData = VE.RightData; VE.RightData = T; } } } ArrayList MinuteEdges = new ArrayList(); foreach (VoronoiEdge VE in VG.Edges) { if (!VE.IsPartlyInfinite && VE.VVertexA.Equals(VE.VVertexB)) { MinuteEdges.Add(VE); foreach (VoronoiEdge VE2 in VG.Edges) { if (VE2.VVertexA.Equals(VE.VVertexA)) { VE2.VVertexA = VE.VVertexA; } if (VE2.VVertexB.Equals(VE.VVertexA)) { VE2.VVertexB = VE.VVertexA; } } } } foreach (VoronoiEdge VE in MinuteEdges) { VG.Edges.Remove(VE); } return(VG); }