/// <summary>
        /// Use <param>chords</param> to construct Bipartite Graph Nodes and create a dictionary that maps Node -> Chords
        /// (so we can easily get which chords were 'selected' from the Max Independent Set later).
        /// </summary>
        /// <param name="chords">List of chords in polygon.</param>
        /// <returns>A dictionary that maps Bipartite Graph Nodes to Chords.</returns>
        private static Dictionary <BipartiteGraphNode, Chord> _ConvertChordsToNodes(IReadOnlyList <Chord> chords)
        {
            var bipartiteNodeToChords = new Dictionary <BipartiteGraphNode, Chord>();

            for (int i = 0; i < chords.Count; i++)
            {
                Chord chord            = chords[i];
                var   connectedNodeIDs = new List <int>();
                for (int j = 0; j < chords.Count; j++)
                {
                    Chord comparisonChord = chords[j];
                    if (j == i || comparisonChord.direction == chord.direction)
                    {
                        continue;
                    }
                    if (GeometryFuncs.DoSegmentsIntersect(chord.a, chord.b, comparisonChord.a, comparisonChord.b))
                    { //chord B is connected to chord A IFF they intersect, B != A, and they have different orientations
                        connectedNodeIDs.Add(j);
                    }
                }
                BipartiteGraphNode.BipartiteSide side = (chord.direction == Chord.Direction.Vertical) ?
                                                        BipartiteGraphNode.BipartiteSide.Left :
                                                        BipartiteGraphNode.BipartiteSide.Right;
                var bipartiteGraphNode = new BipartiteGraphNode(i, connectedNodeIDs, side);
                bipartiteNodeToChords.Add(bipartiteGraphNode, chord);
            }
            return(bipartiteNodeToChords);
        }
        /// <summary>
        /// Checks if a segment between two vertexes is a valid chord, which relies on the following conditions:
        /// 0. The segment is not in the chords array already (with/without reversed points)
        /// 1. The vertices are different
        /// 2. The segment is vertical or horizontal
        /// 3. The segment does not CONTAIN a part of the polygon's outer perimeter OR hole perimeter(s).
        /// 4 WHICH I FORGOT. The segment does not intersect any part of the perimeter
        /// 5 WHICH I ALSO FORGOT. The segment is actually within the polygon.
        /// </summary>
        /// <param name="pointA"></param>
        /// <param name="pointB"></param>
        /// <param name="allIsoPerims"></param>
        /// <param name="chords"></param>
        /// <returns></returns>
        private static bool _IsChordValid(Vector2 pointA, Vector2 pointB, List <Vector2>[] allIsoPerims,
                                          IEnumerable <Chord> chords)
        {
            if (chords.Any(chord => (chord.a == pointA && chord.b == pointB) || (chord.a == pointB && chord.b == pointA)))
            { //if not already in chords array
                return(false);
            }

            if (pointA == pointB)
            {
                return(false);                  //if vertices are different
            }
            if (pointA.x != pointB.x && pointA.y != pointB.y)
            {
                return(false);                                              //if the segment is vertical or horizontal
            }
            Vector2 midpoint = (pointB - pointA) / 2 + pointA;

            for (int i = 0; i < allIsoPerims.Length; i++)
            {
                List <Vector2> perims = allIsoPerims[i];
                if (i == 0)
                { //midpoint not in poly
                    if (!GeometryFuncs.IsPointInPoly(midpoint, perims.ToArray()))
                    {
                        return(false);
                    }
                }
                else
                { //midpoint in hole
                    if (GeometryFuncs.IsPointInPoly(midpoint, perims.ToArray()))
                    {
                        return(false);
                    }
                }
                for (int j = 0; j < perims.Count - 1; j++) //i < perims.Count - 1 because perims[0] = perims[last]
                {                                          //if segment does not contain a part of the polygon's perimeter(s)
                    Vector2 perimVertexA = perims[j];
                    Vector2 perimVertexB = perims[j + 1];
                    if (GeometryFuncs.DoSegmentsOverlap(pointA, pointB, perimVertexA, perimVertexB))
                    { //segment confirmed to contain part of polygon's perimeter(s)
                        return(false);
                    }
                    if (perimVertexA != pointA && perimVertexA != pointB && perimVertexB != pointA && perimVertexB != pointB)
                    {
                        if (GeometryFuncs.DoSegmentsIntersect(pointA, pointB, perimVertexA, perimVertexB))
                        { //segment intersects part of perimeter
                            return(false);
                        }
                    }
                }
            }
            return(true);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Given some segment represented by <param>segmentA</param> and <param>segmentB</param> that is not parallel to
        /// the segment represented by <param>origin</param> and <param>overextension</param> and if necessary, cuts down
        /// the overextension to the segment IFF the segment cuts origin->overextension.
        /// If the two input segments do not intersect just returns overextension.
        /// </summary>
        /// <param name="origin">Concave vertex being extended.</param>
        /// <param name="overextension">Extension that should reach outside the polygon.</param>
        /// <param name="segmentA"></param>
        /// <param name="segmentB">Segment that is being used to cut the overextension.</param>
        /// <returns>A coordinate between origin and overextension closer to the origin IFF segment cuts origin->overextension,
        /// or overextension if the segment does not intersect origin->overextension.</returns>
        private static Vector2 _CutExtensionWithSegment(Vector2 origin, Vector2 overextension, Vector2 segmentA, Vector2 segmentB)
        {
            if (!GeometryFuncs.DoSegmentsIntersect(origin, overextension, segmentA, segmentB))
            {
                return(overextension);
            }

            Vector2 cutExtension = overextension;

            if (origin.x == overextension.x)
            { //VERTICAL
                cutExtension.y = segmentA.y;
            }
            else if (origin.y == overextension.y)
            { //HORIZONTAL
                cutExtension.x = segmentA.x;
            }

            return(cutExtension);
        }