Ejemplo n.º 1
0
 /// <summary>
 /// Add the beach to the end of the list.
 /// </summary>
 public void AddLast(Beach objBeach)
 {
     this.RunningIndex++;
     this.InternalTransitions.Add(this.RunningIndex, objBeach);
     this.InternalIndex.AddLast(this.RunningIndex);
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Detach a beach section.
        /// </summary>
        private void DetachBeach(Beach objBeach)
        {
            // Detach potentially attached circle event.
            this.DetachCircleEvent(objBeach);

            // Remove from RB-tree.
            this.BeachLines.RemoveNode(objBeach);

            // Mark for reuse.
            this.BeachJunkyard.Push(objBeach);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Remove beach section.
        /// </summary>
        private void RemoveBeach(Beach objBeach)
        {
            Circle objCircle = objBeach.Circle;
            double x = objCircle.x;
            double y = objCircle.ycenter;
            Point objVertex = this.CreateEdgeVertex(x, y);
            Beach objPrevious = objBeach.Previous as Beach;
            Beach objNext = objBeach.Next as Beach;
            var lstDisappearingTransitions = new Transitions();
            lstDisappearingTransitions.AddFirst(objBeach);

            // Remove collapsed beach section from beach line.
            this.DetachBeach(objBeach);

            // there could be more than one empty arc at the deletion point, this
            // happens when more than two edges are linked by the same vertex;
            // so we will collect all those edges by looking up both sides of
            // the deletion point.
            // by the way, there is *always* a predecessor/successor to any collapsed
            // beach section, it's just impossible to have a collapsing first/last
            // beach sections on the beachline, since they obviously are unconstrained
            // on their left/right side.

            // look left
            Beach objLeftArc = objPrevious;
            while (objLeftArc.Circle != null && Math.Abs(x - objLeftArc.Circle.x) < Polygons.Epsilon && Math.Abs(y - objLeftArc.Circle.ycenter) < Polygons.Epsilon)
            {
                objPrevious = objLeftArc.Previous as Beach;
                lstDisappearingTransitions.AddFirst(objLeftArc);
                this.DetachBeach(objLeftArc);
                objLeftArc = objPrevious;
            }

            // even though it is not disappearing, I will also add the beach section
            // immediately to the left of the left-most collapsed beach section, for
            // convenience, since we need to refer to it later as this beach section
            // is the 'left' site of an edge for which a start point is set.
            lstDisappearingTransitions.AddFirst(objLeftArc);
            this.DetachCircleEvent(objLeftArc);

            // look right
            Beach objRightArc = objNext;
            while (objRightArc.Circle != null && Math.Abs(x - objRightArc.Circle.x) < Polygons.Epsilon && Math.Abs(y - objRightArc.Circle.ycenter) < Polygons.Epsilon)
            {
                objNext = objRightArc.Next as Beach;
                lstDisappearingTransitions.AddLast(objRightArc);
                this.DetachBeach(objRightArc);
                objRightArc = objNext;
            }

            // we also have to add the beach section immediately to the right of the
            // right-most collapsed beach section, since there is also a disappearing
            // transition representing an edge's start point on its left.
            lstDisappearingTransitions.AddLast(objRightArc);
            this.DetachCircleEvent(objRightArc);

            // walk through all the disappearing transitions between beach sections and
            // set the start point of their (implied) edge.
            int intArcs = lstDisappearingTransitions.Count;

            for (int intArc = 1; intArc < intArcs; intArc++)
            {
                // Reset objects.
                Beach objRightDis = lstDisappearingTransitions.Item(intArc);
                Beach objLeftDis = lstDisappearingTransitions.Item(intArc - 1);

                if (objRightDis.Edge != null)
                {
                    objRightDis.Edge.SetStartPoint(objLeftDis.Site, objRightDis.Site, objVertex);
                }
            }

            // create a new edge as we have now a new transition between
            // two beach sections which were previously not adjacent.
            // since this edge appears as a new vertex is defined, the vertex
            // actually define an end point of the edge (relative to the site
            // on the left)
            Beach objFirstDis = lstDisappearingTransitions.Item(0);
            Beach objLastDis = lstDisappearingTransitions.Item(intArcs - 1);
            objLastDis.Edge = this.CreateEdge(objFirstDis.Site, objLastDis.Site, null, objVertex);

            // create circle events if any for beach sections left in the beachline
            // adjacent to collapsed sections
            this.AttachCircle(objFirstDis);
            this.AttachCircle(objLastDis);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Checks to see if a beach section is available in the junkyard and uses it,
        /// or makes a new one and returns it.
        /// </summary>
        private Beach GetBeach()
        {
            Beach objBeach = null;

            // Check to see whether the stack is empty.
            if (this.BeachJunkyard.Count > 0)
            {
                // Try to retrieve a circle vent from the junkyard.
                objBeach = this.BeachJunkyard.Pop();
            }

            // If we don't find a circle event in the junkyard we'll make a new one.
            if (objBeach == null)
            {
                objBeach = new Beach();
            }

            // And give it back!
            return objBeach;
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Attach a circle event.
        /// </summary>
        private void AttachCircle(Beach objArc)
        {
            // This is a node in the RBTree which points to a beachsection.
            Beach objArcLeft = objArc.Previous as Beach;
            Beach objArcRight = objArc.Next as Beach;

            if (objArcLeft == null || objArcRight == null)
            {
                return;
            } // Does that ever happen?

            Point objSiteLeft = objArcLeft.Site;
            Point objSite = objArc.Site;
            Point objSiteRight = objArcRight.Site;

            // If site of left beachsection is same as site of right beachsection, there can't be convergence.
            if (objSiteLeft == objSiteRight)
            {
                return;
            }

            // Find the circumscribed circle for the three sites associated
            // with the beachsection triplet.
            // rhill 2011-05-26: It is more efficient to calculate in-place
            // rather than getting the resulting circumscribed circle from an
            // object returned by calling Voronoi.circumcircle()
            // http://mathforum.org/library/drmath/view/55002.html
            // Except that I bring the origin at cSite to simplify calculations.
            // The bottom-most part of the circumcircle is our Fortune 'circle
            // event', and its center is a vertex potentially part of the final
            // Voronoi diagram.
            double bx = objSite.x;
            double by = objSite.y;
            double ax = objSiteLeft.x - bx;
            double ay = objSiteLeft.y - by;
            double cx = objSiteRight.x - bx;
            double cy = objSiteRight.y - by;

            // If points l->c->r are clockwise, then center beach section does not
            // collapse, hence it can't end up as a vertex (we reuse 'd' here, which
            // sign is reverse of the orientation, hence we reverse the test.
            // http://en.wikipedia.org/wiki/Curve_orientation#Orientation_of_a_simple_polygon
            // rhill 2011-05-21: Nasty finite precision error which caused circumcircle() to
            // return infinites: 1e-12 seems to fix the problem.
            double d = 2 * (ax * cy - ay * cx);
            if (d >= -2e-12)
            {
                return;
            }

            double ha = ax * ax + ay * ay;
            double hc = cx * cx + cy * cy;
            double x = (cy * ha - ay * hc) / d;
            double y = (ax * hc - cx * ha) / d;
            double ycenter = y + by;

            // Important: ybottom should always be under or at sweep, so no need
            // to waste CPU cycles by checking

            // Recycle circle event object if possible.
            Circle objCircle = this.GetCircle();

            objCircle.Arc = objArc;
            objCircle.Site = objSite;
            objCircle.x = x + bx;
            objCircle.y = ycenter + Math.Sqrt(x * x + y * y); // y bottom
            objCircle.ycenter = ycenter;
            objArc.Circle = objCircle;

            // find insertion point in RB-tree: circle events are ordered from
            // smallest to largest
            Circle objNodePrevious = null;
            Circle objNode = this.Circles.Root as Circle;

            while (objNode != null)
            {
                if (objCircle.y < objNode.y || (objCircle.y == objNode.y && objCircle.x <= objNode.x))
                {
                    if (objNode.Left != null)
                    {
                        objNode = objNode.Left as Circle;
                    }
                    else
                    {
                        objNodePrevious = objNode.Previous as Circle;
                        break;
                    }
                }
                else
                {
                    if (objNode.Right != null)
                    {
                        objNode = objNode.Right as Circle;
                    }
                    else
                    {
                        objNodePrevious = objNode;
                        break;
                    }
                }
            }

            this.Circles.InsertSuccessor(objNodePrevious, objCircle);
            if (objNodePrevious == null)
            {
                this.FirstCircle = objCircle;
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Detach a circle event.
        /// </summary>
        private void DetachCircleEvent(Beach objArc)
        {
            Circle objCircle = objArc.Circle;

            if (objCircle == null)
            {
                return;
            }

            if (objCircle.Previous == null)
            {
                this.FirstCircle = objCircle.Next as Circle;
            }

            // Remove from RBTree.
            this.Circles.RemoveNode(objCircle);
            this.CircleJunkyard.Push(objCircle);
            objArc.Circle = null;
        }