public Generator(int size) { _size = size; GenerateSquareGrid(size); _voronoiGraph = Fortune.ComputeVoronoiGraph(_points); BuildGraph(); ImproveCorners(); }
/// <summary> /// Will return the new root (unchanged except in start-up) /// </summary> public static VNode ProcessDataEvent(VDataEvent e, VNode root, VoronoiGraph vg, double ys, out VDataNode[] circleCheckList) { if (root == null) { root = new VDataNode(e.DataPoint); circleCheckList = new[] { (VDataNode)root }; return(root); } //1. Find the node to be replaced VNode c = FindDataNode(root, ys, e.DataPoint[0]); //2. Create the subtree (ONE Edge, but two VEdgeNodes) var ve = new VoronoiEdge { LeftData = ((VDataNode)c).DataPoint, RightData = e.DataPoint, VVertexA = Fortune.VvUnkown, VVertexB = Fortune.VvUnkown }; vg.Edges.Add(ve); VNode subRoot; if (Math.Abs(ve.LeftData[1] - ve.RightData[1]) < 1e-10) { if (ve.LeftData[0] < ve.RightData[0]) { subRoot = new VEdgeNode(ve, false) { Left = new VDataNode(ve.LeftData), Right = new VDataNode(ve.RightData) }; } else { subRoot = new VEdgeNode(ve, true) { Left = new VDataNode(ve.RightData), Right = new VDataNode(ve.LeftData) }; } circleCheckList = new[] { (VDataNode)subRoot.Left, (VDataNode)subRoot.Right }; } else { subRoot = new VEdgeNode(ve, false) { Left = new VDataNode(ve.LeftData), Right = new VEdgeNode(ve, true) { Left = new VDataNode(ve.RightData), Right = new VDataNode(ve.LeftData) } }; circleCheckList = new[] { (VDataNode)subRoot.Left, (VDataNode)subRoot.Right.Left, (VDataNode)subRoot.Right.Right }; } //3. Apply subtree if (c.Parent == null) { return(subRoot); } c.Parent.Replace(c, subRoot); return(root); }
/// <summary> /// Will return the new root (unchanged except in start-up) /// </summary> public static VNode ProcessDataEvent(VDataEvent e, VNode Root, VoronoiGraph VG, double ys, out VDataNode[] CircleCheckList) { if(Root==null) { Root = new VDataNode(e.DataPoint); CircleCheckList = new VDataNode[] {(VDataNode)Root}; return Root; } //1. Find the node to be replaced VNode C = VNode.FindDataNode(Root, ys, e.DataPoint.X); //2. Create the subtree (ONE Edge, but two VEdgeNodes) VoronoiEdge VE = new VoronoiEdge(); VE.LeftData = ((VDataNode)C).DataPoint; VE.RightData = e.DataPoint; VE.VVertexA = Fortune.VVUnkown; VE.VVertexB = Fortune.VVUnkown; VG.Edges.Add(VE); VNode SubRoot; if(Math.Abs(VE.LeftData.Y-VE.RightData.Y)<1e-10) { if(VE.LeftData.X<VE.RightData.X) { SubRoot = new VEdgeNode(VE,false); SubRoot.Left = new VDataNode(VE.LeftData); SubRoot.Right = new VDataNode(VE.RightData); } else { SubRoot = new VEdgeNode(VE,true); SubRoot.Left = new VDataNode(VE.RightData); SubRoot.Right = new VDataNode(VE.LeftData); } CircleCheckList = new VDataNode[] {(VDataNode)SubRoot.Left,(VDataNode)SubRoot.Right}; } else { SubRoot = new VEdgeNode(VE,false); SubRoot.Left = new VDataNode(VE.LeftData); SubRoot.Right = new VEdgeNode(VE,true); SubRoot.Right.Left = new VDataNode(VE.RightData); SubRoot.Right.Right = new VDataNode(VE.LeftData); CircleCheckList = new VDataNode[] {(VDataNode)SubRoot.Left,(VDataNode)SubRoot.Right.Left,(VDataNode)SubRoot.Right.Right}; } //3. Apply subtree if(C.Parent == null) return SubRoot; C.Parent.Replace(C,SubRoot); return Root; }
public static VNode ProcessCircleEvent(VCircleEvent e, VNode Root, VoronoiGraph 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 Point VNew = new Point(e.Center.X,e.Center.Y); // VNew.X = Fortune.ParabolicCut(a.DataPoint.X,a.DataPoint.Y,c.DataPoint.X,c.DataPoint.Y,ys); // VNew.Y = (ys + a.DataPoint.Y)/2 - 1/(2*(ys-a.DataPoint.Y))*(VNew.X-a.DataPoint.X)*(VNew.X-a.DataPoint.X); 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) //{ // Vector 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 VoronoiGraph ComputeVoronoiGraph(Dictionary<Point, VoronoiCell> cells) { BinaryPriorityQueue PQ = new BinaryPriorityQueue(); Hashtable CurrentCircles = new Hashtable(); VoronoiGraph VG = new VoronoiGraph(); VNode RootNode = null; foreach(Point V in cells.Keys) { PQ.Push(new VDataEvent(V)); } while(PQ.Count>0) { VEvent VE = PQ.Pop() 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.Push(VCE); CurrentCircles[VD]=VCE; } } if(VE is VDataEvent) { Point DP = ((VDataEvent)VE).DataPoint; foreach(VCircleEvent VCE in CurrentCircles.Values) { if (MathF.Dist(DP.X, DP.Y, VCE.Center.X, VCE.Center.Y) < VCE.Y - VCE.Center.Y && Math.Abs(MathF.Dist(DP.X, DP.Y, VCE.Center.X, VCE.Center.Y) - (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.IsUndefined) { VE.AddVertex(Fortune.VVInfinite); if(Math.Abs(VE.LeftData.Y-VE.RightData.Y)<1e-10 && VE.LeftData.X<VE.RightData.X) { Point T = VE.LeftData; VE.LeftData = VE.RightData; VE.RightData = T; } } } ArrayList MinuteEdges = new ArrayList(); foreach (var edge in VG.Edges) { double ax = Math.Round(edge.VVertexA.X, Vector.Precision), ay = Math.Round(edge.VVertexA.Y, Vector.Precision), bx = Math.Round(edge.VVertexB.X, Vector.Precision), by = Math.Round(edge.VVertexB.Y, Vector.Precision); if (ax == bx && ay == by) { MinuteEdges.Add(edge); continue; } edge.VVertexA = new Point(ax, ay); edge.VVertexB = new Point(bx, by); } foreach(VoronoiEdge VE in MinuteEdges) VG.Edges.Remove(VE); foreach (var edge in VG.Edges) { VoronoiCell rightCell = cells[edge.RightData], leftCell = cells[edge.LeftData]; if (!rightCell.Edges.Contains(edge)) { rightCell.Edges.Add(edge); } if (!leftCell.Edges.Contains(edge)) { leftCell.Edges.Add(edge); } } VG.Cells = cells; return VG; }
public static VoronoiGraph FilterVG(VoronoiGraph VG, double minLeftRightDist) { VoronoiGraph VGErg = new VoronoiGraph(); foreach(VoronoiEdge VE in VG.Edges) { if(Math.Sqrt(Point.DistSqr(VE.LeftData,VE.RightData))>=minLeftRightDist) VGErg.Edges.Add(VE); } foreach(VoronoiEdge VE in VGErg.Edges) { VGErg.Vertizes.Add(VE.VVertexA); VGErg.Vertizes.Add(VE.VVertexB); } return VGErg; }
public static VoronoiGraph ComputeVoronoiGraph(IEnumerable<Vector2> points) { var pq = new MinHeap<VEvent>(); var currentCircles = new Dictionary<VDataNode, VCircleEvent>(); var vg = new VoronoiGraph(); VNode rootNode = null; foreach (var v in points) { pq.Add(new VDataEvent(v)); } while (pq.Count > 0) { var ve = pq.RemoveMin(); 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, out circleCheckList); } else throw new Exception("Got event of type " + ve.GetType() + "!"); foreach (var vd in circleCheckList) { if (currentCircles.ContainsKey(vd)) { currentCircles[vd].Valid = false; currentCircles.Remove(vd); } var vce = VNode.CircleCheckDataNode(vd, ve.Y); if (vce != null) { pq.Add(vce); currentCircles[vd] = vce; } } var evt = ve as VDataEvent; if (evt != null) { var dp = evt.DataPoint; foreach (var vce in currentCircles.Values) { if (Vector2.Distance(dp, vce.Center) < vce.Y - vce.Center.Y && Math.Abs(Vector2.Distance(dp, vce.Center) - (vce.Y - vce.Center.Y)) > 1e-10) vce.Valid = false; } } } VNode.CleanUpTree(rootNode as VEdgeNode); foreach (var ve in vg.Edges) { if (ve.Done) continue; if (!ve.VVertexB.HasValue) { ve.AddVertex(VvInfinite); if (Math.Abs(ve.LeftData.Y - ve.RightData.Y) < 1e-10 && ve.LeftData.X < ve.RightData.X) { var t = ve.LeftData; ve.LeftData = ve.RightData; ve.RightData = t; } } } var minuteEdges = new List<Edge>(); foreach (var ve in vg.Edges) { if (!ve.IsPartlyInfinite && ve.VVertexA.Equals(ve.VVertexB)) { minuteEdges.Add(ve); // prevent rounding errors from expanding to holes foreach (var 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 (var ve in minuteEdges) vg.MutableEdges.Remove(ve); return vg; }
public static VoronoiGraph ComputeVoronoiGraph(IEnumerable datapoints) { var pq = new BinaryPriorityQueue(); var currentCircles = new Hashtable(); var vg = new VoronoiGraph(); VNode rootNode = null; foreach (Vector v in datapoints) { pq.Push(new VDataEvent(v)); } while (pq.Count > 0) { var ve = pq.Pop() as VEvent; VDataNode[] circleCheckList; if (ve is VDataEvent) { rootNode = VNode.ProcessDataEvent(ve as VDataEvent, rootNode, vg, ve.Y, out circleCheckList); } else { var @event = ve as VCircleEvent; if (@event != null) { currentCircles.Remove(@event.NodeN); if ([email protected]) { continue; } rootNode = VNode.ProcessCircleEvent(@event, rootNode, vg, ve.Y, out circleCheckList); } else { throw new Exception($"Got event of type {ve?.GetType()}!"); } } foreach (var vd in circleCheckList) { if (currentCircles.ContainsKey(vd)) { ((VCircleEvent)currentCircles[vd]).Valid = false; currentCircles.Remove(vd); } var vce = VNode.CircleCheckDataNode(vd, ve.Y); if (vce == null) { continue; } pq.Push(vce); currentCircles[vd] = vce; } var dataEvent = ve as VDataEvent; if (dataEvent == null) { continue; } var dp = dataEvent.DataPoint; foreach (var vce in currentCircles.Values.Cast <VCircleEvent>().Where(vce => 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 (var ve in vg.Edges.Where(ve => !ve.Done).Where(ve => ve.VVertexB == VvUnkown)) { ve.AddVertex(VvInfinite); if (!(Math.Abs(ve.LeftData[1] - ve.RightData[1]) < 1e-10) || !(ve.LeftData[0] < ve.RightData[0])) { continue; } var T = ve.LeftData; ve.LeftData = ve.RightData; ve.RightData = T; } var minuteEdges = new ArrayList(); foreach (var ve in vg.Edges.Where(ve => !ve.IsPartlyInfinite && ve.VVertexA == ve.VVertexB)) { minuteEdges.Add(ve); // prevent rounding errors from expanding to holes foreach (var ve2 in vg.Edges) { if (ve2.VVertexA == ve.VVertexA) { ve2.VVertexA = ve.VVertexA; } if (ve2.VVertexB == ve.VVertexA) { ve2.VVertexB = ve.VVertexA; } } } foreach (VoronoiEdge ve in minuteEdges) { vg.Edges.Remove(ve); } return(vg); }
/// <summary> /// Will return the new root (unchanged except in start-up) /// </summary> public static VNode ProcessDataEvent(VDataEvent e, VNode root, VoronoiGraph vg, double ys, out VDataNode[] circleCheckList) { if (root == null) { root = new VDataNode(e.DataPoint); circleCheckList = new VDataNode[] { (VDataNode)root }; return root; } //1. Find the node to be replaced VNode c = FindDataNode(root, ys, e.DataPoint.X); //2. Create the subtree (ONE Edge, but two VEdgeNodes) var ve = new Edge { LeftData = ((VDataNode)c).DataPoint, RightData = e.DataPoint, VVertexA = null, VVertexB = null }; vg.MutableEdges.Add(ve); VNode subRoot; if (Math.Abs(ve.LeftData.Y - ve.RightData.Y) < 1e-10) { if (ve.LeftData.X < ve.RightData.X) { subRoot = new VEdgeNode(ve, false) { Left = new VDataNode(ve.LeftData), Right = new VDataNode(ve.RightData) }; } else { subRoot = new VEdgeNode(ve, true) { Left = new VDataNode(ve.RightData), Right = new VDataNode(ve.LeftData) }; } circleCheckList = new VDataNode[] { (VDataNode)subRoot.Left, (VDataNode)subRoot.Right }; } else { subRoot = new VEdgeNode(ve, false) { Left = new VDataNode(ve.LeftData), Right = new VEdgeNode(ve, true) { Left = new VDataNode(ve.RightData), Right = new VDataNode(ve.LeftData) } }; circleCheckList = new VDataNode[] { (VDataNode)subRoot.Left, (VDataNode)subRoot.Right.Left, (VDataNode)subRoot.Right.Right }; } //3. Apply subtree if (c.Parent == null) return subRoot; c.Parent.Replace(c, subRoot); return root; }
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 VDataNode[] { a, c }; //1. Create the new Vertex var vNew = new Vector2(e.Center.X, e.Center.Y); // VNew.X = Fortune.ParabolicCut(a.DataPoint.X,a.DataPoint.Y,c.DataPoint.X,c.DataPoint.Y,ys); // VNew.Y = (ys + a.DataPoint.Y)/2 - 1/(2*(ys-a.DataPoint.Y))*(VNew.X-a.DataPoint.X)*(VNew.X-a.DataPoint.X); vg.MutableVertices.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 = 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); // ///////////////////// 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) //{ // Vector T = eo.Edge.LeftData; // eo.Edge.LeftData = eo.Edge.RightData; // eo.Edge.RightData = T; //} //2. Replace eo by new Edge var ve = new Edge { LeftData = a.DataPoint, RightData = c.DataPoint }; ve.AddVertex(vNew); vg.MutableEdges.Add(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; }
public static VoronoiGraph ComputeVoronoiGraph(Dictionary <Point, VoronoiCell> cells) { BinaryPriorityQueue PQ = new BinaryPriorityQueue(); Hashtable CurrentCircles = new Hashtable(); VoronoiGraph VG = new VoronoiGraph(); VNode RootNode = null; foreach (Point V in cells.Keys) { PQ.Push(new VDataEvent(V)); } while (PQ.Count > 0) { VEvent VE = PQ.Pop() 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.Push(VCE); CurrentCircles[VD] = VCE; } } if (VE is VDataEvent) { Point DP = ((VDataEvent)VE).DataPoint; foreach (VCircleEvent VCE in CurrentCircles.Values) { if (MathF.Dist(DP.X, DP.Y, VCE.Center.X, VCE.Center.Y) < VCE.Y - VCE.Center.Y && Math.Abs(MathF.Dist(DP.X, DP.Y, VCE.Center.X, VCE.Center.Y) - (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.IsUndefined) { VE.AddVertex(Fortune.VVInfinite); if (Math.Abs(VE.LeftData.Y - VE.RightData.Y) < 1e-10 && VE.LeftData.X < VE.RightData.X) { Point T = VE.LeftData; VE.LeftData = VE.RightData; VE.RightData = T; } } } ArrayList MinuteEdges = new ArrayList(); foreach (var edge in VG.Edges) { double ax = Math.Round(edge.VVertexA.X, Vector.Precision), ay = Math.Round(edge.VVertexA.Y, Vector.Precision), bx = Math.Round(edge.VVertexB.X, Vector.Precision), by = Math.Round(edge.VVertexB.Y, Vector.Precision); if (ax == bx && ay == by) { MinuteEdges.Add(edge); continue; } edge.VVertexA = new Point(ax, ay); edge.VVertexB = new Point(bx, by); } foreach (VoronoiEdge VE in MinuteEdges) { VG.Edges.Remove(VE); } foreach (var edge in VG.Edges) { VoronoiCell rightCell = cells[edge.RightData], leftCell = cells[edge.LeftData]; if (!rightCell.Edges.Contains(edge)) { rightCell.Edges.Add(edge); } if (!leftCell.Edges.Contains(edge)) { leftCell.Edges.Add(edge); } } VG.Cells = cells; return(VG); }
public static VNode ProcessCircleEvent(VCircleEvent e, VNode Root, VoronoiGraph 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 Point VNew = new Point(e.Center.X, e.Center.Y); // VNew.X = Fortune.ParabolicCut(a.DataPoint.X,a.DataPoint.Y,c.DataPoint.X,c.DataPoint.Y,ys); // VNew.Y = (ys + a.DataPoint.Y)/2 - 1/(2*(ys-a.DataPoint.Y))*(VNew.X-a.DataPoint.X)*(VNew.X-a.DataPoint.X); 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) //{ // Vector 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 VoronoiGraph ComputeVoronoiGraph(IEnumerable Datapoints) { BinaryPriorityQueue PQ = new BinaryPriorityQueue(); Hashtable CurrentCircles = new Hashtable(); VoronoiGraph VG = new VoronoiGraph(); VNode RootNode = null; foreach (Vector V in Datapoints) { PQ.Push(new VDataEvent(V)); } while (PQ.Count > 0) { VEvent VE = PQ.Pop() 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.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); // 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); }
public static VNode ProcessCircleEvent(VCircleEvent e, VNode root, VoronoiGraph vg, double ys, 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 != e.NodeL.DataPoint || c.DataPoint != 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 Vector(e.Center[0], e.Center[1]); // 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 = 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); // ///////////////////// 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) //{ // Vector T = eo.Edge.LeftData; // eo.Edge.LeftData = eo.Edge.RightData; // eo.Edge.RightData = T; //} //2. Replace eo by new Edge var ve = new VoronoiEdge { LeftData = a.DataPoint, RightData = c.DataPoint }; ve.AddVertex(vNew); vg.Edges.Add(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); }
public static VoronoiGraph ComputeVoronoiGraph(IEnumerable Datapoints) { BinaryPriorityQueue PQ = new BinaryPriorityQueue(); Hashtable CurrentCircles = new Hashtable(); VoronoiGraph VG = new VoronoiGraph(); VNode RootNode = null; foreach(Vector V in Datapoints) { PQ.Push(new VDataEvent(V)); } while(PQ.Count>0) { VEvent VE = PQ.Pop() 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.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); // 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; }
public static VNode ProcessCircleEvent(VCircleEvent e, VNode Root, VoronoiGraph VG, float 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 Vector3 VNew = new Vector3(e.Center[0], e.Center[1], 0); // 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; // ///////////////////// 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); }
public static VoronoiGraph ComputeVoronoiGraph(IEnumerable <Vector2> points) { var pq = new MinHeap <VEvent>(); var currentCircles = new Dictionary <VDataNode, VCircleEvent>(); var vg = new VoronoiGraph(); VNode rootNode = null; foreach (var v in points) { pq.Add(new VDataEvent(v)); } while (pq.Count > 0) { var ve = pq.RemoveMin(); 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, out circleCheckList); } else { throw new Exception("Got event of type " + ve.GetType() + "!"); } foreach (var vd in circleCheckList) { if (currentCircles.ContainsKey(vd)) { currentCircles[vd].Valid = false; currentCircles.Remove(vd); } var vce = VNode.CircleCheckDataNode(vd, ve.Y); if (vce != null) { pq.Add(vce); currentCircles[vd] = vce; } } var evt = ve as VDataEvent; if (evt != null) { var dp = evt.DataPoint; foreach (var vce in currentCircles.Values) { if (Vector2.Distance(dp, vce.Center) < vce.Y - vce.Center.Y && Math.Abs(Vector2.Distance(dp, vce.Center) - (vce.Y - vce.Center.Y)) > 1e-10) { vce.Valid = false; } } } } VNode.CleanUpTree(rootNode as VEdgeNode); foreach (var ve in vg.Edges) { if (ve.Done) { continue; } if (!ve.VVertexB.HasValue) { ve.AddVertex(VvInfinite); if (Math.Abs(ve.LeftData.Y - ve.RightData.Y) < 1e-10 && ve.LeftData.X < ve.RightData.X) { var t = ve.LeftData; ve.LeftData = ve.RightData; ve.RightData = t; } } } var minuteEdges = new List <Edge>(); foreach (var ve in vg.Edges) { if (!ve.IsPartlyInfinite && ve.VVertexA.Equals(ve.VVertexB)) { minuteEdges.Add(ve); // prevent rounding errors from expanding to holes foreach (var 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 (var ve in minuteEdges) { vg.MutableEdges.Remove(ve); } return(vg); }