/// <summary> /// Given a polygon defined by an outer ring with one or more inner rings (holes), return a single list of points representing /// a polygon with a hole added to it. The added hole is removed from <paramref name="innerRings"/>. /// </summary> /// <param name="outerRing">A list of Cartographic points defining the outer polygon.</param> /// <param name="innerRings">A list of lists of Cartographic points, each list defining a "hole" in the outer polygon.</param> /// <returns>A single list of Cartographic points defining the polygon, including the eliminated inner ring.</returns> public static List <Cartographic> EliminateHole(List <Cartographic> outerRing, List <List <Cartographic> > innerRings) { // Convert from LLA -> XYZ and project points onto a tangent plane to find the mutually visible vertex. List <Cartesian> cartesianOuterRing = new List <Cartesian>(); foreach (Cartographic point in outerRing) { cartesianOuterRing.Add(Ellipsoid.Wgs84.ToCartesian(point)); } var windingOrder = GetWindingOrder(cartesianOuterRing); List <List <Cartesian> > cartesianInnerRings = new List <List <Cartesian> >(); for (int i = 0; i < innerRings.Count; ++i) { var ring = innerRings[i]; List <Cartesian> cartesianInnerRing = new List <Cartesian>(); foreach (Cartographic point in ring) { cartesianInnerRing.Add(Ellipsoid.Wgs84.ToCartesian(point)); } var innerWindingOrder = GetWindingOrder(cartesianInnerRing); if (innerWindingOrder == windingOrder) { ring.Reverse(); cartesianInnerRing.Reverse(); } cartesianInnerRings.Add(cartesianInnerRing); } EllipsoidTangentPlane tangentPlane = new EllipsoidTangentPlane(Ellipsoid.Wgs84, cartesianOuterRing); cartesianOuterRing = (List <Cartesian>)(tangentPlane.ComputePositionsOnPlane(cartesianOuterRing)); for (int i = 0; i < cartesianInnerRings.Count; i++) { cartesianInnerRings[i] = (List <Cartesian>)(tangentPlane.ComputePositionsOnPlane(cartesianInnerRings[i])); } int visibleVertexIndex = GetMutuallyVisibleVertexIndex(cartesianOuterRing, cartesianInnerRings); int innerRingIndex = GetRightmostRingIndex(cartesianInnerRings); int innerRingVertexIndex = GetRightmostVertexIndex(cartesianInnerRings[innerRingIndex]); List <Cartographic> innerRing = innerRings[innerRingIndex]; List <Cartographic> newPolygonVertices = new List <Cartographic>(); for (int i = 0; i < outerRing.Count; i++) { newPolygonVertices.Add(outerRing[i]); } List <Cartographic> holeVerticesToAdd = new List <Cartographic>(); // If the rightmost inner vertex is not the starting and ending point of the ring, // then some other point is duplicated in the inner ring and should be skipped once. if (innerRingVertexIndex != 0) { for (int j = 0; j <= innerRing.Count; j++) { int index = (j + innerRingVertexIndex) % innerRing.Count; if (index != 0) { holeVerticesToAdd.Add(innerRing[index]); } } } else { for (int j = 0; j < innerRing.Count; j++) { holeVerticesToAdd.Add(innerRing[(j + innerRingVertexIndex) % innerRing.Count]); } } int lastVisibleVertexIndex = newPolygonVertices.FindLastIndex(delegate(Cartographic point) { return(point.Equals(outerRing[visibleVertexIndex])); }); holeVerticesToAdd.Add(outerRing[lastVisibleVertexIndex]); newPolygonVertices.InsertRange(lastVisibleVertexIndex + 1, holeVerticesToAdd); innerRings.RemoveAt(innerRingIndex); return(newPolygonVertices); }
/// <summary> /// Given a polygon defined by an outer ring with one or more inner rings (holes), return a single list of points representing /// a polygon with a hole added to it. The added hole is removed from <paramref name="innerRings"/>. /// </summary> /// <param name="outerRing">A list of Cartographic points defining the outer polygon.</param> /// <param name="innerRings">A list of lists of Cartographic points, each list defining a "hole" in the outer polygon.</param> /// <returns>A single list of Cartographic points defining the polygon, including the eliminated inner ring.</returns> public static List<Cartographic> EliminateHole(List<Cartographic> outerRing, List<List<Cartographic>> innerRings) { // Convert from LLA -> XYZ and project points onto a tangent plane to find the mutually visible vertex. List<Cartesian> cartesianOuterRing = new List<Cartesian>(); foreach (Cartographic point in outerRing) { cartesianOuterRing.Add(Ellipsoid.Wgs84.ToCartesian(point)); } var windingOrder = GetWindingOrder(cartesianOuterRing); List<List<Cartesian>> cartesianInnerRings = new List<List<Cartesian>>(); for(int i = 0; i < innerRings.Count; ++i) { var ring = innerRings[i]; List<Cartesian> cartesianInnerRing = new List<Cartesian>(); foreach (Cartographic point in ring) { cartesianInnerRing.Add(Ellipsoid.Wgs84.ToCartesian(point)); } var innerWindingOrder = GetWindingOrder(cartesianInnerRing); if (innerWindingOrder == windingOrder) { ring.Reverse(); cartesianInnerRing.Reverse(); } cartesianInnerRings.Add(cartesianInnerRing); } EllipsoidTangentPlane tangentPlane = new EllipsoidTangentPlane(Ellipsoid.Wgs84, cartesianOuterRing); cartesianOuterRing = (List<Cartesian>)(tangentPlane.ComputePositionsOnPlane(cartesianOuterRing)); for (int i = 0; i < cartesianInnerRings.Count; i++) { cartesianInnerRings[i] = (List<Cartesian>)(tangentPlane.ComputePositionsOnPlane(cartesianInnerRings[i])); } int visibleVertexIndex = GetMutuallyVisibleVertexIndex(cartesianOuterRing, cartesianInnerRings); int innerRingIndex = GetRightmostRingIndex(cartesianInnerRings); int innerRingVertexIndex = GetRightmostVertexIndex(cartesianInnerRings[innerRingIndex]); List<Cartographic> innerRing = innerRings[innerRingIndex]; List<Cartographic> newPolygonVertices = new List<Cartographic>(); for (int i = 0; i < outerRing.Count; i++) { newPolygonVertices.Add(outerRing[i]); } List<Cartographic> holeVerticesToAdd = new List<Cartographic>(); // If the rightmost inner vertex is not the starting and ending point of the ring, // then some other point is duplicated in the inner ring and should be skipped once. if (innerRingVertexIndex != 0) { for (int j = 0; j <= innerRing.Count; j++) { int index = (j + innerRingVertexIndex) % innerRing.Count; if (index != 0) { holeVerticesToAdd.Add(innerRing[index]); } } } else { for (int j = 0; j < innerRing.Count; j++) { holeVerticesToAdd.Add(innerRing[(j + innerRingVertexIndex) % innerRing.Count]); } } int lastVisibleVertexIndex = newPolygonVertices.FindLastIndex(delegate(Cartographic point) { return point.Equals(outerRing[visibleVertexIndex]); }); holeVerticesToAdd.Add(outerRing[lastVisibleVertexIndex]); newPolygonVertices.InsertRange(lastVisibleVertexIndex + 1, holeVerticesToAdd); innerRings.RemoveAt(innerRingIndex); return newPolygonVertices; }