Exemple #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);
            }
        }
Exemple #2
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>	Produce a vertex at infinity. </summary>
        /// <remarks>	Darrellp, 2/19/2011. </remarks>
        /// <param name="ptDirection">	Direction for the vertex. </param>
        /// <param name="fNormalize">	If true we normalize, else not. </param>
        /// <returns>	The vertex at infinity. </returns>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        internal static FortuneVertex InfiniteVertex(Vector ptDirection, bool fNormalize = true)
        {
            var vtx = new FortuneVertex(ptDirection);

            vtx.SetInfinite(fNormalize);
            return(vtx);
        }
Exemple #3
0
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 /// <summary>	Add a vertex in the proper place according to _fStartVertexSet. </summary>
 /// <remarks>	Darrellp, 2/19/2011. </remarks>
 /// <param name="vtx">	Vertex to add. </param>
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 internal void AddVertex(FortuneVertex vtx)
 {
     // If we've already set the start vertex
     if (_fStartVertexSet)
     {
         // This is the end vertex
         VtxEnd = vtx;
     }
     else
     {
         // Make this the start vertex and set the start vertex flag
         _fStartVertexSet = true;
         VtxStart         = vtx;
     }
 }
Exemple #4
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;
            }
        }
Exemple #5
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);
        }
Exemple #6
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];
        }
Exemple #7
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];
            }
        }
Exemple #8
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);
        }