Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
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);
        }