Пример #1
0
        /// <summary>
        /// Searches through the extension segments and makes a list of new vertices that did not exist previously.
        /// </summary>
        /// <param name="polygon">Polygon that new vertices have been found for.</param>
        /// <param name="extensionSegments">List of extension segments.</param>
        /// <returns>A list of new vertices.</returns>
        private static HashSet <Vector2> _GetNewVertices(ChordlessPolygon polygon, List <PolyEdge> extensionSegments)
        {
            var newVertices      = new HashSet <Vector2>();
            var existingVertices = new HashSet <Vector2>();

            foreach (Vector2 vertex in polygon.outerPerim)
            {
                existingVertices.Add(vertex);
            }
            foreach (ImmutableList <Vector2> hole in polygon.holes)
            {
                foreach (Vector2 vertex in hole)
                {
                    existingVertices.Add(vertex);
                }
            }
            foreach (PolyEdge edge in extensionSegments)
            {
                if (!existingVertices.Contains(edge.a))
                {
                    newVertices.Add(edge.a);
                }
                if (!existingVertices.Contains(edge.b))
                {
                    newVertices.Add(edge.b);
                }
            }
            return(newVertices);
        }
Пример #2
0
        /// <summary>
        /// Cut down the input overextension coordinate to the closest edge.  Checks edges from:
        ///     1. The polygon's perimeter
        ///     2. The polygon's holes perimeters'
        ///     3. Extensions that already exist
        /// </summary>
        /// <param name="polygon">Input polygon.</param>
        /// <param name="extensions">Extension edges that already exist.</param>
        /// <param name="origin">Concave vertex being extended.</param>
        /// <param name="overextension">Vector2 representing the other side of the extension that is currently too far
        /// and needs to be cut down.</param>
        /// <returns>A vector2 representing the other side of where the extension should be, AKA the first (closest) edge it
        /// hits.</returns>
        private static Vector2 _GetCutExtension(ChordlessPolygon polygon, List <PolyEdge> extensions,
                                                Vector2 origin, Vector2 overextension)
        {
            Vector2 cutExtension = overextension;

            for (int i = 0; i < polygon.outerPerim.Length - 1; i++)
            {
                Vector2 perimCoordA = polygon.outerPerim[i];
                Vector2 perimCoordB = polygon.outerPerim[i + 1];
                if (GeometryFuncs.AreSegmentsParallel(origin, overextension, perimCoordA, perimCoordB) ||
                    perimCoordA == origin || perimCoordB == origin)
                {
                    continue;
                }
                Vector2 potentialCutExtension = _CutExtensionWithSegment(origin, overextension, perimCoordA, perimCoordB);
                if (origin.DistanceSquaredTo(potentialCutExtension) < origin.DistanceSquaredTo(cutExtension))
                {
                    cutExtension = potentialCutExtension;
                }
            }

            foreach (ImmutableList <Vector2> hole in polygon.holes)
            {
                for (int i = 0; i < hole.Count - 1; i++)
                {
                    Vector2 perimCoordA = hole[i];
                    Vector2 perimCoordB = hole[i + 1];
                    if (GeometryFuncs.AreSegmentsParallel(origin, overextension, perimCoordA, perimCoordB) ||
                        perimCoordA == origin || perimCoordB == origin)
                    {
                        continue;
                    }
                    Vector2 potentialCutExtension = _CutExtensionWithSegment(origin, overextension, perimCoordA, perimCoordB);
                    if (origin.DistanceSquaredTo(potentialCutExtension) < origin.DistanceSquaredTo(cutExtension))
                    {
                        cutExtension = potentialCutExtension;
                    }
                }
            }

            foreach (PolyEdge edge in extensions)
            {
                Vector2 extCoordA = edge.a;
                Vector2 extCoordB = edge.b;
                if (GeometryFuncs.AreSegmentsParallel(origin, overextension, extCoordA, extCoordB) ||
                    extCoordA == origin || extCoordB == origin)
                {
                    continue;
                }
                Vector2 potentialCutExtension = _CutExtensionWithSegment(origin, overextension, extCoordA, extCoordB);
                if (origin.DistanceSquaredTo(potentialCutExtension) < origin.DistanceSquaredTo(cutExtension))
                {
                    cutExtension = potentialCutExtension;
                }
            }
            return(cutExtension);
        }
Пример #3
0
        /// <summary>
        /// Creates a ChordlessPolygon with just an outer perimeter and flags it as a hole.
        /// </summary>
        /// <param name="cycle"></param>
        /// <returns>A ChordlessPolygon flagged as a hole, just with an outer perimeter.</returns>
        private static ChordlessPolygon _FinaliseInnerHole(List <PolygonSplittingGraphNode> cycle)
        {
            var cyclePerim = new Vector2[cycle.Count];

            for (int i = 0; i < cycle.Count; i++)
            {
                PolygonSplittingGraphNode node = cycle[i];
                cyclePerim[i] = new Vector2(node.x, node.y);
            }
            var holePolygon = new ChordlessPolygon(cyclePerim, Array.Empty <List <Vector2> >(),
                                                   new Dictionary <Vector2, HashSet <Vector2> >(), true);

            return(holePolygon);
        }
Пример #4
0
        /// <summary>
        /// Given an origin and a direction to extend towards, returns the coordinate that is 'far' enough that it goes
        /// beyond the bounds of the polygon.
        /// </summary>
        /// <param name="polygon">Polygon owning the vertex being extended.</param>
        /// <param name="origin">Concave vertex being extended.</param>
        /// <param name="freeDir">Direction that the extension is in.</param>
        /// <returns>Vector2 representing a coordinate beyond the bounds of the polygon's perimeter.</returns>
        private static Vector2 _GetOverextendedCoord(ChordlessPolygon polygon, Vector2 origin, Vector2 freeDir)
        {
            float furthest = (freeDir.x == 0) ? origin.y : origin.x;

            for (int i = 0; i < polygon.outerPerim.Length - 1; i++)
            {
                Vector2 perimVertex = polygon.outerPerim[i];
                if (freeDir.x == 0)
                {     //vertical direction
                    if (freeDir.y > 0 && perimVertex.y > origin.y)
                    { //down
                        if (perimVertex.y > furthest)
                        {
                            furthest = perimVertex.y;
                        }
                    }
                    else if (freeDir.y < 0 && perimVertex.y < origin.y)
                    { //up
                        if (perimVertex.y < furthest)
                        {
                            furthest = perimVertex.y;
                        }
                    }
                }
                else if (freeDir.y == 0)
                {     //horizontal direction
                    if (freeDir.x > 0 && perimVertex.x > origin.x)
                    { //right
                        if (perimVertex.x > furthest)
                        {
                            furthest = perimVertex.x;
                        }
                    }
                    else if (freeDir.x < 0 && perimVertex.x < origin.x)
                    { //left
                        if (perimVertex.x < furthest)
                        {
                            furthest = perimVertex.x;
                        }
                    }
                }
            }
            Vector2 overextension = (freeDir.x == 0) ? new Vector2(origin.x, furthest) : new Vector2(furthest, origin.y);

            return(overextension + freeDir);
        }
Пример #5
0
        /// <summary>
        /// Checks polygon vertices (of both its outer perimeters and holes) and returns a list of the concave ones.
        /// </summary>
        /// <param name="polygon"></param>
        /// <returns>List of concave vertices.</returns>
        public static HashSet <ConcaveVertex> GetConcaveVertices(ChordlessPolygon polygon)
        {
            if (polygon is null)
            {
                throw new ArgumentNullException(nameof(polygon));
            }

            var concaveVertices = new HashSet <ConcaveVertex>();

            concaveVertices.SymmetricExceptWith(_TracePerimeterForConcaveVertices(polygon.outerPerim));

            foreach (ImmutableList <Vector2> hole in polygon.holes)
            {
                concaveVertices.SymmetricExceptWith(_TracePerimeterForConcaveVertices(hole, true));
            }
            return(concaveVertices);
        }
Пример #6
0
        private static (List <PolyEdge>, HashSet <Vector2>) _AddBridgesToExtensions(ChordlessPolygon polygon)
        {
            var extensions      = new List <PolyEdge>();
            var alreadyExtended = new HashSet <Vector2>();

            foreach (Vector2 bridgeA in polygon.bridges.Keys)
            {
                foreach (Vector2 bridgeB in polygon.bridges[bridgeA])
                {
                    var bridgeExtension = new PolyEdge(bridgeA, bridgeB);
                    if (!extensions.Contains(bridgeExtension) && !extensions.Contains(bridgeExtension.GetReverseEdge()))
                    {
                        extensions.Add(bridgeExtension);
                        alreadyExtended.Add(bridgeA);
                        alreadyExtended.Add(bridgeB);
                    }
                }
            }
            return(extensions, alreadyExtended);
        }
Пример #7
0
 /// <summary>
 /// Gets chordless polygon extensions as a list of PolyEdges.  Always fills in bridges first.
 /// </summary>
 /// <param name="polygon"></param>
 /// <param name="concaveVertices">Vertices in polygon that need to be extended.</param>
 /// <param name="chords"></param>
 /// <returns>List of PolyEdges representing extensions.</returns>
 private static List <PolyEdge> _FindVertexExtensions(ChordlessPolygon polygon, HashSet <ConcaveVertex> concaveVertices, List <Chord> chords)
 {
     (List <PolyEdge> extensions, HashSet <Vector2> alreadyExtended) = _AddBridgesToExtensions(polygon);
     foreach (ConcaveVertex concaveVertex in concaveVertices)
     {
         if (alreadyExtended.Contains(concaveVertex.vertex))
         {
             continue;
         }
         Vector2 freeDir = concaveVertex.GetHorizontalFreeDirection();
         if (_IsDirectionChordFree(concaveVertex.vertex, freeDir, concaveVertices, chords))
         { //ensure that if we were to extend in this direction we would not create a chord
         }
         else
         {
             freeDir = concaveVertex.GetVerticalFreeDirection();
         }
         Vector2 overextension = _GetOverextendedCoord(polygon, concaveVertex.vertex, freeDir);
         Vector2 cutExtension  = _GetCutExtension(polygon, extensions, concaveVertex.vertex, overextension);
         extensions.Add(new PolyEdge(concaveVertex.vertex, cutExtension));
     }
     return(extensions);
 }
Пример #8
0
        /// <summary>
        /// Grabs the new vertices in <param>extensionVertices</param> and inserts them into <param>polygon</param>'s existing
        /// perimeters where they fit, and returns two new Lists (representing outer perim and holes respectively) that
        /// are the same as the polygon's current perimeters but with the new vertices inserted.
        /// </summary>
        /// <param name="polygon">Polygon that new vertices are being inserted into.</param>
        /// <param name="extensionVertices">New vertices created by extending the polygon's concave vertices to the closest
        /// edge.</param>
        /// <returns>Two lists, representing the polygon's outer perim and hole perims respectively, but with the new
        /// vertices inserted.</returns>
        private static (List <Vector2>, List <List <Vector2> >) _InsertNewVerticesIntoPerims(ChordlessPolygon polygon,
                                                                                             HashSet <Vector2> extensionVertices)
        {
            var outerPerimWithNewVertices = new List <Vector2>();
            var holesWithNewVertices      = new List <List <Vector2> >();

            for (int i = 0; i < polygon.outerPerim.Length - 1; i++)
            {
                Vector2        thisVertex        = polygon.outerPerim[i];
                Vector2        nextVertex        = polygon.outerPerim[i + 1];
                List <Vector2> verticesInBetween = _GetVerticesInBetween(thisVertex, nextVertex, extensionVertices);
                outerPerimWithNewVertices.Add(thisVertex);
                IOrderedEnumerable <Vector2> orderedNewVertices = verticesInBetween.OrderBy(x => thisVertex.DistanceSquaredTo(x));
                outerPerimWithNewVertices.AddRange(orderedNewVertices);
            }
            outerPerimWithNewVertices.Add(polygon.outerPerim[polygon.outerPerim.Length - 1]);

            foreach (ImmutableList <Vector2> hole in polygon.holes)
            {
                var holePerimWithNewVertices = new List <Vector2>();
                for (int i = 0; i < hole.Count - 1; i++)
                {
                    Vector2        thisVertex        = hole[i];
                    Vector2        nextVertex        = hole[i + 1];
                    List <Vector2> verticesInBetween = _GetVerticesInBetween(thisVertex, nextVertex, extensionVertices);
                    holePerimWithNewVertices.Add(thisVertex);
                    IOrderedEnumerable <Vector2> orderedNewVertices = verticesInBetween.OrderBy(x => thisVertex.DistanceSquaredTo(x));
                    holePerimWithNewVertices.AddRange(orderedNewVertices);
                }
                holePerimWithNewVertices.Add(hole[hole.Count - 1]);
                holesWithNewVertices.Add(holePerimWithNewVertices);
            }
            return(outerPerimWithNewVertices, holesWithNewVertices);
        }