private static int AssignInteriorRing([NotNull] Linestring interiorRing, IEnumerable <RingGroup> resultPolys, double tolerance) { int assignmentCount = 0; foreach (RingGroup resultPoly in resultPolys) { if (GeomRelationUtils.PolycurveContainsXY( resultPoly.ExteriorRing, interiorRing.StartPoint, tolerance)) { resultPoly.AddInteriorRing(interiorRing); assignmentCount++; } } return(assignmentCount); }
/// <summary> /// Creates the list of result ring groups from the processed inner/outer rings and the /// unprocessed outer rings by: /// - Adding processed outer rings to the output and remove them from the input collection /// - For each processed inner rings, that is contained in an un-processed outer ring: /// - Add the unprocessed outer ring together with the inner ring to the result. /// - Remove both the unprocessed outer and the inner ring from the respective input collection. /// </summary> /// <param name="processedResultRings"></param> /// <param name="unprocessedOuterRings"></param> /// <returns></returns> private IList <RingGroup> AssignToResultRingGroups( ICollection <Linestring> processedResultRings, ICollection <Linestring> unprocessedOuterRings) { var result = new List <RingGroup>(); foreach (Linestring processedResultRing in processedResultRings.ToList()) { if (processedResultRing.ClockwiseOriented != false) { result.Add(new RingGroup(processedResultRing)); processedResultRings.Remove(processedResultRing); } else { // Intersected (processed) inner rings: // Find the containing un-cut outer ring, assign and remove from un-processed list Linestring containing = unprocessedOuterRings.FirstOrDefault( o => o.ClockwiseOriented == true && GeomRelationUtils.PolycurveContainsXY( o, processedResultRing.StartPoint, _subcurveNavigator.Tolerance)); if (containing != null) { unprocessedOuterRings.Remove(containing); // Add at the beginning to boost performance, assuming a few (or one) large rings contains everything result.Insert(0, new RingGroup(containing, new[] { processedResultRing })); // remove from the list, the remaining inner rings will be assigned afterwards; processedResultRings.Remove(processedResultRing); } } } return(result); }
private static bool TryCutCookie <T>([NotNull] T polygon, [NotNull] Linestring cookieCutter, double tolerance, out RingGroup resultCookie, bool allowEmptyResults = false) where T : MultiLinestring { resultCookie = null; if (!GeomRelationUtils.PolycurveContainsXY( polygon, cookieCutter, tolerance)) { return(false); } // Remove pre-existing interior rings that are completely within cookie cutter List <Linestring> containedExistingIslands = RemoveContainedExistingIslands(polygon, cookieCutter, tolerance); Linestring interiorRing = cookieCutter.Clone(); Assert.True(interiorRing.IsClosed, "Interior ring is not closed"); interiorRing.TryOrientAnticlockwise(); IntersectionPoint3D outerRingIntersection; bool ringsAreEqual; int parentRingIdx = GetContainingRingIndex( polygon, interiorRing, tolerance, out ringsAreEqual, out outerRingIntersection); Assert.False(parentRingIdx < 0, "No parent ring found"); Linestring containingRing = polygon.GetLinestring(parentRingIdx); if (containingRing.ClockwiseOriented == false) { // The cutter is completely within an existing island -> ignore (keep existing ring) return(false); } if (ringsAreEqual) { // The cutter is equal to the found ring. Positive rings cancel each other out: if (!allowEmptyResults) { return(false); } polygon.RemoveLinestring(containingRing); } else if (outerRingIntersection == null) { // The cutter is completely within an existing outer ring -> add as island polygon.AddLinestring(interiorRing); } else { // create boundary loop: polygon.RemoveLinestring(containingRing); Linestring withBoundaryLoop = CreateWithBoundaryLoop(containingRing, interiorRing, outerRingIntersection, tolerance); polygon.InsertLinestring(parentRingIdx, withBoundaryLoop); } resultCookie = RingGroup.CreateProperlyOriented(cookieCutter.Clone()); foreach (Linestring unusedCutRing in containedExistingIslands) { RingGroup cookieInCookie; Assert.True(TryCutCookie(resultCookie, unusedCutRing, tolerance, out cookieInCookie), "Inner ring in cookie cutter cannot be cut from result cookie"); } return(true); }