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); }
public static VoronoiGraph ComputeVoronoiGraph(IEnumerable <Vector2> datapoints) { var pq = new List <VEvent>(); var currentCircles = new Hashtable(); var vg = new VoronoiGraph(); VNode rootNode = null; foreach (var v in datapoints) { pq.Add(new VDataEvent(v)); } pq.Sort(); while (pq.Count > 0) { var ve = pq.First(); pq.Remove(ve); if (ve == null) { return(null); } 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)) { ((VCircleEvent)currentCircles[vd]).Valid = false; currentCircles.Remove(vd); } var vce = VNode.CircleCheckDataNode(vd, ve.Y); if (vce != null) { pq.Add(vce); pq.Sort(); currentCircles[vd] = vce; } } if (ve is VDataEvent) { var dp = ((VDataEvent)ve).DataPoint; foreach (VCircleEvent vce in currentCircles.Values) { if (Dist(dp[0], dp[1], vce.CenterX, vce.CenterY) < vce.Y - vce.CenterY && Math.Abs(Dist(dp[0], dp[1], vce.CenterX, vce.CenterY) - (vce.Y - vce.CenterY)) > 1e-10) { vce.Valid = false; } } } } VNode.CleanUpTree(rootNode); foreach (var ve in vg.GetEdges().Select(edge => edge as VoronoiEdge)) { if (Edge.IsUnknownVertex(ve.V2)) { ve.AddVertex(Edge.GetInfiniteVertex()); if (Math.Abs(ve.LeftData[1] - ve.RightData[1]) < 1e-10 && ve.LeftData[0] < ve.RightData[0]) { var T = ve.LeftData; ve.LeftData = ve.RightData; ve.RightData = T; } } } var minuteEdges = new ArrayList(); foreach (var ve in vg.GetEdges()) { if (!ve.IsPartlyInfinite && ve.V1.Equals(ve.V2)) { minuteEdges.Add(ve); foreach (var ve2 in vg.GetEdges()) { if (ve2.V1.Equals(ve.V1)) { ve2.V1 = ve.V1; } if (ve2.V2.Equals(ve.V1)) { ve2.V2 = ve.V1; } } } } foreach (VoronoiEdge ve in minuteEdges) { vg.RemoveEdge(ve, false); } return(vg); }