public Event(EVENT_TYPE type, double x, Point p, Arc a)
     : this(type)
 {
     this.x = x;
     this.p = p;
     this.a = a;
 }
示例#2
0
 public Arc(VoronoiCell cell, Point p, Arc prev, Arc next)
     : this(cell, p, prev)
 {
     this.next = next;
 }
示例#3
0
 public Arc(VoronoiCell cell, Point p, Arc prev)
     : this(cell, p)
 {
     this.prev = prev;
 }
示例#4
0
        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));
                }
            }
        }
示例#5
0
        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);
                }
            });
        }
示例#6
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);
        }
 public Event(EVENT_TYPE type, double x, Point p, Arc a) : this(type) {
     this.x = x;
     this.p = p;
     this.a = a;
 }