Пример #1
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>	Insert the edge at infinity into the edge list for the vertices at infinity. </summary>
        /// <remarks>	Darrellp, 2/19/2011. </remarks>
        /// <param name="edge">				Edge at infinity being added. </param>
        /// <param name="leadingVtxCw">		Vertex on the left of infinite poly as we look out. </param>
        /// <param name="trailingVtxCw">	Vertex on the right. </param>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        private static void HookEdgeAtInfinityToVerticesAtInfinity(FortuneEdge edge, FortuneVertex leadingVtxCw,
                                                                   FortuneVertex trailingVtxCw)
        {
            // if we've only got one edge at infinity
            if (leadingVtxCw.FortuneEdges.Count == 1)
            {
                // Add this one as a placeholder
                //
                // This will be overwritten later but we have to insert here so that we can insert ourselves at
                // index 2.  This is just a placeholder.
                leadingVtxCw.FortuneEdges.Add(edge);
            }

            // Add this edge into it's proper position
            leadingVtxCw.FortuneEdges.Add(edge);

            // If we have three edges
            if (trailingVtxCw.FortuneEdges.Count == 3)
            {
                // Overwrite the placeholder we placed in another call
                //
                // Here is where the overwriting referred to above occurs
                // This will happen on a later call - not on the current one
                trailingVtxCw.FortuneEdges[1] = edge;
            }
            else
            {
                // Otherwise just add us in to the trailing vertex's list of edges
                trailingVtxCw.FortuneEdges.Add(edge);
            }
        }
Пример #2
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        ///     Finds the third polygon which created this vertex besides the two on each side of the passed
        ///     in edge.
        /// </summary>
        /// <remarks>	Darrellp, 2/19/2011. </remarks>
        /// <param name="edge">	Edge in question. </param>
        /// <returns>	The polygon "opposite" this edge. </returns>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        internal FortunePoly PolyThird(FortuneEdge edge)
        {
            // Get the indices for the two polys on each side of our passed in edge
            var i1 = edge.Poly1.Index;
            var i2 = edge.Poly2.Index;

            // For each edge incident with this vertex
            foreach (var edgeDifferent in FortuneEdges)
            {
                // If it's not our own edge
                if (edgeDifferent != edge)
                {
                    // The polygon we want is on one side or the other of this edge
                    var i1Diff = edgeDifferent.Poly1.Index;

                    // If that edge's poly1 is one of our polygons
                    if (i1Diff == i1 || i1Diff == i2)
                    {
                        // Then we're looking for his poly2
                        return(edgeDifferent.Poly2);
                    }

                    // Otherwise, we're looking for his poly1
                    return(edgeDifferent.Poly1);
                }
            }

            return(null);
        }
Пример #3
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>	Insert a new parabola into the beachline when the beachline spans the X axis. </summary>
        /// <remarks>
        ///     This is the normal case.  We insert our new parabola and split the parabola above our site in
        ///     two. This means one new leaf node is created for leftmost of the two nodes in the split (the
        ///     old lfn is recycled to become the right node of the split).  Also a new internal node to
        ///     parent all this.
        /// </remarks>
        /// <param name="lfnOld">			Parabola above the new site. </param>
        /// <param name="lfnNewParabola">	parabola for the new site. </param>
        /// <param name="innSubRoot">
        ///     Parent node of both lfnOld and lfnNewParabola represneting
        ///     the breakpoint between them.
        /// </param>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        private static void InsertAtDifferentY(LeafNode lfnOld, LeafNode lfnNewParabola, InternalNode innSubRoot)
        {
            // The old lfn will become the new right half of the split but we need a new leaf node
            // for the left half of the split...
            var lfnLeftHalf         = new LeafNode(lfnOld.Poly);
            var innSubRootLeftChild = new InternalNode(lfnOld.Poly, lfnNewParabola.Poly);
            var edge = new FortuneEdge();

            // This is all fairly straightforward (albeit dense) insertion of a node into a binary tree.
            innSubRoot.RightChild = lfnOld;
            innSubRoot.LeftChild  = innSubRootLeftChild;
            innSubRoot.SetEdge(edge);
            innSubRoot.AddEdgeToPolygons(edge);
            innSubRootLeftChild.LeftChild  = lfnLeftHalf;
            innSubRootLeftChild.RightChild = lfnNewParabola;
            innSubRootLeftChild.SetEdge(edge);
            lfnNewParabola.LeftAdjacentLeaf  = lfnLeftHalf;
            lfnNewParabola.RightAdjacentLeaf = lfnOld;
            lfnLeftHalf.LeftAdjacentLeaf     = lfnOld.LeftAdjacentLeaf;
            lfnLeftHalf.RightAdjacentLeaf    = lfnNewParabola;

            if (lfnOld.LeftAdjacentLeaf != null)
            {
                lfnOld.LeftAdjacentLeaf.RightAdjacentLeaf = lfnLeftHalf;
            }

            lfnOld.LeftAdjacentLeaf = lfnNewParabola;
            edge.SetPolys(innSubRoot.PolyRight, innSubRoot.PolyLeft);
        }
Пример #4
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        ///     Set up the polygon at infinity.  The main difficulty here consists in traversing around the
        ///     infinite polygons at the edge of the diagram in order.
        /// </summary>
        /// <remarks>	Darrellp, 2/18/2011. </remarks>
        /// <param name="we">				WingedEdge structure we'll add the polygon at infinity to. </param>
        /// <param name="polyStart">		Infinite polygon to start the polygon at infinity's polygon list with. </param>
        /// <param name="iLeadingEdgeCw">	Starting infinite edge. </param>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        private static void AddPolygonAtInfinity(WE we, FortunePoly polyStart, int iLeadingEdgeCw)
        {
            // See if we've got a degenerate case
            //
            // Such as a single point
            if (polyStart == null)
            {
                return;
            }

            // Initialize
            var polyCur = polyStart;
            int iLeadingEdgeNext;

            // Create the infamous polygon at infinity...
            var         polyAtInfinity         = new FortunePoly(new Vector(0, 0), -1);
            FortuneEdge edgePreviousAtInfinity = null;

            // Declare this the official polygon at infinity
            polyAtInfinity.FAtInfinity = true;

            // Add it to the winged edge
            we.AddPoly(polyAtInfinity);

            do
            {
                // Add the edge at infinity between our current poly and the poly at infinity
                edgePreviousAtInfinity = AddEdgeAtInfinity(
                    polyAtInfinity,
                    polyCur,
                    iLeadingEdgeCw,
                    edgePreviousAtInfinity,
                    out var polyNext,
                    out iLeadingEdgeNext);
                we.AddEdge(edgePreviousAtInfinity);

                // Move to the neighboring polygon at infinity
                polyCur        = polyNext;
                iLeadingEdgeCw = iLeadingEdgeNext;

                // Save this edge as the "first edge" for the polygon at infinity
                //
                // We could check to do this only once, but it doesn't make any difference which
                // edge we get, just so long as we get one and the check would take as long as
                // just doing it every time.
                polyAtInfinity.FirstEdge = edgePreviousAtInfinity;
            }
            // we reach the end of the "outer" infinite polygons of the diagram
            //
            // Set each of the outer infinite polygons up with an edge at infinity to separate
            // them from the polygon at infinity
            while (polyCur != polyStart);

            // Thread the last poly back to the first
            var edgeFirstAtInfinity = polyCur.FortuneEdges[iLeadingEdgeNext];

            edgePreviousAtInfinity.EdgeCCWPredecessor = edgeFirstAtInfinity;
            edgeFirstAtInfinity.EdgeCWSuccessor       = edgePreviousAtInfinity;
        }
Пример #5
0
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 /// <summary>	Remove an edge. </summary>
 /// <remarks>	This really only makes much sense for zero length edges. </remarks>
 /// <param name="edge">	Edge to remove. </param>
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 internal void DetachEdge(FortuneEdge edge)
 {
     // Remove the zero length edge
     //
     // We do this by removing it's end vertex, reassigning the proper
     // vertex in each of the edges which formerly connected to that vertex and splicing those edges into the
     // the proper spot for the edge list of our start vertex and finally removing it from the edge list of
     // both polygons which it adjoins.
     edge.ReassignVertexEdges();
 }
Пример #6
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>	Handle the top N nodes located on a single horizontal line. </summary>
        /// <remarks>
        ///     This only handles the corner case where the top N nodes are on the same horizontal
        ///     line.  In that case the parabolas from previous points are vertically straight up and only
        ///     project to a single point on the x axis so that the beachline is a series of points rather
        ///     than a series of parabolas.  When that is the case we can't "intersect" new points with
        ///     parabolas that span the x axis.  After the scanline passes that initial set of topmost points,
        ///     there will always be a parabola which projects to the entire x axis so no need for this
        ///     special handling. Normally, we produce two new parabolas at a site event like this - the new
        ///     parabola for the site itself and the new parabola produced when we split the parabola above
        ///     us.  In this case there is no parabola above us so we only produce one new parabola - the one
        ///     inserted by the site.
        /// </remarks>
        /// <param name="lfn">				LeafNode of the (degenerate) parabola nearest us. </param>
        /// <param name="lfnNewParabola">	LeafNode we're inserting. </param>
        /// <param name="innParent">		Parent of lfnOld. </param>
        /// <param name="innSubRoot">		Root of the tree. </param>
        /// <param name="fLeftChild">		Left child of innParent. </param>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        private static void NdInsertAtSameY(
            LeafNode lfn,
            LeafNode lfnNewParabola,
            InternalNode innParent,
            InternalNode innSubRoot,
            bool fLeftChild)
        {
            // Locals
            LeafNode lfnLeft, lfnRight;
            var      lfnAdjacentParabolaLeft  = lfn.LeftAdjacentLeaf;
            var      lfnAdjacentParabolaRight = lfn.RightAdjacentLeaf;

            if (lfnNewParabola.Poly.VoronoiPoint.X < lfn.Poly.VoronoiPoint.X)
            {
                lfnLeft  = lfnNewParabola;
                lfnRight = lfn;
            }
            else
            {
                //! Note: I don't think this case ever occurs in practice since we pull events off with higher
                //! x coordinates before events with lower x coordinates
                lfnLeft  = lfn;
                lfnRight = lfnNewParabola;
            }

            innSubRoot.PolyLeft  = lfnLeft.Poly;
            innSubRoot.PolyRight = lfnRight.Poly;

            innSubRoot.LeftChild  = lfnLeft;
            innSubRoot.RightChild = lfnRight;

            var edge = new FortuneEdge();

            innSubRoot.SetEdge(edge);
            innSubRoot.AddEdgeToPolygons(edge);
            lfnLeft.LeftAdjacentLeaf   = lfnAdjacentParabolaLeft;
            lfnLeft.RightAdjacentLeaf  = lfnRight;
            lfnRight.LeftAdjacentLeaf  = lfnLeft;
            lfnRight.RightAdjacentLeaf = lfnAdjacentParabolaRight;

            if (innParent != null)
            {
                if (fLeftChild)
                {
                    innParent.PolyLeft = lfnRight.Poly;
                }
                else
                {
                    innParent.PolyRight = lfnLeft.Poly;
                }
            }

            edge.SetPolys(innSubRoot.PolyRight, innSubRoot.PolyLeft);
        }
Пример #7
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        ///     Find the common polygon between two edges.  An assertion will be raised if there is no common
        ///     polygon.
        /// </summary>
        /// <remarks>	Darrellp, 2/19/2011. </remarks>
        /// <param name="edge">	Edge to find a common poly with. </param>
        /// <returns>	The common polygon. </returns>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        private FortunePoly PolyCommon(FortuneEdge edge)
        {
            // If my Poly1 is the same as one of the edge's polys
            if (ReferenceEquals(Poly1, edge.Poly1) || ReferenceEquals(Poly1, edge.Poly2))
            {
                // Return poly1
                return(Poly1);
            }

            // Otherwise, return Poly2
            return(Poly2);
        }
Пример #8
0
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 /// <summary>	One of our incoming edges is zero length so note it properly in the polygons. </summary>
 /// <remarks>
 ///     This happens when cocircular generators cause more than one circle event at the same
 ///     location.
 /// </remarks>
 /// <param name="edgeNearSibling">	Immediate sibling. </param>
 /// <param name="edgeFarSibling">	Far sibling. </param>
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 private static void SetZeroLengthFlagOnPolys(FortuneEdge edgeNearSibling, FortuneEdge edgeFarSibling)
 {
     // If it's the edge between us and our near sibling that's zero length
     if (edgeNearSibling.VtxEnd != null && edgeNearSibling.FZeroLength())
     {
         // Both polys on each side of the far edge need to be marked as having a zero length edge
         edgeNearSibling.Poly1.FZeroLengthEdge     =
             edgeNearSibling.Poly2.FZeroLengthEdge = true;
     }
     else
     {
         // Both polys on each side of the near edge need to be marked as having a zero length edge
         edgeFarSibling.Poly1.FZeroLengthEdge     =
             edgeFarSibling.Poly2.FZeroLengthEdge = true;
     }
 }
Пример #9
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>	Splits a doubly infinite edge. </summary>
        /// <remarks>	Darrellp, 2/18/2011. </remarks>
        /// <param name="edge">	Edge we need to split. </param>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        private static void SplitDoublyInfiniteEdge(FortuneEdge edge)
        {
            // Initialize
            var pt1   = edge.Poly1.VoronoiPoint;
            var pt2   = edge.Poly2.VoronoiPoint;
            var dx    = pt2.X - pt1.X;
            var dy    = pt2.Y - pt1.Y;
            var ptMid = new Vector((pt1.X + pt2.X) / 2, (pt1.Y + pt2.Y) / 2);

            // Infinite vertices have directions in them rather than locations
            var vtx1 = FortuneVertex.InfiniteVertex(new Vector(-dy, dx));
            var vtx2 = FortuneVertex.InfiniteVertex(new Vector(dy, -dx));

            // Create the new edge an link it in
            edge.VtxStart = new FortuneVertex(ptMid);
            edge.VtxEnd   = vtx1;
            var edgeNew = new FortuneEdge {
                VtxStart = edge.VtxStart, VtxEnd = vtx2
            };

            edgeNew.SetPolys(edge.Poly1, edge.Poly2);
            edge.Poly1.AddEdge(edgeNew);
            edge.Poly2.AddEdge(edgeNew);
            ((FortuneVertex)edge.VtxStart).Add(edge);
            ((FortuneVertex)edge.VtxStart).Add(edgeNew);
            vtx1.Add(edge);
            vtx2.Add(edgeNew);
            edge.FSplit = edgeNew.FSplit = true;

            // If the edge "leans right"
            //
            // We have to be very picky about how we set up the left and right
            // polygons for our new rays.
            // ReSharper disable once CompareOfFloatsByEqualityOperator
            if (dx == 0 || dx * dy > 0)             // dy == 0 case needs to fall through...
            {
                // Set up left and right polygons one way
                edge.PolyRight = edgeNew.PolyLeft = edge.Poly1;
                edge.PolyLeft  = edgeNew.PolyRight = edge.Poly2;
            }
            else
            {
                // Set left and right polygons the other way
                edge.PolyLeft  = edgeNew.PolyRight = edge.Poly1;
                edge.PolyRight = edgeNew.PolyLeft = edge.Poly2;
            }
        }
Пример #10
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>	Turn a null endpoint of the ray into an infinite vertex. </summary>
        /// <remarks>	Darrellp, 2/18/2011. </remarks>
        /// <param name="edge">	Edge with the null vertex. </param>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        private static void ProcessRay(FortuneEdge edge)
        {
            // If it's the start vertex that's null
            if (edge.VtxStart == null)
            {
                // Swap the vertices
                //
                // This is what justifies the assertion in WeEdge.FLeftOf() (see the code).
                edge.VtxStart = edge.VtxEnd;
                edge.VtxEnd   = null;
            }

            // Replace the null vertex with an infinite vertex
            var pt1   = edge.Poly1.VoronoiPoint;
            var pt2   = edge.Poly2.VoronoiPoint;
            var ptMid = new Vector((pt1.X + pt2.X) / 2, (pt1.Y + pt2.Y) / 2);

            // Point the ray in the proper direction
            //
            // We have to be careful to get this ray pointed in the proper orientation.  At
            // this point we just have a vertex and points which are the original voronoi
            // points which created these infinite polys.  That's enough to figure out the
            // absolute direction the voronoi points but not enough to determine which "orientation"
            // it points along.  To do this, we find the third polygon at the "base" of this ray
            // and point the ray "away" from it.
            var polyThird             = ((FortuneVertex)edge.VtxStart).PolyThird(edge);
            var fThirdOnLeft          = FLeft(pt1, pt2, polyThird.VoronoiPoint);
            var dx                    = pt2.X - pt1.X;
            var dy                    = pt2.Y - pt1.Y;
            var ptProposedDirection   = new Vector(dy, -dx);
            var ptInProposedDirection = new Vector(ptMid.X + dy, ptMid.Y - dx);
            var fProposedOnLeft       = FLeft(pt1, pt2, ptInProposedDirection);

            // Do we need to reverse orientation?
            if (fProposedOnLeft == fThirdOnLeft)
            {
                // Do it
                ptProposedDirection.X = -ptProposedDirection.X;
                ptProposedDirection.Y = -ptProposedDirection.Y;
            }

            // Create the new infinite vertex and add it to our edge
            edge.VtxEnd = FortuneVertex.InfiniteVertex(ptProposedDirection);
            ((FortuneVertex)edge.VtxEnd).FortuneEdges.Add(edge);
        }
Пример #11
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        ///     Determine whether two edges connect at a common vertex and if so, how they connect.
        /// </summary>
        /// <remarks>	Darrellp, 2/19/2011. </remarks>
        /// <param name="edge1">					First edge. </param>
        /// <param name="edge2">					Second edge. </param>
        /// <param name="fEdge1ConnectsAtStartVtx">
        ///     [out] True if edge1 connects to edge2 at its start
        ///     vertex, else false.
        /// </param>
        /// <param name="fEdge2ConnectsAtStartVtx">
        ///     [out] True if edge2 connects to edge1 at its start
        ///     vertex, else false.
        /// </param>
        /// <returns>	true if the edges connect. </returns>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        internal static bool FConnectsTo(
            FortuneEdge edge1,
            FortuneEdge edge2,
            out bool fEdge1ConnectsAtStartVtx,
            out bool fEdge2ConnectsAtStartVtx)
        {
            // Locals
            var fRet = false;

            // Init out parameters to false
            fEdge1ConnectsAtStartVtx = false;
            fEdge2ConnectsAtStartVtx = false;

            // RQS- Compare starting and ending vertices
            if (ReferenceEquals(edge1.VtxStart, edge2.VtxStart))
            {
                fEdge1ConnectsAtStartVtx = true;
                fEdge2ConnectsAtStartVtx = true;
                fRet = true;
            }
            else if (ReferenceEquals(edge1.VtxStart, edge2.VtxEnd))
            {
                fEdge1ConnectsAtStartVtx = true;
                fRet = true;
            }
            else if (ReferenceEquals(edge1.VtxEnd, edge2.VtxStart))
            {
                fEdge2ConnectsAtStartVtx = true;
                fRet = true;
            }
            else if (ReferenceEquals(edge1.VtxEnd, edge2.VtxEnd))
            {
                fRet = true;
            }
            //-RQS

            // Return the result
            return(fRet);
        }
Пример #12
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        ///     Get the next edge in both the cw and ccw directions from this edge at the given 3 valent
        ///     vertex.
        /// </summary>
        /// <remarks>
        ///     This is the simplest and most common case.  It's called before the winged edge stuff is set up
        ///     so we have to search manually.  The edges have been sorted in clockwise order however.
        ///     Darrellp, 2/19/2011.
        /// </remarks>
        /// <param name="vtx">		vertex to use. </param>
        /// <param name="edgeCW">	[out] returned cw edge. </param>
        /// <param name="edgeCCW">	[out] returned ccw edge. </param>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        private void GetSuccessorEdgesFrom3ValentVertex(
            FortuneVertex vtx,
            out FortuneEdge edgeCW,
            out FortuneEdge edgeCCW)
        {
            // Locals
            int iEdge;

            // Figure out which of the edges is ours
            for (iEdge = 0; iEdge < 3; iEdge++)
            {
                // If the current edge is us
                if (ReferenceEquals(vtx.FortuneEdges[iEdge], this))
                {
                    break;
                }
            }

            // The next two edges, in order, are the onew we're looking for
            edgeCW  = vtx.FortuneEdges[(iEdge + 1) % 3];
            edgeCCW = vtx.FortuneEdges[(iEdge + 2) % 3];
        }
Пример #13
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        ///     Get the next edge in both the cw and ccw directions from this edge at the given vertex.
        /// </summary>
        /// <remarks>
        ///     This routine is called before they've been set up as winged edges so we have to search them
        ///     out ourselves.  The edges have been ordered in CW order, however.
        ///     Darrellp, 2/19/2011.
        /// </remarks>
        /// <param name="vtx">		vertex to use. </param>
        /// <param name="edgeCW">	[out] returned cw edge. </param>
        /// <param name="edgeCCW">	[out] returned ccw edge. </param>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        private void GetSuccessorEdgesFromVertex(
            FortuneVertex vtx,
            out FortuneEdge edgeCW,
            out FortuneEdge edgeCCW)
        {
            // Are we free of zero length edges?
            if (vtx.FortuneEdges.Count == 3)
            {
                // Do the extremely simple, extremely common 3 valent case
                GetSuccessorEdgesFrom3ValentVertex(vtx, out edgeCW, out edgeCCW);
            }
            else
            {
                // Locals
                int iEdge;
                int cEdges;

                // If we're looking at our start vertex
                if (vtx == VtxStart)
                {
                    // Find our place in the list of edges for start vertex
                    iEdge  = EdgeIndex(true);
                    cEdges = ((FortuneVertex)VtxStart).CtEdges;
                }
                else
                {
                    // Find our place in the list of edges for end vertex
                    iEdge  = EdgeIndex(false);
                    cEdges = ((FortuneVertex)VtxEnd).CtEdges;
                }

                // Get our immediate neighbors on the edge list
                edgeCW  = vtx.FortuneEdges[(iEdge + 1) % cEdges];
                edgeCCW = vtx.FortuneEdges[(iEdge + cEdges - 1) % cEdges];
            }
        }
Пример #14
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        ///     Remove a parabola node from the beachline since it's being squeezed out and insert a vertex
        ///     into the voronoi diagram.
        /// </summary>
        /// <remarks>
        ///     This happens when a circle event occurs.  It's a rather delicate operation. From the point of
        ///     view of the voronoi diagram, we have two edges from above coming together into the newly
        ///     created vertex and a new edge created which descends below it.  This is really where the meat
        ///     of actually creating the voronoi diagram occurs.  One of the important details which seems to
        ///     be left totally out of the book is the importance of keeping accurate left and right sibling
        ///     pointers on the leaf nodes.  Since each leaf node represents a parabola in the beachline,
        ///     these pointers represent the set of parabolas from the left to the right of the beachline.
        ///     In a case like this where a parabola is being squeezed out, it's left and right siblings will
        ///     not butt up against each other forming a new edge and we need to be able to locate both these
        ///     nodes in order to make everything come out right.
        ///     This is very persnickety code.
        /// </remarks>
        /// <param name="cevt">				Circle event which caused this. </param>
        /// <param name="lfnEliminated">	Leaf node for the parabola being eliminated. </param>
        /// <param name="voronoiVertex">	The new vertex to be inserted into the voronoi diagram. </param>
        /// <param name="evq">				Event queue. </param>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        internal void RemoveNodeAndInsertVertex(CircleEvent cevt, LeafNode lfnEliminated, Vector voronoiVertex,
                                                EventQueue evq)
        {
            // Initialize
            var yScanLine = cevt.Pt.Y;

            // Determine whether we're the left or right child of our parent
            var fLeftChildEliminated = lfnEliminated.IsLeftChild;
            var innParent            = lfnEliminated.NdParent;

            // Retrieve sibling nodes
            var lfnLeft        = lfnEliminated.LeftAdjacentLeaf;
            var lfnRight       = lfnEliminated.RightAdjacentLeaf;
            var lfnNearSibling = fLeftChildEliminated ? lfnRight : lfnLeft;

            // Remove from the queue any circle events which involve the eliminated node or its siblings
            RemoveAssociatedCircleEvents(lfnEliminated, evq);

            // remove the leaf from the tree and rearrange the nodes around it
            RemoveLeaf(lfnEliminated);

            // Locate the internal node which represents the breakpoint between our near and far sibling
            var innFarSiblingEdge = lfnNearSibling.InnFindSiblingEdge(fLeftChildEliminated);

            // Get the edges being developed on each side of us
            //
            // The meeting of these edges is what causes the creation of our vertex in the voronoi diagram
            var edgeNearSibling = innParent.Edge;
            var edgeFarSibling  = innFarSiblingEdge.Edge;

            // Create a new fortune vertex to insert into the diagram
            var vertex = new FortuneVertex {
                Pt = voronoiVertex
            };

            // Give both edges from above their brand new vertex - hooray!
            edgeFarSibling.AddVertex(vertex);
            edgeNearSibling.AddVertex(vertex);

            // Is this a zero length edge?
            //
            // Some of our incoming edges are zero length due to cocircular points,
            // so keep track of it in the polys which border them. This will be used
            // later in Fortune.BuildWingedEdge() to determine when to try and remove
            // zero length edges.
            if (cevt.FZeroLength)
            {
                // Mark the poly as having a zero length edge.
                //
                // We can't eliminate it here because most of our winged edge machinery
                // needs to assume three edges entering every vertex.  We'll take care of
                // it later in post-processing.  This flag is the signal to do that.
                SetZeroLengthFlagOnPolys(edgeNearSibling, edgeFarSibling);
            }

            // RQS- Add edges to the vertex in proper clockwise direction
            if (fLeftChildEliminated)
            {
                vertex.Add(edgeFarSibling);
                vertex.Add(edgeNearSibling);
            }
            else
            {
                vertex.Add(edgeNearSibling);
                vertex.Add(edgeFarSibling);
            }
            // -RQS

            // Create the new edge which emerges below this vertex
            var edge = new FortuneEdge();

            edge.AddVertex(vertex);
            vertex.Add(edge);

            // Add the edge to our siblings
            //
            // Since lfnEliminated is being removed, it's siblings now butt against each other forming
            // the new edge so save that edge on the internal node and add it to the poly for the
            // generator represented by the near sibling.  This means that polygon edges get added in
            // a fairly random order.  They'll be sorted in postprocessing.

            // Add it to our winged edge polygon
            lfnNearSibling.Poly.AddEdge(edge);

            // Also add it to our beachline sibling
            innFarSiblingEdge.Edge = edge;

            // Fix up the siblings and the edges/polygons they border
            //
            // The inner node which used to represent one of the incoming edges now takes on responsibility
            // for the newly created edge so it no longer borders the polygon represented by the eliminated
            // leaf node, but rather borders the polygon represented by its sibling on the other side.
            // Also, that polygon receives a new edge.

            // If we eliminated the left child from a parent
            if (fLeftChildEliminated)
            {
                // Reset the data on the inner node representing our far sibling
                innFarSiblingEdge.PolyRight = lfnNearSibling.Poly;
                innFarSiblingEdge.PolyLeft.AddEdge(edge);

                // If this event represented a zero length edge
                if (cevt.FZeroLength)
                {
                    // Keep track of it in the fortune polygon
                    innFarSiblingEdge.PolyLeft.FZeroLengthEdge = true;
                }
            }
            else
            {
                // Reset the data on the inner node representing our far sibling
                innFarSiblingEdge.PolyLeft = lfnNearSibling.Poly;
                innFarSiblingEdge.PolyRight.AddEdge(edge);

                // If this event represented a zero length edge
                if (cevt.FZeroLength)
                {
                    // Keep track of it in the fortune polygon
                    innFarSiblingEdge.PolyRight.FZeroLengthEdge = true;
                }
            }

            // Set the polygons which border the new edge
            edge.SetPolys(innFarSiblingEdge.PolyRight, innFarSiblingEdge.PolyLeft);

            // Create new circle events for our siblings
            //
            // Now that we're squeezed out, our former left and right siblings become immediate siblings
            // so we need to set new circle events to represent when they get squeezed out by their
            // newly acquired siblings
            CreateCircleEventFromTriple(lfnLeft.LeftAdjacentLeaf, lfnLeft, lfnRight, yScanLine, evq);
            CreateCircleEventFromTriple(lfnLeft, lfnRight, lfnRight.RightAdjacentLeaf, yScanLine, evq);
        }
Пример #15
0
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 /// <summary>	Sets our edge for this internal node. </summary>
 /// <remarks>	Darrellp, 2/18/2011. </remarks>
 /// <param name="edge">	The edge. </param>
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 internal void SetEdge(FortuneEdge edge)
 {
     Edge = edge;
 }
Пример #16
0
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 /// <summary>	Adds an edge to the fortune polygons we abut. </summary>
 /// <remarks>	Darrellp, 2/18/2011. </remarks>
 /// <param name="edge">	The edge. </param>
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 internal void AddEdgeToPolygons(FortuneEdge edge)
 {
     PolyLeft.AddEdge(edge);
     PolyRight.AddEdge(edge);
 }
Пример #17
0
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 /// <summary>
 ///     Edges are assumed to be added in a Clockwise direction.  The first edge is random and has no
 ///     particular significance.
 /// </summary>
 /// <remarks>	Darrellp, 2/19/2011. </remarks>
 /// <param name="edge">	Next clockwise edge to add. </param>
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 public void Add(FortuneEdge edge)
 {
     FortuneEdges.Add(edge);
 }
Пример #18
0
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 /// <summary>	Adds an edge to the Fortune polygon. </summary>
 /// <remarks>	Darrellp, 2/22/2011. </remarks>
 /// <param name="edge">	The edge to be added. </param>
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 internal void AddEdge(FortuneEdge edge)
 {
     FortuneEdges.Add(edge);
 }
Пример #19
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        ///     Add an edge at infinity and step the polygon and edge along to the next infinite polygon and
        ///     rayed edge.
        /// </summary>
        /// <remarks>	Darrellp, 2/18/2011. </remarks>
        /// <param name="polyAtInfinity">			Polygon at infinity. </param>
        /// <param name="poly">						Infinite polygon we're adding the edge to. </param>
        /// <param name="iLeadingEdgeCw">			index to rayed edge  we start with. </param>
        /// <param name="edgePreviousAtInfinity">
        ///     Edge at infinity we added in the previous infinite
        ///     polygon.
        /// </param>
        /// <param name="polyNextCcw">
        ///     [out] Returns the next infinite polygon to be
        ///     processed.
        /// </param>
        /// <param name="iLeadingEdgeNext">			[out] Returns the next infinite edge. </param>
        /// <returns>	. </returns>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        private static FortuneEdge AddEdgeAtInfinity(
            FortunePoly polyAtInfinity,
            FortunePoly poly,
            int iLeadingEdgeCw,
            WeEdge edgePreviousAtInfinity,
            out FortunePoly polyNextCcw,
            out int iLeadingEdgeNext)
        {
            // Get the other infinite edge
            //
            // This is the edge to the right as we look outward
            var iTrailingEdgeCw = (iLeadingEdgeCw + 1) % poly.VertexCount;
            var edgeLeadingCw   = poly.FortuneEdges[iLeadingEdgeCw];
            var edgeTrailingCw  = poly.FortuneEdges[iTrailingEdgeCw];

            // Next polygon in order is to the left of our leading edge
            polyNextCcw = edgeLeadingCw.PolyLeft as FortunePoly;

            // Create the edge at infinity
            //
            // Create the edge at infinity separating the current infinite polygon from
            // the polygon at infinity.  The vertices for this edge will both be vertices
            // at infinity.  This, of course, doesn't really have any real impact on the
            // "position" of the edge at infinity, but allows us to maintain a properly
            // set up winged edge structure.
            var edgeAtInfinity = new FortuneEdge
            {
                PolyRight = poly,
                PolyLeft  = polyAtInfinity,
                VtxStart  = edgeLeadingCw.VtxEnd,
                VtxEnd    = edgeTrailingCw.VtxEnd
            };

            // The poly at infinity is to the left of the edge, the infinite poly is to its right
            //
            // Start and end vertices are the trailing and leading infinite edges
            // Add the edge at infinity to the poly at infinity and the current infinite poly
            polyAtInfinity.AddEdge(edgeAtInfinity);
            poly.FortuneEdges.Insert(iTrailingEdgeCw, edgeAtInfinity);

            // Set up the wings of the wingedEdge
            edgeAtInfinity.EdgeCWPredecessor = edgeLeadingCw;
            edgeAtInfinity.EdgeCCWSuccessor  = edgeTrailingCw;
            edgeLeadingCw.EdgeCCWSuccessor   = edgeAtInfinity;
            edgeTrailingCw.EdgeCWSuccessor   = edgeAtInfinity;

            // If we've got a previous edge at infinity
            if (edgePreviousAtInfinity != null)
            {
                // Incorporate it properly
                edgePreviousAtInfinity.EdgeCCWPredecessor = edgeAtInfinity;
                edgeAtInfinity.EdgeCWSuccessor            = edgePreviousAtInfinity;
            }

            // Hook up our edge at infinity to our vertices at infinity
            HookEdgeAtInfinityToVerticesAtInfinity(
                edgeAtInfinity,
                edgeAtInfinity.VtxStart as FortuneVertex,
                edgeAtInfinity.VtxEnd as FortuneVertex);

            // Locate the leading edge index in the next polygon

            // For each Edge of the infinite polygon to our left
            // ReSharper disable once PossibleNullReferenceException
            for (iLeadingEdgeNext = 0; iLeadingEdgeNext < polyNextCcw.VertexCount; iLeadingEdgeNext++)
            {
                // If it's the same as our leading CW infinite edge
                if (polyNextCcw.FortuneEdges[iLeadingEdgeNext] == edgeLeadingCw)
                {
                    // then their leading edge is the one immediately preceding it in CW order
                    iLeadingEdgeNext = (polyNextCcw.VertexCount + iLeadingEdgeNext - 1) % polyNextCcw.VertexCount;
                    break;
                }
            }

            // Return the edge at infinity we've created
            return(edgeAtInfinity);
        }