Пример #1
0
        private static FeatureCutter CreateFeatureCutter([NotNull] ApplyCutLinesRequest request,
                                                         out IList <IFeature> targetFeatures)
        {
            GetFeatures(request.CalculationRequest.SourceFeatures,
                        request.CalculationRequest.TargetFeatures,
                        request.CalculationRequest.ClassDefinitions,
                        out IList <IFeature> sourceFeatures, out targetFeatures);

            ChangeAlongZSource zSource = (ChangeAlongZSource)request.ChangedVerticesZSource;

            DatasetSpecificSettingProvider <ChangeAlongZSource> zSourceProvider =
                new DatasetSpecificSettingProvider <ChangeAlongZSource>(
                    "Z values for changed vertices", zSource);

            var cutter = new FeatureCutter(sourceFeatures)
            {
                ZSourceProvider = zSourceProvider
            };

            if (request.InsertVerticesInTarget)
            {
                cutter.TargetFeatures = targetFeatures;
            }

            return(cutter);
        }
Пример #2
0
        private static IList <IGeometry> TryCutRingGroups(
            IPolygon inputPolygon,
            IPolyline cutPolyline,
            ChangeAlongZSource zSource)
        {
            // TODO:
            // In order to avoid the arbitrary grouping of multipart polygons, try to apply left/right logic
            // provided by GeomTopoOpUtils

            var existingFeature = new List <IPolygon>();
            var newFeatures     = new List <IPolygon>();

            var cutResultsPerConnectedComponent =
                TryCutConnectedComponents(inputPolygon, cutPolyline, zSource);

            foreach (IList <RingGroup> cutRingGroups in cutResultsPerConnectedComponent)
            {
                IRing ringTemplate = GeometryFactory.CreateEmptyRing(inputPolygon);

                var cutResults =
                    cutRingGroups.Select(
                        rg =>
                        GeometryConversionUtils.CreatePolygon(
                            inputPolygon, ringTemplate, rg))
                    .ToList();

                var largest = GeometryUtils.GetLargestGeometry(cutResults);

                foreach (IPolygon cutComponent in cutResults)
                {
                    if (cutComponent == largest)
                    {
                        existingFeature.Add(cutComponent);
                    }
                    else
                    {
                        newFeatures.Add(cutComponent);
                    }
                }
            }

            if (newFeatures.Count == 0)
            {
                // no cut happened:
                return(null);
            }

            var result = new List <IGeometry>
            {
                GeometryUtils.Union(existingFeature)
            };

            result.AddRange(newFeatures.Cast <IGeometry>());

            return(result);
        }
Пример #3
0
        private static IList <RingGroup> CutRingGroupPlanar(
            [NotNull] RingGroup ringGroup,
            [NotNull] IPolyline cutLine,
            double tolerance,
            ChangeAlongZSource zSource,
            double zTolerance)
        {
            cutLine = GeometryFactory.Clone(cutLine);

            if (GeometryUtils.IsZAware(cutLine) &&
                zSource != ChangeAlongZSource.Target)
            {
                ((IZAware)cutLine).DropZs();
            }

            Plane3D plane = null;

            if (zSource == ChangeAlongZSource.SourcePlane)
            {
                plane = ChangeAlongZUtils.GetSourcePlane(
                    ringGroup.ExteriorRing.GetPoints().ToList(), zTolerance);
            }

            GeometryUtils.Simplify(cutLine, true, true);

            MultiPolycurve cutLinestrings = new MultiPolycurve(
                GeometryUtils.GetPaths(cutLine).Select(
                    cutPath => GeometryConversionUtils.CreateLinestring(cutPath)));

            IList <RingGroup> resultGroups =
                GeomTopoOpUtils.CutPlanar(ringGroup, cutLinestrings, tolerance);

            foreach (RingGroup resultPoly in resultGroups)
            {
                resultPoly.Id = ringGroup.Id;

                if (plane != null)
                {
                    resultPoly.AssignUndefinedZs(plane);
                }
                else
                {
                    resultPoly.InterpolateUndefinedZs();
                }
            }

            Marshal.ReleaseComObject(cutLine);

            if (resultGroups.Count == 0)
            {
                // Return uncut original
                resultGroups.Add(ringGroup);
            }

            return(resultGroups);
        }
Пример #4
0
        public void CannotCutMultipartPolygonWithCutLineWithinTolerance()
        {
            ISpatialReference lv95 = SpatialReferenceUtils.CreateSpatialReference(
                WellKnownHorizontalCS.LV95);

            IPolygon originalPoly = GeometryFactory.CreatePolygon(
                GeometryFactory.CreateEnvelope(2600000, 1200000, 500, 100, 100, lv95));

            IPolygon innerRingPoly = GeometryFactory.CreatePolygon(
                GeometryFactory.CreateEnvelope(2600000, 1200000, 500, 10, 10, lv95));

            IPolygon secondPart = GeometryFactory.CreatePolygon(
                GeometryFactory.CreateEnvelope(2700000, 1200000, 500, 100, 100, lv95));

            ((IGeometryCollection)originalPoly).AddGeometryCollection(
                (IGeometryCollection)innerRingPoly);

            ((IGeometryCollection)originalPoly).AddGeometryCollection(
                (IGeometryCollection)secondPart);

            GeometryUtils.Simplify(originalPoly);

            // The cut line runs along the second ring (and diverts off to the outside)
            IPolyline cutLine = GeometryFactory.CreateLine(
                GeometryFactory.CreatePoint(2700000 + 50, 1200000 - 30),
                GeometryFactory.CreatePoint(2700000 + 50, 1200000),
                GeometryFactory.CreatePoint(2700000 + 130, 1200000 + 50));

            cutLine.SpatialReference = lv95;

            bool customIntersectOrig = IntersectionUtils.UseCustomIntersect;

            try
            {
                IntersectionUtils.UseCustomIntersect = false;

                const ChangeAlongZSource zSource = ChangeAlongZSource.InterpolatedSource;

                var resultsAo =
                    CutGeometryUtils.TryCut(originalPoly, cutLine, zSource);

                IntersectionUtils.UseCustomIntersect = true;
                var resultsGeom =
                    CutGeometryUtils.TryCut(originalPoly, cutLine, zSource);

                Assert.Null(resultsAo);
                Assert.Null(resultsGeom);
            }
            finally
            {
                IntersectionUtils.UseCustomIntersect = customIntersectOrig;
            }
        }
Пример #5
0
        private ChangeAlongZSource DetermineZSource(IFeature feature)
        {
            string             note    = null;
            ChangeAlongZSource zSource = ZSourceProvider?.GetValue(feature, out note) ??
                                         ChangeAlongZSource.Target;

            if (note != null)
            {
                _msg.Info(note);
            }

            return(zSource);
        }
Пример #6
0
        public static string GetDisplayText(ChangeAlongZSource zSource)
        {
            switch (zSource)
            {
            case ChangeAlongZSource.Target: return("Target");

            case ChangeAlongZSource.InterpolatedSource: return("Interpolated source");

            case ChangeAlongZSource.SourcePlane: return("Source plane");

            default:
                throw new ArgumentOutOfRangeException(
                          $"Unknown ChangeAlongZSource: {zSource}");
            }
        }
Пример #7
0
        private void ProcessFeature([NotNull] IFeature feature,
                                    [NotNull] IPolycurve overlappingGeometry)
        {
            IGeometry featureShape = feature.Shape;

            if (GeometryUtils.Disjoint(featureShape, overlappingGeometry))
            {
                return;
            }

            IList <IGeometry> overlappingResults;

            string             note    = null;
            ChangeAlongZSource zSource = ZSourceProvider?.GetValue(feature, out note) ??
                                         ChangeAlongZSource.Target;

            if (note != null)
            {
                _msg.Info(note);
            }

            var sourceMultipatch = featureShape as IMultiPatch;

            IList <IGeometry> modifiedGeometries =
                sourceMultipatch != null
                                        ? RemoveOverlaps(sourceMultipatch, (IPolygon)overlappingGeometry,
                                                         zSource, out overlappingResults)
                                        : RemoveOverlap((IPolycurve)featureShape, overlappingGeometry,
                                                        zSource, out overlappingResults);

            // additional check for undefined z values - this happens if the target has no Zs or UseSourceZs is active
            // -> currently the undefined Zs are interpolated before storing
            if (HasAnyGeometryUndefinedZs(modifiedGeometries))
            {
                _msg.DebugFormat(
                    "The result geometry of {0} has undefined z values.",
                    GdbObjectUtils.ToString(feature));
            }

            OverlapResultGeometries singleFeatureResult =
                new OverlapResultGeometries(feature, modifiedGeometries,
                                            overlappingResults);

            Result.ResultsByFeature.Add(singleFeatureResult);
        }
Пример #8
0
        public static T PrepareCutPolylineZs <T>([NotNull] T cutPolycurve,
                                                 ChangeAlongZSource zSource)
            where T : IPolycurve
        {
            // Copy from CutGeometryUtils
            if (zSource == ChangeAlongZSource.Target ||
                !GeometryUtils.IsZAware(cutPolycurve))
            {
                return(cutPolycurve);
            }

            T result = GeometryFactory.Clone(cutPolycurve);

            // Do not make z-unaware to avoid the Z values to be restored in SegmentReplacementUtils.EnsureZs()
            ((IZAware)result).DropZs();

            return(result);
        }
Пример #9
0
        private static void CutAndAssignToFootprintParts(
            [NotNull] GeometryPart multipatchPart,
            [NotNull] IPolyline cutLine,
            [NotNull] IDictionary <RingGroup, List <RingGroup> > splitPartsByFootprintPart,
            ChangeAlongZSource zSource)
        {
            double tolerance  = GeometryUtils.GetXyTolerance(multipatchPart.FirstGeometry);
            double zTolerance = GeometryUtils.GetZTolerance(multipatchPart.FirstGeometry);

            RingGroup ringGroup = GeometryConversionUtils.CreateRingGroup(multipatchPart);

            int pointId;

            if (GeometryUtils.HasUniqueVertexId(
                    Assert.NotNull(multipatchPart.MainOuterRing), out pointId))
            {
                ringGroup.Id = pointId;
            }

            bool inverted = ringGroup.ClockwiseOriented == false;

            if (inverted)
            {
                ringGroup.ReverseOrientation();
            }

            IList <RingGroup> cutRingGroups =
                CutRingGroupPlanar(ringGroup, cutLine, tolerance, zSource, zTolerance);

            AssignResultsToFootprintParts(cutRingGroups, splitPartsByFootprintPart,
                                          tolerance);

            if (inverted)
            {
                foreach (RingGroup cutRingGroup in cutRingGroups)
                {
                    cutRingGroup.ReverseOrientation();
                }
            }
        }
Пример #10
0
        public static IList <IGeometry> TryCut([NotNull] IPolygon inputPolygon,
                                               [NotNull] IPolyline cutPolyline,
                                               ChangeAlongZSource zSource)
        {
            IList <IGeometry> result;

            double originalArea = ((IArea)inputPolygon).Area;

            if (IntersectionUtils.UseCustomIntersect &&
                !GeometryUtils.HasNonLinearSegments(inputPolygon) &&
                !GeometryUtils.HasNonLinearSegments(cutPolyline) &&
                !GeometryUtils.IsMAware(inputPolygon))
            {
                result = TryCutXY(inputPolygon, cutPolyline, zSource);
            }
            else
            {
                result = TryCutArcObjects(inputPolygon, cutPolyline, zSource);
            }

            if (result != null)
            {
                double newArea   = result.Sum(geometry => ((IArea)geometry).Area);
                double tolerance = originalArea * 0.001;
                if (!MathUtils.AreEqual(newArea, originalArea, tolerance))
                {
                    _msg.DebugFormat("Input Polygon:{0}{1}", Environment.NewLine,
                                     GeometryUtils.ToXmlString(inputPolygon));
                    _msg.DebugFormat("Cut polyline:{0}{1}", Environment.NewLine,
                                     GeometryUtils.ToXmlString(cutPolyline));

                    throw new AssertionException(
                              "The cut operation has significantly changed the polygon area! Please report this polygon and the cut line.");
                }
            }

            return(result);
        }
Пример #11
0
        private static IList <IList <RingGroup> > TryCutConnectedComponents(
            IPolygon inputPolygon,
            IPolyline cutPolyline,
            ChangeAlongZSource zSource)
        {
            double tolerance  = GeometryUtils.GetXyTolerance(inputPolygon);
            double zTolerance = GeometryUtils.GetZTolerance(inputPolygon);

            var result = new List <IList <RingGroup> >();

            foreach (IPolygon connectedComponent in GeometryUtils.GetConnectedComponents(
                         inputPolygon))
            {
                RingGroup ringGroup =
                    GeometryConversionUtils.CreateRingGroup(connectedComponent);

                IList <RingGroup> cutRingGroups = CutRingGroupPlanar(
                    ringGroup, cutPolyline, tolerance, zSource, zTolerance);

                result.Add(cutRingGroups);
            }

            return(result);
        }
Пример #12
0
        public void CanCutPolygonWithZSourcePlane()
        {
            ISpatialReference lv95 = SpatialReferenceUtils.CreateSpatialReference(
                WellKnownHorizontalCS.LV95);

            IPolygon originalPoly = GeometryFactory.CreatePolygon(
                GeometryFactory.CreateEnvelope(2600000, 1200000, 500, 100, 100, lv95));

            IPolygon innerRingPoly = GeometryFactory.CreatePolygon(
                GeometryFactory.CreateEnvelope(2600000, 1200000, 500, 10, 10, lv95));

            Plane3D plane = Plane3D.FitPlane(new List <Pnt3D>
            {
                new Pnt3D(2600000, 1200000, 500),
                new Pnt3D(2600100, 1200100, 580),
                new Pnt3D(2600000, 1200100, 550)
            });

            ((IGeometryCollection)originalPoly).AddGeometryCollection(
                (IGeometryCollection)innerRingPoly);

            GeometryUtils.Simplify(originalPoly);

            ChangeAlongZUtils.AssignZ((IPointCollection)originalPoly, plane);

            // The non-z-aware cut line cuts north of the inner ring -> the inner ring should be assigned to the southern result
            IPolyline cutLine = GeometryFactory.CreateLine(
                GeometryFactory.CreatePoint(2600000 - 100, 1200020),
                GeometryFactory.CreatePoint(2600000 - 40, 1200020),
                GeometryFactory.CreatePoint(2600000 - 40, 1200040),
                GeometryFactory.CreatePoint(2600000 + 40, 1200040),
                GeometryFactory.CreatePoint(2600000 + 40, 1200020),
                GeometryFactory.CreatePoint(2600000 + 100, 1200020));

            cutLine.SpatialReference = lv95;

            bool customIntersectOrig = IntersectionUtils.UseCustomIntersect;

            try
            {
                IntersectionUtils.UseCustomIntersect = false;

                const ChangeAlongZSource zSource = ChangeAlongZSource.SourcePlane;
                var resultsAo =
                    CutGeometryUtils.TryCut(originalPoly, cutLine, zSource);

                IntersectionUtils.UseCustomIntersect = true;
                var resultsGeom =
                    CutGeometryUtils.TryCut(originalPoly, cutLine, zSource);

                Assert.NotNull(resultsAo);
                Assert.NotNull(resultsGeom);

                EnsureCutResult(resultsAo, originalPoly, plane, 3);
                EnsureCutResult(resultsGeom, originalPoly, plane, 3);

                // NOTE: The results have different start/end points, therefore GeometryUtils.AreEqual is false
                Assert.True(GeometryUtils.AreEqualInXY(resultsAo[0], resultsGeom[0]));
                Assert.True(GeometryUtils.AreEqualInXY(resultsAo[1], resultsGeom[1]));

                Assert.AreEqual(0,
                                IntersectionUtils.GetZOnlyDifferenceLines(
                                    (IPolycurve)resultsAo[0],
                                    (IPolycurve)resultsGeom[0], 0.001)
                                .Length);

                Assert.AreEqual(0,
                                IntersectionUtils.GetZOnlyDifferenceLines(
                                    (IPolycurve)resultsAo[1],
                                    (IPolycurve)resultsGeom[1], 0.001)
                                .Length);
            }
            finally
            {
                IntersectionUtils.UseCustomIntersect = customIntersectOrig;
            }
        }
Пример #13
0
        private static IList <IGeometry> TryCutXY(
            IPolygon inputPolygon,
            IPolyline cutPolyline,
            ChangeAlongZSource zSource)
        {
            // TODO:
            // In order to avoid the arbitrary grouping of multipart polygons, try to apply left/right logic
            // provided by GeomTopoOpUtils

            double tolerance  = GeometryUtils.GetXyTolerance(inputPolygon);
            double zTolerance = GeometryUtils.GetZTolerance(inputPolygon);

            MultiPolycurve inputMultipoly =
                GeometryConversionUtils.CreateMultiPolycurve(inputPolygon);

            var cutLine = GeometryFactory.Clone(cutPolyline);

            if (GeometryUtils.IsZAware(cutLine) &&
                zSource != ChangeAlongZSource.Target)
            {
                ((IZAware)cutLine).DropZs();
            }

            Plane3D plane = null;

            if (zSource == ChangeAlongZSource.SourcePlane)
            {
                plane = ChangeAlongZUtils.GetSourcePlane(
                    inputMultipoly.GetPoints().ToList(), zTolerance);
            }

            GeometryUtils.Simplify(cutLine, true, true);

            MultiPolycurve cutLinestrings = GeometryConversionUtils.CreateMultiPolycurve(cutLine);

            bool isMultipart = GeometryUtils.GetExteriorRingCount(inputPolygon) > 1;

            IList <MultiLinestring> resultGeoms =
                GeomTopoOpUtils.CutXY(inputMultipoly, cutLinestrings, tolerance, !isMultipart);

            var result = new List <IGeometry>();

            foreach (MultiLinestring resultPoly in resultGeoms)
            {
                if (plane != null)
                {
                    resultPoly.AssignUndefinedZs(plane);
                }
                else
                {
                    resultPoly.InterpolateUndefinedZs();
                }

                result.Add(GeometryConversionUtils.CreatePolygon(inputPolygon,
                                                                 resultPoly.GetLinestrings()));
            }

            Marshal.ReleaseComObject(cutLine);

            return(result.Count == 0 ? null : result);
        }
Пример #14
0
        /// <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);
        }
Пример #15
0
        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);
        }
Пример #16
0
        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);
        }
Пример #17
0
        private IList <IGeometry> RemoveOverlaps(
            [NotNull] IMultiPatch sourceMultipatch,
            [NotNull] IPolygon overlaps,
            ChangeAlongZSource zSource,
            out IList <IGeometry> overlappingMultiPatches)
        {
            // NOTE:
            // Difference / Intersect are useless for multipatches, they can only return polygons

            // -> Get the relevant boundary segments of the overlap and use the FeatureCutter to cut the multipatch.
            // Then select the correct (non-intersecting part)
            IPolyline interiorIntersection = GetCutLine(sourceMultipatch, overlaps);

            Assert.False(interiorIntersection.IsEmpty, "Cut line is empty.");

            IDictionary <IPolygon, IMultiPatch> cutResultByFootprintPart =
                CutGeometryUtils.TryCut(sourceMultipatch,
                                        interiorIntersection, zSource);

            IList <IGeometry> result = new List <IGeometry>(cutResultByFootprintPart.Count);

            overlappingMultiPatches = _storeOverlapsAsNewFeatures
                                                          ? new List <IGeometry>(
                cutResultByFootprintPart.Count)
                                                          : null;

            // now select the multipatch of the right side...
            foreach (KeyValuePair <IPolygon, IMultiPatch> footprintWithMultipatch in
                     cutResultByFootprintPart)
            {
                IMultiPatch resultMultipatch = footprintWithMultipatch.Value;

                if (!GeometryUtils.InteriorIntersects(footprintWithMultipatch.Key,
                                                      overlaps))
                {
                    result.Add(resultMultipatch);
                }
                else
                {
                    overlappingMultiPatches?.Add(resultMultipatch);
                }
            }

            if (!_explodeMultipartResult)
            {
                // merge the different parts into one:
                if (result.Count > 1)
                {
                    result = new List <IGeometry> {
                        GeometryUtils.Union(result)
                    };
                }

                if (overlappingMultiPatches?.Count > 1)
                {
                    overlappingMultiPatches =
                        new List <IGeometry>
                    {
                        GeometryUtils.Union(overlappingMultiPatches)
                    };
                }
            }

            return(result);
        }