private void CutFeature3D(IFeature feature, IMultiPatch cutSurfaces) { IGeometry selectedGeometry = feature.Shape; if (GeometryUtils.Disjoint(cutSurfaces, selectedGeometry)) { return; } if (GeometryUtils.AreEqual(cutSurfaces, selectedGeometry)) { return; } if (FeatureToCutPredicate != null && !FeatureToCutPredicate(selectedGeometry, cutSurfaces)) { return; } // TODO: Multipatches should be cut if its footprint can be cut. However, if multiple ring groups exist, // that are not connected (touch along a line) in 3D, the rings should be grouped into connected parts. List <CutPolyline> cutPolylines = IntersectionUtils.GetIntersectionLines3D((IMultiPatch)selectedGeometry, cutSurfaces).ToList(); foreach (CutPolyline cutPoline in cutPolylines) { cutPoline.ObjectId = feature.OID; // Add the calculated lines for reference and traceability, filtering and subsequent cutting // with Success field equals null ProcessedCutLines?.Add(cutPoline); } if (cutPolylines.Count > 0) { var success = false; // TODO: Consider filter option for cut lines or even a clever path selection logic to avoid junctions: // Only use cut lines that are in the plane to connect disjoint cut line paths that are positive or negative // Consider adding an option to delete the negative or the positive side of the rings. var cutLineToUse = (IPolyline)GeometryUtils.Union( cutPolylines.Select(c => c.Polyline).ToList()); GeometryUtils.Simplify(cutLineToUse, true, false); if (!cutLineToUse.IsEmpty) { try { success = CutFeature(feature, cutLineToUse, ChangeAlongZSource.SourcePlane); } catch (Exception e) { _msg.WarnFormat("Cutting multipatch feature {0} failed.", GdbObjectUtils.ToString(feature)); _msg.Debug(e); } var appliedCutline = new CutPolyline(cutLineToUse); appliedCutline.SuccessfulCut = success; ProcessedCutLines?.Add(appliedCutline); } } }