예제 #1
0
        public FortuneArc SplitArc(FortuneArc splittingArc, FortuneArc splitter)
        {
            FortuneArc left = new FortuneArc();

            left.Site = splittingArc.Site;

            FortuneArc right = new FortuneArc();

            right.Site = splittingArc.Site;

            // create a new edge
            VoronoiEdge edge = new VoronoiEdge(splittingArc.Site.Cell, splitter.Site.Cell);

            // both nodes of the edge are initially points at infinity,
            // but can become final after the event range
            double x        = splitter.Site.Cell.DataPoint.X;
            double y        = splitter.Site.Cell.DataPoint.Y;
            double distance = getDistanceToArc(splittingArc.Site.Cell.DataPoint, y, x);

            edge.Node1           = new VoronoiNode(x, y - distance);
            edge.Node1.IsInfinit = true;
            edge.Node2           = new VoronoiNode(x, y - distance);
            edge.Node2.IsInfinit = true;

            // add this edge in both cell diagram
            splitter.Site.Cell.AddEdge(edge);
            splittingArc.Site.Cell.AddEdge(edge);

            //add nodes to the arcs of the ribs
            splitter.LeftNode  = edge.Node1;
            splitter.RightNode = edge.Node2;

            left.LeftNode   = splittingArc.LeftNode;
            left.RightNode  = edge.Node1;
            right.LeftNode  = edge.Node2;
            right.RightNode = splittingArc.RightNode;

            left.Left      = splittingArc.Left;
            right.Right    = splittingArc.Right;
            splitter.Left  = left;
            splitter.Right = right;

            if (splittingArc.Parent != null)
            {
                if (splittingArc.Parent.Left == splittingArc)
                {
                    splittingArc.Parent.Left = splitter;
                }
                else if (splittingArc.Parent.Right == splittingArc)
                {
                    splittingArc.Parent.Right = splitter;
                }
            }
            else
            {
                Root = splitter;
            }

            return(splitter);
        }
예제 #2
0
        /// <summary>
        /// Sets the directions of dangles for infinite edges.
        /// </summary>
        /// <param name="rectangle">Bounding rectangle of the tessellation nodes</param>
        /// <param name="startVerticalNodes">The initial nodes of the infinit vertical edges,
        /// formed by points with the maximum Y coordinate</param>
        internal void Finish(BoundingRectangle rectangle, List <VoronoiNode> startVerticalNodes)
        {
            double l = rectangle.MinY - rectangle.Width - rectangle.Height;

            FortuneArc arc = Root;

            while (arc.Left != null)
            {
                arc = arc.Left;
            }
            while (arc != null)
            {
                FortuneArc rn = arc.RightNeighbor;

                if (rn != null)
                {
                    ICoordinate[] points =
                        getArcIntersections(arc.Site.Cell.DataPoint, rn.Site.Cell.DataPoint, 2 * l);

                    if (points.Length == 2)
                    {
                        ICoordinate p1 = points[0].X < points[1].X ? points[0] : points[1];
                        ICoordinate p2 = points[0].X < points[1].X ? points[1] : points[0];

                        if (arc.RightNode != null && arc.RightNode.IsInfinit)
                        {
                            if (arc.Site.Cell.DataPoint.Y > rn.Site.Cell.DataPoint.Y)
                            {
                                arc.RightNode.Point = p1;
                            }
                            else
                            {
                                arc.RightNode.Point = p2;
                            }
                        }
                    }

                    if (points.Length == 1)
                    {
                        if (arc.RightNode != null && arc.RightNode.IsInfinit)
                        {
                            arc.RightNode.Point = points[0];
                        }
                    }
                }

                arc = rn;
            }

            foreach (VoronoiNode node in startVerticalNodes)
            {
                node.Point = PlanimetryEnvironment.NewCoordinate(node.Point.X, rectangle.MaxY + rectangle.Height);
            }
        }
예제 #3
0
        private FortuneEvent getCircleEvent(FortuneArc arc1,
                                            FortuneArc arc2,
                                            FortuneArc arc3,
                                            double y)
        {
            ICoordinate a = arc1.Site.Cell.DataPoint;
            ICoordinate b = arc2.Site.Cell.DataPoint;
            ICoordinate c = arc3.Site.Cell.DataPoint;

            //bc should turn to the right with respect to ab
            if ((b.X - a.X) * (c.Y - a.Y) - (c.X - a.X) * (b.Y - a.Y) > 0)
            {
                return(null);
            }

            ICoordinate point = getCircleCenter(a, b, c);

            if (point != null)
            {
                FortuneCircleEvent newEvent = new FortuneCircleEvent();
                newEvent.CircleCenter = point;

                double distance = PlanimetryAlgorithms.Distance(point, a);
                point = PlanimetryEnvironment.NewCoordinate(point.X, point.Y - distance);

                newEvent.Point = point;
                newEvent.Arc   = arc2;

                if (_buildTriangles)
                {
                    newEvent.Triangle = new Triangle(arc1.Site.Cell, arc2.Site.Cell, arc3.Site.Cell);
                }

                return(newEvent);
            }
            return(null);
        }
예제 #4
0
 /// <summary>
 /// Removes an arc from the shoreline.
 /// </summary>
 /// <param name="arc">An arc to remove</param>
 public void RemoveArc(FortuneArc arc)
 {
     removeArcRecursive(Root, arc);
 }
예제 #5
0
        private bool removeArcRecursive(FortuneArc root, FortuneArc arc)
        {
            if (root == null)
            {
                return(false);
            }

            if (root == arc)
            {
                // no children
                if (arc.Left == null && arc.Right == null)
                {
                    if (arc.Parent != null)
                    {
                        if (arc.Parent.Left == arc)
                        {
                            arc.Parent.Left = null;
                        }
                        else if (arc.Parent.Right == arc)
                        {
                            arc.Parent.Right = null;
                        }
                    }
                    if (Root == arc)
                    {
                        Root = null;
                    }
                    return(true);
                }

                // one child
                if (arc.Left != null ^ arc.Right != null)
                {
                    FortuneArc child = arc.Left != null ? arc.Left : arc.Right;
                    if (arc.Parent != null)
                    {
                        if (arc.Parent.Left == arc)
                        {
                            arc.Parent.Left = child;
                        }
                        else if (arc.Parent.Right == arc)
                        {
                            arc.Parent.Right = child;
                        }
                    }
                    else
                    {
                        Root        = child;
                        Root.Parent = null;
                    }

                    return(true);
                }

                // have both child
                FortuneArc rightLeft = root.Right;
                while (rightLeft.Left != null)
                {
                    rightLeft = rightLeft.Left;
                }

                rightLeft.Left = arc.Left;

                if (arc.Parent != null)
                {
                    if (arc.Parent.Left == arc)
                    {
                        arc.Parent.Left = arc.Right;
                    }
                    else if (arc.Parent.Right == arc)
                    {
                        arc.Parent.Right = arc.Right;
                    }
                }
                if (Root == arc)
                {
                    Root        = arc.Right;
                    Root.Parent = null;
                }
                return(true);
            }
            else
            {
                if (removeArcRecursive(root.Left, arc))
                {
                    return(true);
                }

                return(removeArcRecursive(root.Right, arc));
            }
        }
예제 #6
0
        /// <summary>
        /// Finds the arc of the shoreline, under which arose a point event.
        /// </summary>
        /// <param name="eventX">An X coordinate of event</param>
        /// <param name="ly">A Y coordinate of the sweepline</param>
        /// <returns>The arc finded or null</returns>
        public FortuneArc FindArc(double eventX, double ly)
        {
            if (Root == null)
            {
                return(null);
            }

            FortuneArc currentArc = Root;

            while (true)
            {
                if (currentArc.Left == null && currentArc.Right == null)
                {
                    return(currentArc);
                }

                if (currentArc.Site.Cell.DataPoint.Y == ly)
                {
                    currentArc = currentArc.Site.Cell.DataPoint.X < eventX ? currentArc.Right : currentArc.Left;
                    continue;
                }

                //find the boundaries of the left and right subtrees
                FortuneArc leftNeighbor  = currentArc.LeftSubtreeBound;
                FortuneArc rightNeighbor = currentArc.RightSubtreeBound;

                ICoordinate[] pointsPrev = null;
                ICoordinate[] pointsNext = null;

                if (leftNeighbor != null)
                {
                    pointsPrev = getArcIntersections(leftNeighbor.Site.Cell.DataPoint, currentArc.Site.Cell.DataPoint, ly);
                    if (pointsPrev.Length == 2)
                    {
                        if ((pointsPrev[1].X < pointsPrev[0].X ^ leftNeighbor.Site.Cell.DataPoint.Y < currentArc.Site.Cell.DataPoint.Y))
                        {
                            pointsPrev[0] = pointsPrev[1];
                        }
                    }
                }

                if (rightNeighbor != null)
                {
                    pointsNext = getArcIntersections(rightNeighbor.Site.Cell.DataPoint, currentArc.Site.Cell.DataPoint, ly);
                    if (pointsNext.Length == 2)
                    {
                        if ((pointsNext[1].X <pointsNext[0].X ^ rightNeighbor.Site.Cell.DataPoint.Y> currentArc.Site.Cell.DataPoint.Y))
                        {
                            pointsNext[0] = pointsNext[1];
                        }
                    }
                }

                if ((currentArc.Left == null || pointsPrev[0].X <= eventX) &&
                    (currentArc.Right == null || pointsNext[0].X >= eventX))
                {
                    return(currentArc);
                }

                if (leftNeighbor != null && pointsPrev[0].X > eventX)
                {
                    currentArc = currentArc.Left;
                    continue;
                }

                if (rightNeighbor != null && pointsNext[0].X < eventX)
                {
                    currentArc = currentArc.Right;
                    continue;
                }
            }
        }
예제 #7
0
 /// <summary>
 /// Initializes a new instance of MapAround.Geometry.Tessellations.FortuneArc
 /// </summary>
 internal FortuneArc(FortuneArc left, FortuneArc right)
 {
     _left  = left;
     _right = right;
 }
예제 #8
0
        private void init(List <VoronoiCell> cells, int lastMaxYIndex)
        {
            _rectangle          = new BoundingRectangle();
            _eventList          = new LinkedList <FortuneEvent>();
            _startVerticalNodes = new List <VoronoiNode>();

            // Where several points have the minimum ordinate requires a separate pre-treatment
            int skipEventCount = 0;

            if (lastMaxYIndex > 0)
            {
                VoronoiNode previousNode = null;
                FortuneArc  currentArc   = null;
                skipEventCount = lastMaxYIndex + 1;
                for (int i = 0; i <= lastMaxYIndex; i++)
                {
                    // add an arc of coastline
                    FortuneArc  arc  = new FortuneArc();
                    FortuneSite site = new FortuneSite();
                    site.Cell = cells[i];
                    arc.Site  = site;

                    if (currentArc != null)
                    {
                        currentArc.Right = arc;
                    }

                    currentArc = arc;
                    if (_shoreLine.Root == null)
                    {
                        _shoreLine.Root = arc;
                    }

                    if (previousNode != null)
                    {
                        arc.LeftNode = previousNode;
                    }

                    // add the vertical edges of the Voronoi diagram
                    if (i < lastMaxYIndex)
                    {
                        VoronoiEdge edge    = new VoronoiEdge(cells[i], cells[i + 1]);
                        double      middleX = (cells[i].DataPoint.X + cells[i + 1].DataPoint.X) / 2;
                        double      middleY = cells[i].DataPoint.Y;

                        edge.Node1           = new VoronoiNode(middleX, middleY);
                        edge.Node1.IsInfinit = true;
                        _startVerticalNodes.Add(edge.Node1);

                        edge.Node2           = new VoronoiNode(middleX, middleY);
                        edge.Node2.IsInfinit = true;

                        previousNode = edge.Node2;

                        arc.RightNode = edge.Node2;

                        cells[i].AddEdge(edge);
                        cells[i + 1].AddEdge(edge);
                    }
                }
            }

            // fill all point events
            int j = 0;

            foreach (VoronoiCell cell in cells)
            {
                if (skipEventCount > j++)
                {
                    continue;
                }

                FortunePointEvent ev = new FortunePointEvent();
                ev.Point = cell.DataPoint;
                ev.Cell  = cell;
                _eventList.AddLast(ev);
            }
        }
예제 #9
0
        private void handleCircleEvent(FortuneCircleEvent ev)
        {
            FortuneArc ln = ev.Arc.LeftNeighbor;
            FortuneArc rn = ev.Arc.RightNeighbor;

            // remove events range associated with this arc
            if (ln.CircleEvent != null)
            {
                _eventList.Remove(ln.CircleEvent);
            }
            if (rn.CircleEvent != null)
            {
                _eventList.Remove(rn.CircleEvent);
            }

            // remove the arc of coastline
            _shoreLine.RemoveArc(ev.Arc);

            //fix slave nodes arc ribs
            if (ev.Arc.LeftNode != null)
            {
                ev.Arc.LeftNode.Point     = ev.CircleCenter;
                ev.Arc.LeftNode.IsInfinit = false;
            }

            if (ev.Arc.RightNode != null)
            {
                ev.Arc.RightNode.Point     = ev.CircleCenter;
                ev.Arc.RightNode.IsInfinit = false;
            }

            // add a new edge
            VoronoiEdge edge = new VoronoiEdge(ln.Site.Cell, rn.Site.Cell);

            edge.Node1 = new VoronoiNode(ev.CircleCenter.X, ev.CircleCenter.Y);
            edge.Node2 = new VoronoiNode((ln.Site.Cell.DataPoint.X + rn.Site.Cell.DataPoint.X) / 2,
                                         (ln.Site.Cell.DataPoint.Y + rn.Site.Cell.DataPoint.Y) / 2);

            //expand the bounding rectangle of the chart
            _rectangle.Join(ev.CircleCenter);

            // one node of the new edge is fixed, the second - no
            edge.Node1.IsInfinit = false;
            edge.Node2.IsInfinit = true;

            // dobavleyaem edge to cells
            ln.Site.Cell.AddEdge(edge);
            rn.Site.Cell.AddEdge(edge);

            //add a triangle in the Delaunay triangulation, if necessary
            if (_buildTriangles)
            {
                _triangles.Add(ev.Triangle);
            }

            // not a fixed node is a new edge now vanished neighbors arc
            ln.RightNode = edge.Node2;
            rn.LeftNode  = edge.Node2;

            FortuneArc lnln = ln.LeftNeighbor;
            FortuneArc lnrn = ln.RightNeighbor;

            FortuneArc rnln = rn.LeftNeighbor;
            FortuneArc rnrn = rn.RightNeighbor;

            // add events to the newly formed circle arcs triples
            if (lnln != null)
            {
                if (lnrn != null)
                {
                    FortuneEvent eventToAdd = getCircleEvent(lnln, ln, lnrn, ev.Point.Y);
                    if (eventToAdd != null)
                    {
                        addCircleEvent(eventToAdd);
                    }
                    ln.CircleEvent = eventToAdd;
                }
            }

            if (rnln != null)
            {
                if (rnrn != null)
                {
                    FortuneEvent eventToAdd = getCircleEvent(rnln, rn, rnrn, ev.Point.Y);
                    if (eventToAdd != null)
                    {
                        addCircleEvent(eventToAdd);
                    }
                    rn.CircleEvent = eventToAdd;
                }
            }
        }
예제 #10
0
        private void handlePointEvent(FortunePointEvent ev)
        {
            if (_shoreLine.Root == null)
            {
                FortuneArc  arc  = new FortuneArc();
                FortuneSite site = new FortuneSite();
                site.Cell = ev.Cell;
                arc.Site  = site;

                _shoreLine.Root = arc;

                return;
            }

            FortuneArc arcAbove = _shoreLine.FindArc(ev.Point.X, ev.Point.Y);

            // remove events range from the queue
            if (arcAbove.CircleEvent != null)
            {
                _eventList.Remove(arcAbove.CircleEvent);
            }

            // create an arc
            FortuneArc splitter = new FortuneArc();

            splitter.Site      = new FortuneSite();
            splitter.Site.Cell = ev.Cell;

            FortuneArc newArc = _shoreLine.SplitArc(arcAbove, splitter);

            FortuneArc ln   = newArc.LeftNeighbor;
            FortuneArc lnln = null;

            if (ln != null)
            {
                lnln = ln.LeftNeighbor;
            }

            FortuneArc rn   = newArc.RightNeighbor;
            FortuneArc rnrn = null;

            if (rn != null)
            {
                rnrn = rn.RightNeighbor;
            }

            if (ln != null)
            {
                if (lnln != null)
                {
                    FortuneEvent eventToAdd = getCircleEvent(lnln, ln, newArc, ev.Point.Y);
                    if (eventToAdd != null)
                    {
                        addCircleEvent(eventToAdd);
                    }
                    ln.CircleEvent = eventToAdd;
                }
            }

            if (rn != null)
            {
                if (rnrn != null)
                {
                    FortuneEvent eventToAdd = getCircleEvent(newArc, rn, rnrn, ev.Point.Y);
                    if (eventToAdd != null)
                    {
                        addCircleEvent(eventToAdd);
                    }
                    rn.CircleEvent = eventToAdd;
                }
            }
        }