public void Compute(HashSet<Point> points, int width, int height) { _root = null; _width = width; _height = height; if (points.Count < 2) { return; } Edges = new List<Edge>(); Cells = new List<Cell>(); _queue = new Queue(); foreach (Point point in points) { var @event = new Event(point, true); var cell = new Cell(point); point.Cell = cell; _queue.Enqueue(@event); Cells.Add(cell); } while (!_queue.IsEmpty()) { Event @event = _queue.Dequeue(); _ly = @event.Point.Y; if (@event.IsParabola) { InsertParabola(@event.Point); } else { RemoveParabola(@event); } _lasty = @event.Point.Y; } FinishEdge(_root); for (var i = 0; i < Edges.Count; i++) { if (Edges[i].Neighbour != null) { Edges[i].Start = Edges[i].Neighbour.End; } } }
private void CheckCircle(Parabola b) { Parabola lp = GetLeftParent(b); Parabola rp = GetRightParent(b); Parabola a = GetLeftChild(lp); Parabola c = GetRightChild(rp); if (a == null || c == null || Equals(a.Site, c.Site)) return; Point s = GetEdgeIntersection(lp.Edge, rp.Edge); if (s == null) return; double d = Distance(a.Site, s); if (s.Y - d >= _ly) return; var e = new Event(new Point(s.X, s.Y - d), false); b.CircleEvent = e; e.Arch = b; _queue.Enqueue(e); }
private void InsertParabola(Point p) { if (_root == null) { _root = new Parabola(p); _fp = p; return; } if (_root.IsLeaf && _root.Site.Y - p.Y < 0.01) { _root.IsLeaf = false; _root.Left = new Parabola(_fp); _root.Right = new Parabola(p); var s = new Point((p.X + _fp.X)/2, _height); if (p.X > _fp.X) { _root.Edge = new Edge(s, _fp, p); } else { _root.Edge = new Edge(s, p, _fp); } Edges.Add(_root.Edge); return; } Parabola par = GetParabolaByX(p.X); if (par.CircleEvent != null) { _queue.Remove(par.CircleEvent); par.CircleEvent = null; } var start = new Point(p.X, GetY(par.Site, p.X)); var el = new Edge(start, par.Site, p); var er = new Edge(start, p, par.Site); el.Neighbour = er; Edges.Add(el); par.Edge = er; par.IsLeaf = false; var p0 = new Parabola(par.Site); var p1 = new Parabola(p); var p2 = new Parabola(par.Site); par.Right = p2; par.Left = new Parabola(); par.Left.Edge = el; par.Left.Left = p0; par.Left.Right = p1; CheckCircle(p0); CheckCircle(p2); }
private double GetXOfEdge(Parabola par, double y) { Parabola left = GetLeftChild(par); Parabola right = GetRightChild(par); Point p = left.Site; Point r = right.Site; double dp = 2*(p.Y - y); double a1 = 1/dp; double b1 = -2*p.X/dp; double c1 = y + dp*0.25 + p.X*p.X/dp; dp = 2*(r.Y - y); double a2 = 1/dp; double b2 = -2*r.X/dp; double c2 = y + dp*0.25 + r.X*r.X/dp; double a = a1 - a2; double b = b1 - b2; double c = c1 - c2; double disc = b*b - 4*a*c; double x1 = (-b + Math.Sqrt(disc))/(2*a); double x2 = (-b - Math.Sqrt(disc))/(2*a); double ry; if (p.Y < r.Y) ry = Math.Max(x1, x2); else ry = Math.Min(x1, x2); return ry; }
private Parabola GetRightParent(Parabola n) { Parabola par = n.Parent; Parabola pLast = n; while (par.Right == pLast) { if (par.Parent == null) return null; pLast = par; par = par.Parent; } return par; }
private Parabola GetRightChild(Parabola n) { if (n == null) return null; Parabola par = n.Right; while (!par.IsLeaf) par = par.Left; return par; }
private void FinishEdge(Parabola n) { double mx; if (n.Edge.Direction.X > 0.0f) { mx = Math.Max(_width, n.Edge.Start.X + 10); } else { mx = Math.Min(0.0f, n.Edge.Start.X - 10); } n.Edge.End = new Point(mx, n.Edge.F * mx + n.Edge.G); if (!n.Left.IsLeaf) this.FinishEdge(n.Left); if (!n.Right.IsLeaf) this.FinishEdge(n.Right); }