Exemple #1
0
        private static void AssignInteriorRings([NotNull] IEnumerable <Linestring> interiorRings,
                                                [NotNull] IList <RingGroup> leftPolys,
                                                [NotNull] IList <RingGroup> rightPolys,
                                                [NotNull] IList <RingGroup> bothSidePolys,
                                                [NotNull] MultiLinestring unCutParts,
                                                double tolerance)
        {
            foreach (Linestring unCutIsland in interiorRings)
            {
                // Assuming no conflicts (island within island) between un-cut islands because
                // they all come from the same source.
                int assignmentCount = 0;
                assignmentCount +=
                    AssignInteriorRing(unCutIsland, rightPolys, tolerance);

                assignmentCount +=
                    AssignInteriorRing(unCutIsland, leftPolys, tolerance);

                assignmentCount +=
                    AssignInteriorRing(unCutIsland, bothSidePolys, tolerance);

                if (assignmentCount == 0)
                {
                    unCutParts.AddLinestring(unCutIsland);
                }

                Assert.True(assignmentCount < 2, "Multiple inner ring assignments!");
            }
        }
        public MultipleRingNavigator([NotNull] MultiLinestring sourceRings,
                                     [NotNull] MultiLinestring targets,
                                     double tolerance,
                                     bool allowTargetTargetIntersections = false)
            : base(sourceRings, targets, tolerance)
        {
            Assert.ArgumentCondition(sourceRings.IsClosed, "Source rings must be closed.");

            // TODO: Implement target-self-intersecting navigation (vertical, spaghetti, multipatch rings,
            // and especially simplified self-intersecting lines)
            // TODO: Implement Reshape and avoid phantom points
            _allowTargetTargetIntersections = allowTargetTargetIntersections;
        }
Exemple #3
0
        private static void AssignInteriorRings([NotNull] IEnumerable <Linestring> interiorRings,
                                                [NotNull] ICollection <RingGroup> polygons,
                                                [NotNull] MultiLinestring unassignedParts,
                                                double tolerance)
        {
            foreach (Linestring interiorRing in interiorRings)
            {
                // Assuming no conflicts (island within island) between un-cut islands because
                // they all come from the same source.
                int assignmentCount =
                    AssignInteriorRing(interiorRing, polygons, tolerance);

                if (assignmentCount == 0)
                {
                    unassignedParts.AddLinestring(interiorRing);
                }

                Assert.True(assignmentCount < 2, "Multiple inner ring assignments!");
            }
        }
Exemple #4
0
        private static int GetContainingRingIndex([NotNull] MultiLinestring polygon,
                                                  [NotNull] Linestring containedRing,
                                                  double tolerance,
                                                  out bool ringsAreEqual,
                                                  out IntersectionPoint3D touchPoint)
        {
            IList <IntersectionPoint3D> intersectionPoints =
                GeomTopoOpUtils.GetIntersectionPoints(polygon, containedRing, tolerance);

            ringsAreEqual = false;
            touchPoint    = null;

            // Equal to outer ring -> removes outer ring in original
            // or equal to inner ring -> ignore cookie cutter
            if (intersectionPoints.Count == 2 &&
                intersectionPoints[0].SourcePartIndex == intersectionPoints[1].SourcePartIndex &&
                intersectionPoints[0].Point.Equals(intersectionPoints[1].Point) &&
                intersectionPoints[0].Type == IntersectionPointType.LinearIntersectionStart &&
                intersectionPoints[1].Type == IntersectionPointType.LinearIntersectionEnd)
            {
                ringsAreEqual = true;
                return(intersectionPoints[0].SourcePartIndex);
            }

            var outerRingIntersections =
                intersectionPoints
                .Where(i => polygon.GetLinestring(i.SourcePartIndex).ClockwiseOriented == true)
                .ToList();

            // Touching outer ring in one point -> boundary loop in original
            if (outerRingIntersections.Count > 0)
            {
                Assert.True(outerRingIntersections.Count < 2,
                            "Unexpected number of touching points.");

                touchPoint = outerRingIntersections[0];

                return(touchPoint.SourcePartIndex);
            }

            // Inside an inner ring -> ignore cookie cutter
            for (int i = 0; i < polygon.PartCount; i++)
            {
                Linestring ring = polygon.GetLinestring(i);

                if (ring.ClockwiseOriented == true)
                {
                    continue;
                }

                int currentIdx = i;

                bool?areaContainsXY = GeomRelationUtils.AreaContainsXY(
                    ring, containedRing,
                    intersectionPoints.Where(ip => ip.SourcePartIndex == currentIdx),
                    tolerance, true);

                if (areaContainsXY == true)
                {
                    return(i);
                }
            }

            // Inside an outer ring but not an inner ring: Add as island
            for (int i = 0; i < polygon.PartCount; i++)
            {
                Linestring ring = polygon.GetLinestring(i);

                if (ring.ClockwiseOriented == false)
                {
                    continue;
                }

                if (GeomRelationUtils.AreaContainsXY(ring, containedRing.StartPoint,
                                                     tolerance) == true)
                {
                    return(i);
                }
            }

            return(-1);
        }
Exemple #5
0
        /// <summary>
        /// Cuts the source ring using the target and returns separate lists
        /// of result rings on the left/right side of the cut line.
        /// </summary>
        /// <param name="leftPolys">Result polygons on the left side of the cut line.</param>
        /// <param name="rightPolys">Result polygons on the right side of the cut line.</param>
        /// <param name="clipPolys"></param>
        /// <param name="undefinedSidePolys"></param>
        /// <param name="unCutParts"></param>
        /// <returns>Whether the cut operation was successful or not.</returns>
        public bool CutXY([NotNull] out IList <RingGroup> leftPolys,
                          [NotNull] out IList <RingGroup> rightPolys,
                          [NotNull] out IList <RingGroup> clipPolys,
                          [NotNull] out IList <MultiLinestring> undefinedSidePolys,
                          [NotNull] out MultiLinestring unCutParts)
        {
            Assert.ArgumentCondition(_subcurveNavigator.Source.IsClosed, "source must be closed.");

            // Based on Weiler–Atherton clipping algorithm, added specific logic for
            // linear intersections, un-closed target lines and multi-parts.
            // Potential enhancements: Do not insert phantom points!

            IList <Linestring> rightRings = GetRightSideRings();
            IList <Linestring> leftRings  = GetLeftSideRings();

            IList <Linestring> duplicates = new List <Linestring>();

            if (!_subcurveNavigator.Target.IsClosed &&
                _subcurveNavigator.AreIntersectionPointsNonSequential())
            {
                // Cut backs result in duplicates which are both on the left and the right!
                duplicates = RemoveDuplicateRings(leftRings, rightRings);
            }

            // Assign the cut inner rings (anti-clockwise) to un-cut outer rings...
            var unCutOuterRings = _subcurveNavigator.GetNonIntersectedSourceRings()
                                  .Where(r => r.ClockwiseOriented != false)
                                  .ToList();

            rightPolys = AssignToResultRingGroups(rightRings, unCutOuterRings);
            leftPolys  = AssignToResultRingGroups(leftRings, unCutOuterRings);

            IList <RingGroup> bothSidePolys = AssignToResultRingGroups(duplicates, unCutOuterRings);

            unCutParts =
                unCutOuterRings.Count == 1
                                        ? (MultiLinestring) new RingGroup(unCutOuterRings[0])
                                        : new MultiPolycurve(unCutOuterRings);

            // Assign the remaining interior rings;
            AssignInteriorRings(rightRings, leftPolys, rightPolys, bothSidePolys, unCutParts,
                                _subcurveNavigator.Tolerance);
            AssignInteriorRings(leftRings, leftPolys, rightPolys, bothSidePolys, unCutParts,
                                _subcurveNavigator.Tolerance);
            AssignInteriorRings(duplicates, leftPolys, rightPolys, bothSidePolys, unCutParts,
                                _subcurveNavigator.Tolerance);

            // Assign the inner rings from the original
            var unCutIslands = _subcurveNavigator.GetNonIntersectedSourceRings()
                               .Where(r => r.ClockwiseOriented == false);

            AssignInteriorRings(unCutIslands, leftPolys, rightPolys, bothSidePolys, unCutParts,
                                _subcurveNavigator.Tolerance);

            // Assign closed cut lines completely contained by an outer ring (and not by an inner ring)
            var unusedCutRings =
                _subcurveNavigator.GetNonIntersectedTargets().Where(t => t.IsClosed);

            undefinedSidePolys = bothSidePolys.Cast <MultiLinestring>().ToList();

            clipPolys = new List <RingGroup>();
            foreach (Linestring unusedCutRing in unusedCutRings)
            {
                MultiLinestring updatedUnCut;
                RingGroup       cookie;
                if (!unCutParts.IsEmpty &&
                    TryCutCookie(unusedCutRing, unCutParts, out updatedUnCut, out cookie))
                {
                    unCutParts = MultiPolycurve.CreateEmpty();
                    undefinedSidePolys.Add(updatedUnCut);
                    clipPolys.Add(cookie);
                    continue;
                }

                RingGroup updatedCut;
                if (TryCutCookie(unusedCutRing, leftPolys, out updatedCut, out cookie))
                {
                    clipPolys.Add(cookie);
                    continue;
                }

                if (TryCutCookie(unusedCutRing, rightPolys, out updatedCut, out cookie))
                {
                    clipPolys.Add(cookie);
                    continue;
                }

                if (TryCutCookie(unusedCutRing, bothSidePolys, out updatedCut, out cookie))
                {
                    clipPolys.Add(cookie);
                }
            }

            return((rightPolys.Count > 0 && leftPolys.Count > 0) ||
                   undefinedSidePolys.Count > 1 || clipPolys.Count > 0);
        }