/// <summary> /// Checks if the other group's outer perimeter is inside this group's perimeter. Inclusive of the two groups /// sharing vertices. /// </summary> /// <param name="otherGroup"></param> /// <returns>True if the other group is inside this group, false otherwise.</returns> public bool IsOtherGroupInThisGroup(ConnectedNodeGroup otherGroup) { HashSet <Vector2> sharedVertices = this.GetSharedVertices(otherGroup); if (sharedVertices.Count == 0) { return(GeometryFuncs.IsPolyInPoly(otherGroup.outerPerimSimplified, this.outerPerimSimplified)); } else { bool isInside = true; foreach (PolygonSplittingGraphNode node in otherGroup.nodes.Values) { var nodeCoord = new Vector2(node.x, node.y); if (sharedVertices.Contains(nodeCoord)) { continue; } if (!GeometryFuncs.IsPointInPoly(nodeCoord, this.outerPerimSimplified)) { isInside = false; break; } } return(isInside); } }
/// <summary> /// Checks which potential holes could be contained within this polygon and adds them /// to holes if they pass the IsPolyInPoly check. /// </summary> /// <param name="potentialHoles"></param> /// <returns></returns> private List <Vector2>[] _GetContainedHoles(List <Vector2>[] potentialHoles) { var confirmedHoles = new List <List <Vector2> >(); foreach (List <Vector2> hole in potentialHoles) { HashSet <Vector2> sharedVertices; if (GeometryFuncs.IsPolyInPoly(hole.ToArray(), this._outerPerim)) { confirmedHoles.Add(hole); } else if ((sharedVertices = this._GetHoleSharedVertices(hole)).Count > 0) { int holeVerticesInPoly = 0; //guilty until proven innocent, to prevent snake poly from containing hole foreach (Vector2 holeVertex in hole) { if (sharedVertices.Contains(holeVertex)) { continue; } if (GeometryFuncs.IsPointInPoly(holeVertex, this._outerPerim) && !GeometryFuncs.IsPointOnPolyBoundary(holeVertex, this._outerPerim)) { holeVerticesInPoly++; } } if (holeVerticesInPoly > 0) { confirmedHoles.Add(hole); } } } return(confirmedHoles.ToArray()); }
/// <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); }