Beispiel #1
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        ///     Clip this voronoi cell with a passed in bounding box.
        /// </summary>
        /// <remarks>
        ///     <para>
        ///         I'm trying to handle all the exceptional cases.  There is one incredibly exceptional
        ///         case which I'm ignoring.  That is the case where there are two vertices at infinity which are
        ///         at such nearly opposite directions without being completely collinear that we can't push
        ///         their points at infinity out far enough to encompass the rest of the box within the range of
        ///         a double.  If this is important to you, then see the comments below, but it's hard to imagine
        ///         it ever arising.
        ///     </para>
        ///     <para>
        ///         Editorial comment - The annoying thing about all of this is that, like in so much of
        ///         computational geometry, the rarer and less significant the exceptional cases are, the more
        ///         difficult they are to handle.  It's both a blessing and a curse - it means that the normal
        ///         cases are generally faster, but it also makes it difficult to get excited about slogging
        ///         through the tedious details of situations that will probably never arise in practice.  Still,
        ///         in order to keep our noses clean, we press on regardless.
        ///     </para>
        ///     Darrellp, 2/26/2011.
        /// </remarks>
        /// <param name="ptUL">	The upper left point of the box. </param>
        /// <param name="ptLR">	The lower right point of the box. </param>
        /// <returns>	An enumerable of real points representing the voronoi cell clipped to the box. </returns>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        public IEnumerable <Vector> BoxVertices(Vector ptUL, Vector ptLR)
        {
            // If no edges, then it's just the entire box
            if (!Edges.Any())
            {
                foreach (var pt in BoxPoints(ptUL, ptLR))
                {
                    yield return(pt);
                }

                yield break;
            }

            var ptsBox = BoxPoints(ptUL, ptLR);

            var fFound = FCheckEasy(out var ptsToBeClipped);

            if (!fFound)
            {
                fFound = FCheckParallelLines(ptsBox, out ptsToBeClipped);
            }

            if (!fFound)
            {
                fFound = FCheckDoublyInfinite(ptsBox, out ptsToBeClipped);
            }

            if (!fFound)
            {
                ptsToBeClipped = RealVertices(CalcRayLength(ptsBox));
            }

            foreach (var pt in ConvexPolyIntersection.FindIntersection(ptsToBeClipped, ptsBox))
            {
                yield return(pt);
            }
        }
Beispiel #2
0
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>	Lloyd relaxation. </summary>
        /// <remarks>
        ///     This routine performs a single Lloyd relaxation on a fortune winged edge structure.  That
        ///     means the points for the voronoi diagram are moved to the centroid of their cell and the
        ///     voronoi algorithm is run again.  In order to do this we have to be able to clip the infinite
        ///     polygons or else their centroid is undefined so a clipping polygon is passed in to clip to.
        ///     Also, as usual, we need a ray length to know how far to extend any infinite rays.  This
        ///     should be a large enough value that all rays extend to the side of the clipping polygon.
        ///     Currently, my clipping algorithm only works for convex polygons so the clipping polygon
        ///     passed in must be convex and the points must be in counterclockwise order.  This works fine
        ///     for clipping to rectangles or voronoi cells which are the two cases I'm currently interested
        ///     in.
        ///     Darrellp, 2/24/2011.
        /// </remarks>
        /// <param name="we">			WingedEdge structure we'll relax. </param>
        /// <param name="rayLength">	Length of the rays we extend. </param>
        /// <param name="polyClip">		The polygon to clip to. </param>
        /// <param name="strength">
        ///     Strength of relaxation.  The default is 1 for "standard"
        ///     relaxation. 0 has no effect.  Negative values can make it more
        ///     "spikey".
        /// </param>
        /// <returns>	The relaxed Winged Edge structure. </returns>
        ////////////////////////////////////////////////////////////////////////////////////////////////////
        public static WE LloydRelax(WE we, double rayLength, IEnumerable <Vector> polyClip, double strength = 1)
        {
            // Locals
            var ptsRelaxed = new List <Vector>();

            // For each polygon in the Winged edge
            foreach (var poly in we.LstPolygons)
            {
                // Skip the polygon at infinity
                if (poly.FAtInfinity)
                {
                    continue;
                }

                // Get the polygon vertices in CCW order
                var ptsPoly = poly.RealVertices(rayLength);

                // Clip them to our clipping polygon
                // ReSharper disable PossibleMultipleEnumeration
                var ptsCentroid =
                    ConvexPolyIntersection.FindIntersection(polyClip, ptsPoly);

                // If this polygon is outside our bounding box, just skip it
                if (!ptsCentroid.Any())
                {
                    continue;
                }

                // Locals for the centroid calculations
                var cpts       = 0;
                var ptCentroid = new Vector();

                // For each point in the clipped polygon
                foreach (var pt in ptsCentroid)
                {
                    // Add it in to the centroid accumulator
                    ptCentroid += pt;
                    cpts++;
                }
                // ReSharper restore PossibleMultipleEnumeration

                // Determine the centroid
                var ctrd = new Vector(ptCentroid.X / cpts, ptCentroid.Y / cpts);

                // If strength is the default -1, just take our centroid
                // ReSharper disable once CompareOfFloatsByEqualityOperator
                if (strength == 1)
                {
                    // Calculate the new centroid and add it to our list of points
                    ptsRelaxed.Add(new Vector(ptCentroid.X / cpts, ptCentroid.Y / cpts));
                }
                else
                {
                    // Move the original voronoi point nearer or further from the centroid
                    ptsRelaxed.Add(poly.VoronoiPoint + (poly.VoronoiPoint - ctrd) * -strength);
                }
            }

            // Return the voronoi diagram on all the centroids
            return(ComputeVoronoi(ptsRelaxed));
        }