private static List <IGeometry> TryCutArcObjects( [NotNull] IPolygon inputPolygon, [NotNull] IPolyline cutPolyline, ChangeAlongZSource zSource) { cutPolyline = ChangeAlongZUtils.PrepareCutPolylineZs(cutPolyline, zSource); var existingFeature = new List <IPolygon>(); var newFeatures = new List <IPolygon>(); foreach (IPolygon connectedComponent in GeometryUtils.GetConnectedComponents( inputPolygon)) { Plane3D plane = null; if (zSource == ChangeAlongZSource.SourcePlane) { double zTolerance = GeometryUtils.GetZTolerance(inputPolygon); plane = ChangeAlongZUtils.GetSourcePlane( GeometryConversionUtils.GetPntList(connectedComponent), zTolerance); } var cutComponents = TryCut(connectedComponent, cutPolyline); if (cutComponents == null) { existingFeature.Add(connectedComponent); } else { var largest = GeometryUtils.GetLargestGeometry(cutComponents); foreach (IPolygon cutComponent in cutComponents.Cast <IPolygon>()) { if (plane != null) { ChangeAlongZUtils.AssignZ((IPointCollection)cutComponent, plane); } else if (zSource == ChangeAlongZSource.InterpolatedSource && GeometryUtils.IsZAware(cutComponent)) { ((IZ)cutComponent).CalculateNonSimpleZs(); } if (cutComponent == largest) { existingFeature.Add(cutComponent); } else { newFeatures.Add(cutComponent); } } } } if (newFeatures.Count == 0) { return(null); } var result = new List <IGeometry> { GeometryUtils.Union(existingFeature), }; result.AddRange(newFeatures.Cast <IGeometry>()); return(result); }
public void CanCutAlongUsingZSources() { GetOverlappingPolygons(out GdbFeature sourceFeature, out GdbFeature targetFeature); GeometryUtils.MakeZAware(sourceFeature.Shape); GeometryUtils.MakeZAware(targetFeature.Shape); var normal = new Vector(new[] { 0.5, 0.5, 2 }); Pnt3D planePoint = new Pnt3D(2600000, 1200000, 600); Plane3D sourcePlane = new Plane3D(normal, planePoint); ChangeAlongZUtils.AssignZ((IPointCollection)sourceFeature.Shape, sourcePlane); GeometryUtils.ApplyConstantZ(targetFeature.Shape, 500); CalculateCutLinesRequest calculationRequest = CreateCalculateCutLinesRequest(sourceFeature, targetFeature); CalculateCutLinesResponse calculateResponse = ChangeAlongServiceUtils.CalculateCutLines(calculationRequest, null); Assert.AreEqual(ReshapeAlongCurveUsability.CanReshape, (ReshapeAlongCurveUsability)calculateResponse.ReshapeLinesUsability); AssertReshapeLineCount(calculateResponse.CutLines, 1, 1); IPolyline reshapeLine = (IPolyline)ProtobufGeometryUtils.FromShapeMsg(calculateResponse.CutLines[0].Path); Assert.NotNull(reshapeLine); Assert.AreEqual(1000, (reshapeLine).Length); Linestring cutLinestring = GeometryConversionUtils.GetLinestring(GeometryUtils.GetPaths(reshapeLine).Single()); Pnt3D midPoint = (Pnt3D)cutLinestring.GetPointAlong(0.5, true); List <Pnt3D> points = GeometryConversionUtils.GetPntList(reshapeLine); Assert.IsTrue(points.All(p => MathUtils.AreEqual(p.Z, 500.0))); // // Cutting - TargetZ // var applyRequest = new ApplyCutLinesRequest(); applyRequest.CutLines.Add(calculateResponse.CutLines[0]); applyRequest.CalculationRequest = calculationRequest; applyRequest.InsertVerticesInTarget = false; applyRequest.ChangedVerticesZSource = (int)ChangeAlongZSource.Target; ApplyCutLinesResponse applyResponse = ChangeAlongServiceUtils.ApplyCutLines(applyRequest, null); Assert.AreEqual(2, applyResponse.ResultFeatures.Count); List <IGeometry> cutGeometries = applyResponse.ResultFeatures.Select(GetShape).ToList(); Assert.AreEqual(1000 * 1000, cutGeometries.Sum(g => ((IArea)g).Area)); List <MultiPolycurve> multiPolycurves = cutGeometries .Select(g => GeometryConversionUtils.CreateMultiPolycurve((IPolycurve)g)) .ToList(); foreach (MultiPolycurve multiPolycurve in multiPolycurves) { Line3D segment = multiPolycurve.FindSegments(midPoint, 0.001).First().Value; Assert.AreEqual(500, segment.StartPoint.Z); Assert.AreEqual(500, segment.EndPoint.Z); } // // Cutting - Interpolate // applyRequest = new ApplyCutLinesRequest(); applyRequest.CutLines.Add(calculateResponse.CutLines[0]); applyRequest.CalculationRequest = calculationRequest; applyRequest.InsertVerticesInTarget = false; applyRequest.ChangedVerticesZSource = (int)ChangeAlongZSource.InterpolatedSource; applyResponse = ChangeAlongServiceUtils.ApplyCutLines(applyRequest, null); Assert.AreEqual(2, applyResponse.ResultFeatures.Count); cutGeometries = applyResponse.ResultFeatures.Select(GetShape).ToList(); Assert.AreEqual(1000 * 1000, cutGeometries.Sum(g => ((IArea)g).Area)); multiPolycurves = cutGeometries .Select(g => GeometryConversionUtils.CreateMultiPolycurve((IPolycurve)g)) .ToList(); foreach (MultiPolycurve multiPolycurve in multiPolycurves) { List <Line3D> segments = multiPolycurve.FindSegments(midPoint, 0.001) .Select(kvp => kvp.Value).ToList(); Assert.AreEqual(2, segments.Count); // Check if they are properly ordered and same length Assert.AreEqual(segments[0].EndPoint, segments[1].StartPoint); Assert.AreEqual(segments[0].Length2D, segments[1].Length2D); // Check if they are interpolated double average = (segments[0].StartPoint.Z + segments[1].EndPoint.Z) / 2; Assert.AreEqual(average, segments[0].EndPoint.Z); } // // Cutting - Plane // applyRequest = new ApplyCutLinesRequest(); applyRequest.CutLines.Add(calculateResponse.CutLines[0]); applyRequest.CalculationRequest = calculationRequest; applyRequest.InsertVerticesInTarget = false; applyRequest.ChangedVerticesZSource = (int)ChangeAlongZSource.SourcePlane; applyResponse = ChangeAlongServiceUtils.ApplyCutLines(applyRequest, null); Assert.AreEqual(2, applyResponse.ResultFeatures.Count); cutGeometries = applyResponse.ResultFeatures.Select(GetShape).ToList(); Assert.AreEqual(1000 * 1000, cutGeometries.Sum(g => ((IArea)g).Area)); multiPolycurves = cutGeometries .Select(g => GeometryConversionUtils.CreateMultiPolycurve((IPolycurve)g)) .ToList(); foreach (MultiPolycurve multiPolycurve in multiPolycurves) { bool?coplanar = ChangeAlongZUtils.AreCoplanar( multiPolycurve.GetPoints().ToList(), sourcePlane, 0.01, out double _, out string _); Assert.IsTrue(coplanar); } }
private IList <IGeometry> RemoveOverlap( [NotNull] IPolycurve fromGeometry, [NotNull] IPolycurve overlaps, ChangeAlongZSource zSource, out IList <IGeometry> overlappingResults) { Assert.ArgumentNotNull(fromGeometry, nameof(fromGeometry)); Assert.ArgumentNotNull(overlaps, nameof(overlaps)); overlaps = ChangeAlongZUtils.PrepareCutPolylineZs(overlaps, zSource); Plane3D plane = null; if (zSource == ChangeAlongZSource.SourcePlane) { plane = ChangeAlongZUtils.GetSourcePlane( GeometryConversionUtils.GetPntList(fromGeometry), GeometryUtils.GetZTolerance(fromGeometry)); } IGeometry rawResult = GetDifference(fromGeometry, overlaps); if (plane != null) { ChangeAlongZUtils.AssignZ((IPointCollection)rawResult, plane); } int originalPartCount = GetRelevantPartCount(fromGeometry); int resultPartCount = GetRelevantPartCount(rawResult); // TODO: This works for simple cases. To be correct the difference operation and part comparison would have to be // done on a per-part basis, because in the same operation one part could be added and one removed. // Just comparing part counts before and after is misleading in such cases. if (resultPartCount > originalPartCount) { Result.ResultHasMultiparts = true; } IList <IGeometry> result = new List <IGeometry>(); // TODO explode only those input parts that where cut into more than one result part // --> preserve other input parts in original geometry if (rawResult is IPolycurve && _explodeMultipartResult && IsMultipart(rawResult)) { // Exploding all selected multipart geos // to explode geos only if not avoidable, // use GetPositivePartCount and compare counts before and after cut operation foreach (IGeometry geometry in GeometryUtils.Explode(rawResult)) { var part = (IPolycurve)geometry; result.Add(part); } if (((IGeometryCollection)fromGeometry).GeometryCount > 1) { // TODO: Fix this situation by checking which individual parts were split by the overlap and only turn them into a new feature _msg.Warn( "The selection included multi-part geometry. Storing this geometry generated several copies of the feature."); } } else { result.Add(rawResult); } overlappingResults = _storeOverlapsAsNewFeatures ? CalculateOverlappingGeometries(fromGeometry, overlaps) : null; return(result); }