public Event(EVENT_TYPE type, double x, Point p, Arc a) : this(type) { this.x = x; this.p = p; this.a = a; }
public Arc(VoronoiCell cell, Point p, Arc prev, Arc next) : this(cell, p, prev) { this.next = next; }
public Arc(VoronoiCell cell, Point p, Arc prev) : this(cell, p) { this.prev = prev; }
void FinishEdges() { // Advance the sweep line so no parabolas can cross the bounding box. double l = X1 + (X1 - X0) + (Y1 - Y0); // Extend each remaining segment to the new parabola intersections. for (Arc i = root; i.next != null; i = i.next) { if (i.s1 != null) { i.s1.Finish(Intersection(i.p, i.next.p, l * 2)); } } // Crop output for (int c = 0; c < cells.Length; c++) { VoronoiCell cell = cells [c]; bool cropped = false; // Crop segments if needed for (int k = 0; k < cell.segments.Count; k++) { Segment s = cell.segments [k]; // is the segment completely outside? if (!s.done || (s.start.x < X0 && s.end.x < X0) || (s.start.y < Y0 && s.end.y < Y0) || (s.start.x > X1 && s.end.x > X1) || (s.start.y > Y1 && s.end.y > Y1) || Point.EqualsBoth(s.start, s.end)) { s.deleted = true; continue; } // is any endpoint outside of the canvas? bool p1inside = PointInsideRect(s.start); if (!p1inside) { s.start = CropPoint(s.start, s, cell); cropped = true; } bool p2inside = PointInsideRect(s.end); if (!p2inside) { s.end = CropPoint(s.end, s, cell); cropped = true; } } if (cropped) { // join borders with 2 points if (cell.top.Count > 1) { cell.segments.Add(new Segment(cell.top [0], cell.top [1], true)); } if (cell.bottom.Count > 1) { cell.segments.Add(new Segment(cell.bottom [0], cell.bottom [1], true)); } if (cell.left.Count > 1) { cell.segments.Add(new Segment(cell.left [0], cell.left [1], true)); } if (cell.right.Count > 1) { cell.segments.Add(new Segment(cell.right [0], cell.right [1], true)); } } } // 2nd step - snap to nearest corners Point[] corners = new Point[4]; corners [0] = new Point(X0, Y0); corners [1] = new Point(X0, Y1); corners [2] = new Point(X1, Y0); corners [3] = new Point(X1, Y1); Point np; for (int cornerIndex = 0; cornerIndex < corners.Length; cornerIndex++) { Point corner = corners [cornerIndex]; // Get the nearest point of the segments VoronoiCell nearestCell = GetNearestCellFrom(corner); // this territory is the nearest to the corner so now we can snap the nearest segment safely if (GetNearestSegmentPointToCorner(corner, nearestCell.segments, true, out np)) { nearestCell.segments.Add(new Segment(np, corner, true)); } if (GetNearestSegmentPointToCorner(corner, nearestCell.segments, false, out np)) { nearestCell.segments.Add(new Segment(np, corner, true)); } } }
public void AssignData(Point[] centers) { if (this.cells == null || this.cells.Length != centers.Length) { this.cells = new VoronoiCell[centers.Length]; } for (int k = 0; k < cells.Length; k++) { cells [k] = new VoronoiCell(centers [k]); } if (eventQueue == null) { eventQueue = new List <Event> (cells.Length); } else { eventQueue.Clear(); } root = null; eventQueueTop = 0; if (hit == null) { hit = new Dictionary <Point, bool> (cells.Length); } else { hit.Clear(); } for (int k = 0; k < cells.Length; k++) { Point p = cells [k].center; // Checks that p is not near than PRECISION from other point while (hit.ContainsKey(p)) { if (p.x > 0) { p.x -= Point.PRECISION * 2.0f; } else { p.x += Point.PRECISION * 2.0f; } } hit.Add(p, true); Event siteEvent = new Event(EVENT_TYPE.SiteEvent); siteEvent.p = p; siteEvent.x = p.x; siteEvent.cell = cells [k]; eventQueue.Add(siteEvent); } eventQueue.Sort((Event e1, Event e2) => { if (e1.x < e2.x - Point.PRECISION) { return(-1); } else if (e1.x > e2.x + Point.PRECISION) { return(1); } else if (e1.p.y < e2.p.y - Point.PRECISION) { return(-1); } else if (e1.p.y > e2.p.y + Point.PRECISION) { return(1); } else { return(0); } }); }
void HandleSiteEvent(Event ev) { Point p = ev.p; if (root == null) { root = new Arc(ev.cell, p); return; } Arc i; // Find the current arc(s) at height p.y (if there are any). for (i = root; i != null; i = i.next) { Point z, zz; if (Intersect(p, i, out z)) { // New parabola intersects arc i. If necessary, duplicate i. if (i.next != null && !Intersect(p, i.next, out zz)) { i.next.prev = new Arc(i.cell, i.p, i, i.next); i.next = i.next.prev; } else { i.next = new Arc(i.cell, i.p, i); } i.next.s1 = i.s1; // Add p between i and i->next. i.next.prev = new Arc(ev.cell, p, i, i.next); i.next = i.next.prev; i = i.next; // Now i points to the new arc. // Add new half-edges connected to i's endpoints. i.prev.s1 = i.s0 = new Segment(z); i.prev.cell.segments.Add(i.prev.s1); i.cell.segments.Add(i.prev.s1); i.next.s0 = i.s1 = new Segment(z); i.next.cell.segments.Add(i.next.s0); i.cell.segments.Add(i.next.s0); // Check for new circle events around the new arc: CheckCircleEvent(i, p.x); CheckCircleEvent(i.prev, p.x); CheckCircleEvent(i.next, p.x); return; } } // Special case: If p never intersects an arc, append it to the list. for (i = root; i.next != null; i = i.next) { ; // Find the last node. } i.next = new Arc(ev.cell, p, i); // Insert segment between p and i Point start = new Point(X0 - 1, (i.next.p.y + i.p.y) / 2); i.next.s0 = i.s1 = new Segment(start); i.next.cell.segments.Add(i.next.s0); i.cell.segments.Add(i.next.s0); }