public EdgeList( SiteList siteList) { Edges = new List<HalfEdge>(); _siteList = siteList; LeftEnd = new HalfEdge(null, Side.Left); RightEnd = new HalfEdge(null, Side.Left); LeftEnd.Right = RightEnd; RightEnd.Left = LeftEnd; Edges.Add(LeftEnd); Edges.Add(RightEnd); }
public void Insert(HalfEdge he, Site site, float offset) { he.Vertex = site; he.YStar = site.Y + offset; int i; for (i = 0; i < _events.Count; i++) { var next = _events[i]; if (he.YStar > next.YStar || (Math.Abs(he.YStar - next.YStar) < Geometry.Tolerance && site.X > next.Vertex.X)) { continue; } break; } _events.Insert(i, he); }
public static bool RightOf(HalfEdge he, Site p) { var e = he.Edge; var topSite = e.Region[Side.Right]; var rightOfSite = (p.X > topSite.X); if (rightOfSite && (he.Side == Side.Left)) { return true; } if (!rightOfSite && (he.Side == Side.Right)) { return false; } bool above; if (Math.Abs(e.A - 1) < Tolerance) { var dyp = p.Y - topSite.Y; var dxp = p.X - topSite.X; var fast = false; if ((!rightOfSite && (e.B < 0)) || (rightOfSite && (e.B >= 0))) { above = fast = (dyp >= e.B*dxp); } else { above = ((p.X + p.Y*e.B) > e.C); if (e.B < 0) { above = !above; } if (!above) { fast = true; } } if (!fast) { var dxs = topSite.X - e.Region[Side.Left].X; above = (e.B*(dxp*dxp - dyp*dyp)) < (dxs*dyp*(1 + 2*dxp/dxs + e.B*e.B)); if (e.B < 0) { above = !above; } } } else { // e.b == 1 var y1 = e.C - e.A*p.X; var t1 = p.Y - y1; var t2 = p.X - topSite.X; var t3 = y1 - topSite.Y; above = (t1*t1) > (t2*t2 + t3*t3); } return he.Side == Side.Left ? above : !above; }
public static Site Intersect(HalfEdge el1, HalfEdge el2) { var e1 = el1.Edge; var e2 = el2.Edge; if (e1 == null || e2 == null) { return null; } if (e1.Region[Side.Right] == e2.Region[Side.Right]) { return null; } var d = (e1.A*e2.B) - (e1.B*e2.A); if (Math.Abs(d) < Tolerance) { return null; } var xint = (e1.C*e2.B - e2.C*e1.B)/d; var yint = (e2.C*e1.A - e1.C*e2.A)/d; var e1Region = e1.Region[Side.Right]; var e2Region = e2.Region[Side.Right]; HalfEdge el; Edge e; if ((e1Region.Y < e2Region.Y) || Math.Abs(e1Region.Y - e2Region.Y) < Tolerance && e1Region.X < e2Region.X) { el = el1; e = e1; } else { el = el2; e = e2; } var rightOfSite = (xint >= e.Region[Side.Right].X); if ((rightOfSite && (el.Side == Side.Left)) || (!rightOfSite && (el.Side == Side.Right))) { return null; } var vertex = new Site(xint, yint); //vertex.AddEdge(e1); //vertex.AddEdge(e2); return vertex; }
public VoronoiGraph StepVoronoi() { _graph.ResetNewItems(); if (!_edgeFixup) { if (!_eventQueue.IsEmpty) { _newIntStar = _eventQueue.Min(); } if (_newSite != null && (_eventQueue.IsEmpty || /*Geometry.CompareByYThenX(_newSite, _newIntStar)*/ _newSite.CompareTo(_newIntStar) < 0 )) { _graph.PlotSite(_newSite); var lbnd = _edgeList.LeftBound(_newSite); var rbnd = lbnd.Right; var bot = _edgeList.RightRegion(lbnd); var e = Edge.CreateBisectingEdge(bot, _newSite); _graph.PlotBisector(e); var bisector = new HalfEdge(e, Side.Left); EdgeList.Insert(lbnd, bisector); var p = Site.CreateIntersectingSite(lbnd, bisector); if (p != null) { _eventQueue.Delete(lbnd); if (_graph.Debug) { Console.WriteLine("Inserting {0}", p); } _eventQueue.Insert(lbnd, p, Site.Distance(p, _newSite)); } lbnd = bisector; bisector = new HalfEdge(e, Side.Right); EdgeList.Insert(lbnd, bisector); p = Site.CreateIntersectingSite(bisector, rbnd); if (p != null) { if (_graph.Debug) { Console.WriteLine("Inserting {0}", p); } _eventQueue.Insert(bisector, p, Site.Distance(p, _newSite)); } _newSite = _sites.ExtractMin(); if (_newSite !=null && _newSite.Y > _graph.SweepLine) { _graph.SweepLine = _newSite.Y; } else if (_newSite == null) { _graph.SweepLine = _graph.Height; } } else if (!_eventQueue.IsEmpty) { // intersection is smallest var lbnd = _eventQueue.ExtractMin(); var llbnd = lbnd.Left; var rbnd = lbnd.Right; var rrbnd = rbnd.Right; var bot = _edgeList.LeftRegion(lbnd); var top = _edgeList.RightRegion(rbnd); _graph.PlotTriple(bot, top, _edgeList.RightRegion(lbnd)); var v = lbnd.Vertex; _graph.PlotVertex(v); _graph.EndPoint(lbnd.Edge, lbnd.Side, v); _graph.EndPoint(rbnd.Edge, rbnd.Side, v); EdgeList.Delete(lbnd); _eventQueue.Delete(rbnd); EdgeList.Delete(rbnd); var pm = Side.Left; if (bot.Y > top.Y) { var temp = bot; bot = top; top = temp; pm = Side.Right; } var e = Edge.CreateBisectingEdge(bot, top); _graph.PlotBisector(e); var bisector = new HalfEdge(e, pm); EdgeList.Insert(llbnd, bisector); _graph.EndPoint(e, pm == Side.Left ? Side.Right : Side.Left, v); var p = Site.CreateIntersectingSite(llbnd, bisector); if (p != null) { _eventQueue.Delete(llbnd); if (_graph.Debug) { Console.WriteLine("Inserting {0}", p); } _eventQueue.Insert(llbnd, p, Site.Distance(p, bot)); } p = Site.CreateIntersectingSite(bisector, rrbnd); if (p != null) { if (_graph.Debug) { Console.WriteLine("Inserting {0}", p); } _eventQueue.Insert(bisector, p, Site.Distance(p, bot)); } } else { _edgeFixup = true; } StepNumber++; } else { var lbnd = _edgeList.LeftEnd.Right; if (lbnd != _edgeList.RightEnd) { var e = lbnd.Edge; _graph.PlotEndpoint(e); EdgeList.Delete(lbnd); StepNumber++; } else { foreach (var edge in _graph.Edges) { edge.ClipVertices(new Rectangle(0, 0, _graph.Width, _graph.Height)); } if (_graph.Debug) { Console.WriteLine("Done computing graph!"); } } } if (_graph.Debug) { Console.WriteLine("Step: " + StepNumber); } return _graph; }
public static VoronoiGraph ComputeVoronoi(IEnumerable<PointF> points, int w = 800, int h = 600, bool debug=false) { var sites = new SiteList(points); sites.LogSites(); var graph = new VoronoiGraph(w, h) { Debug = debug }; try { var edgeList = new EdgeList(sites); var eventQueue = new EventQueue(); sites.BottomSite = sites.ExtractMin(); graph.PlotSite(sites.BottomSite); var newSite = sites.ExtractMin(); var newIntStar = new Site(float.MaxValue, float.MaxValue); while (true) { if (!eventQueue.IsEmpty) { newIntStar = eventQueue.Min(); } // new site is smallest if (newSite != null && (eventQueue.IsEmpty || newSite.Y < newIntStar.Y || (Math.Abs(newSite.Y - newIntStar.Y) < Geometry.Tolerance && newSite.X < newIntStar.X))) { graph.PlotSite(newSite); var lbnd = edgeList.LeftBound(newSite); var rbnd = lbnd.Right; var bot = edgeList.RightRegion(lbnd); var e = Geometry.Bisect(bot, newSite); graph.PlotBisector(e); var bisector = new HalfEdge(e, Side.Left); edgeList.Insert(lbnd, bisector); var p = Geometry.Intersect(lbnd, bisector); if (p != null) { eventQueue.Delete(lbnd); if (debug) { Console.WriteLine("Inserting {0}", p); } eventQueue.Insert(lbnd, p, Geometry.Distance(p, newSite)); } lbnd = bisector; bisector = new HalfEdge(e, Side.Right); edgeList.Insert(lbnd, bisector); p = Geometry.Intersect(bisector, rbnd); if (p != null) { if (debug) { Console.WriteLine("Inserting {0}", p); } eventQueue.Insert(bisector, p, Geometry.Distance(p, newSite)); } newSite = sites.ExtractMin(); } else if (!eventQueue.IsEmpty) { // intersection is smallest var lbnd = eventQueue.ExtractMin(); var llbnd = lbnd.Left; var rbnd = lbnd.Right; var rrbnd = rbnd.Right; var bot = edgeList.LeftRegion(lbnd); var top = edgeList.RightRegion(rbnd); graph.PlotTriple(bot, top, edgeList.RightRegion(lbnd)); var v = lbnd.Vertex; graph.PlotVertex(v); Geometry.EndPoint(lbnd.Edge, lbnd.Side, v, graph); Geometry.EndPoint(rbnd.Edge, rbnd.Side, v, graph); edgeList.Delete(lbnd); eventQueue.Delete(rbnd); edgeList.Delete(rbnd); var pm = Side.Left; if (bot.Y > top.Y) { var temp = bot; bot = top; top = temp; pm = Side.Right; } var e = Geometry.Bisect(bot, top); graph.PlotBisector(e); var bisector = new HalfEdge(e, pm); edgeList.Insert(llbnd, bisector); Geometry.EndPoint(e, Side.Other(pm), v, graph); var p = Geometry.Intersect(llbnd, bisector); if (p != null) { eventQueue.Delete(llbnd); if (debug) { Console.WriteLine("Inserting {0}", p); } eventQueue.Insert(llbnd, p, Geometry.Distance(p, bot)); } p = Geometry.Intersect(bisector, rrbnd); if (p != null) { if (debug) { Console.WriteLine("Inserting {0}", p); } eventQueue.Insert(bisector, p, Geometry.Distance(p, bot)); } } else { break; } } for (var lbnd = edgeList.LeftEnd.Right; lbnd != edgeList.RightEnd; lbnd = lbnd.Right) { var e = lbnd.Edge; graph.PlotEndpoint(e); } } catch (Exception ex) { Console.WriteLine("########################################"); Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); } graph.SweepLine = graph.Height; graph.ResetNewItems(); foreach (var edge in graph.Edges) { edge.ClipVertices(new Rectangle(0,0, w, h)); } return graph; }
public void Delete(HalfEdge he) { _events.Remove(he); }
public Site RightRegion(HalfEdge he) { if (he.Edge == null) { return _siteList.BottomSite; } return he.Side == Side.Left ? he.Edge.Region[Side.Right] : he.Edge.Region[Side.Left]; }
public void Delete(HalfEdge he) { he.Left.Right = he.Right; he.Right.Left = he.Left; he.Edge = null; }
public void Insert(HalfEdge lb, HalfEdge he) { he.Left = lb; he.Right = lb.Right; lb.Right.Left = he; lb.Right = he; }