private static Dictionary <IPolygon, IMultiPatch> BuildResultMultipatches( [NotNull] IMultiPatch prototype, [NotNull] IDictionary <RingGroup, List <RingGroup> > splitResultsByFootprintPart, DegenerateMultipatchFootprintAction nonSimpleBoundaryAction) { var result = new Dictionary <IPolygon, IMultiPatch>(); IRing emptyRing = GeometryFactory.CreateEmptyRing(prototype); foreach (var outerRingsByFootprintPart in splitResultsByFootprintPart) { RingGroup footprintPart = outerRingsByFootprintPart.Key; List <RingGroup> resultPolys = outerRingsByFootprintPart.Value; IMultiPatch resultMultipatch = GeometryFactory.CreateEmptyMultiPatch(prototype); foreach (RingGroup poly in resultPolys) { // TODO: Support vertical ring group with inner rings bool simplify = poly.InteriorRings.Any(); GeometryConversionUtils.AddRingGroup( resultMultipatch, poly, simplify, poly.Id != null); } if (resultPolys.Any(p => p.Id != null)) { GeometryUtils.MakePointIDAware(resultMultipatch); } // Guard against multipatches with wrong footprint. They are so broken (IRelationalOps are wrong) that // it's not worth using them any further... if (IsMultipatchWithDegenerateFootprint(resultMultipatch)) { switch (nonSimpleBoundaryAction) { case DegenerateMultipatchFootprintAction.Throw: throw new DegenerateResultGeometryException( "The multipatch cut operation resulted in a multipatch with degenerate footprint."); case DegenerateMultipatchFootprintAction.Discard: _msg.DebugFormat( "Discarding result multipatch with degenerate boundary: {0}", GeometryUtils.ToString(resultMultipatch)); continue; case DegenerateMultipatchFootprintAction.Keep: _msg.DebugFormat( "Detected result multipatch with degenerate boundary (it will be kept): {0}", GeometryUtils.ToString(resultMultipatch)); break; } } IPolygon footprintPoly = GeometryConversionUtils.CreatePolygon(emptyRing, emptyRing, footprintPart); result.Add(footprintPoly, resultMultipatch); } return(result); }
/// <summary> /// Cuts the provided multipatch along the specified cutLine. /// </summary> /// <param name="multipatch"></param> /// <param name="cutLine"></param> /// <param name="zSource">The source of the Z values to be used for the new vertices of the result features.</param> /// <param name="usedCutLine">The cut result containing information about the cut operation.</param> /// <param name="nonSimpleFootprintAction">The action to be performed if one of the result multipatches /// has a degenerate footprint (because it is a sliver polygon with sub-tolerance self intersections).</param> /// <returns></returns> public static IDictionary <IPolygon, IMultiPatch> TryCut( [NotNull] IMultiPatch multipatch, [NotNull] IPolyline cutLine, ChangeAlongZSource zSource, [CanBeNull] CutPolyline usedCutLine = null, DegenerateMultipatchFootprintAction nonSimpleFootprintAction = DegenerateMultipatchFootprintAction.Throw) { Assert.ArgumentNotNull(multipatch, nameof(multipatch)); Assert.ArgumentNotNull(cutLine, nameof(cutLine)); bool allRings = GeometryUtils.IsRingBasedMultipatch(multipatch); Assert.True(allRings, "The multipatch geometry contains triangles, triangle fans or triangle strips, which are currently not supported"); // NOTE: ITopologicalOperator4 is not supported by multipatch, ITopologicalOperator3.Cut returns non-Z-aware polygons // -> Use GeomUtils.Cut implementation which could eventually classify the left/right parts and avoid footprint-cutting // only to find the correct assignment to result features. // TODO: Create footprint as RingGroups directly from multipatch rings IPolygon footprint = GeometryFactory.CreatePolygon(multipatch); IList <IGeometry> cutFootprintParts = TryCutRingGroups(footprint, cutLine, ChangeAlongZSource.Target); if (cutFootprintParts == null || cutFootprintParts.Count == 0) { _msg.DebugFormat( "Not even the footprint could be cut. No multipatch cutting performed."); if (usedCutLine != null) { usedCutLine.Polyline = cutLine; usedCutLine.SuccessfulCut = false; } return(new Dictionary <IPolygon, IMultiPatch>(0)); } // Get the 'connected components', i.e. outer ring with respective inner rings. IList <GeometryPart> multipatchParts = GeometryPart.FromGeometry(multipatch).ToList(); Dictionary <RingGroup, List <RingGroup> > splitPartsByFootprintPart = PrepareSplitPartsDictionary(cutFootprintParts); foreach (GeometryPart part in multipatchParts) { CutAndAssignToFootprintParts(part, cutLine, splitPartsByFootprintPart, zSource); } // make a separate multipatch per footprint-part with all respective ring-groups Dictionary <IPolygon, IMultiPatch> result = BuildResultMultipatches( multipatch, splitPartsByFootprintPart, nonSimpleFootprintAction); if (usedCutLine != null && splitPartsByFootprintPart.Values.Count > 1) { // TODO: Extract actual cutLine from inBound/outBound intersections usedCutLine.Polyline = cutLine; usedCutLine.SuccessfulCut = false; } return(result); }