private IEnumerable <IRing> ReadSingleExteriorRingPolygon(
            [NotNull] BinaryReader reader, Ordinates ordinates, bool?reverseOrder = null)
        {
            if (reader == null)
            {
                throw new ArgumentNullException(nameof(reader));
            }

            int ringCount = checked ((int)reader.ReadUInt32());

            bool zAware = ordinates == Ordinates.Xyz || ordinates == Ordinates.Xyzm;
            bool mAware = ordinates == Ordinates.Xym || ordinates == Ordinates.Xyzm;

            // NOTE: Somtimes this takes ca. 250ms (may be when the license is checked?)!
            IRing ringTemplate = GeometryFactory.CreateEmptyRing(zAware, mAware);

            if (ringCount > 0)
            {
                bool reverse         = reverseOrder ?? !AssumeWkbPolygonsClockwise;
                var  geometryBuilder = new WksPointListBuilder(reverse);

                foreach (WKSPointZ[] wksPoints in ReadLinestringsCore(
                             reader, ordinates, ringCount, geometryBuilder))
                {
                    IRing resultRing = GeometryFactory.Clone(ringTemplate);

                    GeometryUtils.SetWKSPointZs(resultRing, wksPoints);

                    yield return(resultRing);
                }
            }
        }
        public static void AddRingGroup(IMultiPatch result,
                                        RingGroup ringGroup, bool simplify,
                                        bool setPointIds)
        {
            IRing ringTemplate = GeometryFactory.CreateEmptyRing(result);

            int?pointId = setPointIds ? ringGroup.Id : null;

            if (simplify)
            {
                IPolygon poly = CreatePolygon(result, ringTemplate, ringGroup);

                GeometryUtils.Simplify(poly);

                if (!poly.IsEmpty)
                {
                    AddToMultipatch(result, poly, false,
                                    pointId);

                    return;
                }
            }

            Linestring         exteriorRing  = ringGroup.ExteriorRing;
            IList <Linestring> interiorRings = ringGroup.InteriorRings.ToList();

            AddToMultipatch(result, ringTemplate, exteriorRing, interiorRings, false,
                            pointId);
        }
        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);
        }
        public static IPolygon CreatePolygon(IGeometry template,
                                             IEnumerable <Linestring> rings)
        {
            IPolygon poly         = GeometryFactory.CreateEmptyPolygon(template);
            IRing    ringTemplate = GeometryFactory.CreateEmptyRing(template);

            foreach (Linestring closedLinestring in rings)
            {
                Assert.True(closedLinestring.IsClosed, "Linestring is not closed.");

                IRing ring = CreateRing(closedLinestring, ringTemplate);

                ((IGeometryCollection)poly).AddGeometry(ring);
            }

            ((IGeometryCollection)poly).GeometriesChanged();

            return(poly);
        }
        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);
        }