Ejemplo n.º 1
0
        /// <summary>
        /// Returns the points from the target that deviate from the source, i.e. that are on neither of the sourceLines.
        /// </summary>
        /// <param name="targetSegments"></param>
        /// <param name="sourceLine1"></param>
        /// <param name="sourceLine2"></param>
        /// <param name="xyTolerance"></param>
        /// <param name="before"></param>
        /// <param name="after"></param>
        private void GetNonIntersectingTargetPoints(ISegmentList targetSegments,
                                                    Line3D sourceLine1,
                                                    Line3D sourceLine2,
                                                    double xyTolerance,
                                                    [CanBeNull] out Pnt3D before,
                                                    [CanBeNull] out Pnt3D after)
        {
            Line3D thisTargetSegment = targetSegments[TargetIndex];

            before = null;
            after  = null;
            double?targetStartIntersectionFactor = GetTargetStartIntersectionFactor();
            double?targetEndIntersectionFactor   = GetTargetEndIntersectionFactor();

            if (targetStartIntersectionFactor == null &&
                targetEndIntersectionFactor == null)
            {
                // The target interior intersects the source start
                before = thisTargetSegment.StartPoint;
                after  = thisTargetSegment.EndPoint;
            }
            else if (targetStartIntersectionFactor != null)
            {
                Line3D previousTargetSegment = targetSegments.PreviousSegment(TargetIndex);

                if (previousTargetSegment != null)
                {
                    before = previousTargetSegment.StartPoint;
                    after  = thisTargetSegment.EndPoint;
                }
            }
            else             // targetEndIntersectionFactor != null
            {
                Line3D nextTargetSegment = targetSegments.NextSegment(TargetIndex);

                if (nextTargetSegment != null)
                {
                    before = thisTargetSegment.StartPoint;
                    after  = nextTargetSegment.EndPoint;
                }
            }

            if (before != null)
            {
                if (sourceLine1.IntersectsPointXY(before, xyTolerance) ||
                    sourceLine2.IntersectsPointXY(before, xyTolerance))
                {
                    before = null;
                }
            }

            if (after != null)
            {
                if (sourceLine1.IntersectsPointXY(after, xyTolerance) ||
                    sourceLine2.IntersectsPointXY(after, xyTolerance))
                {
                    after = null;
                }
            }
        }
Ejemplo n.º 2
0
        private static void ClassifyIntersection([NotNull] ISegmentList source,
                                                 [NotNull] ISegmentList target,
                                                 [NotNull] IntersectionPoint3D intersectionPoint,
                                                 out bool isInbound,
                                                 out bool isOutbound)
        {
            Assert.False(intersectionPoint.Type == IntersectionPointType.Unknown,
                         "Cannot classify unknown intersection type.");

            if (intersectionPoint.Type ==
                IntersectionPointType.LinearIntersectionIntermediate)
            {
                isInbound  = false;
                isOutbound = false;
                return;
            }

            int?previousTargetSegment =
                intersectionPoint.GetNonIntersectingTargetSegmentIndex(target, false);
            int?nextTargetSegment =
                intersectionPoint.GetNonIntersectingTargetSegmentIndex(target, true);

            Pnt3D previousPntAlongTarget = previousTargetSegment == null
                                                               ? null
                                                               : target[previousTargetSegment.Value].StartPoint;

            Pnt3D nextPntAlongTarget = nextTargetSegment == null
                                                           ? null
                                                           : target[nextTargetSegment.Value].EndPoint;

            isInbound = nextPntAlongTarget != null &&
                        intersectionPoint.IsOnTheRightSide(source, nextPntAlongTarget, true);
            isOutbound = previousPntAlongTarget != null &&
                         intersectionPoint.IsOnTheRightSide(source, previousPntAlongTarget, true);
        }
Ejemplo n.º 3
0
        protected void ClassifyIntersections(
            [NotNull] ISegmentList source,
            [NotNull] ISegmentList target,
            [NotNull] out IList <IntersectionPoint3D> intersectionsInboundTarget,
            [NotNull] out IList <IntersectionPoint3D> intersectionsOutboundTarget)
        {
            intersectionsInboundTarget  = new List <IntersectionPoint3D>();
            intersectionsOutboundTarget = new List <IntersectionPoint3D>();

            foreach (IntersectionPoint3D intersectionPoint3D in IntersectionsAlongSource)
            {
                bool isInbound, isOutbound;
                ClassifyIntersection(source, target, intersectionPoint3D, out isInbound,
                                     out isOutbound);

                // In-bound takes precedence because if the target is both inbound and outbound (i.e. touching from inside)
                // the resulting part is on the left of the cut line which is consistent with other in-bound intersections.
                if (isInbound)
                {
                    intersectionsInboundTarget.Add(intersectionPoint3D);
                }
                else if (isOutbound)
                {
                    intersectionsOutboundTarget.Add(intersectionPoint3D);
                }
            }

            if (!target.IsClosed)
            {
                // Remove dangles that cannot cut and would lead to duplicate result rings
                RemoveDeadEndIntersections(intersectionsInboundTarget, intersectionsOutboundTarget);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Determines whether the specified closed polycurve contains (including the boundary) the
        /// specified test geometry. This method ignores the orientation.
        /// </summary>
        /// <param name="closedPolycurve"></param>
        /// <param name="targetSegments"></param>
        /// <param name="tolerance"></param>
        /// <param name="knownIntersections"></param>
        /// <returns></returns>
        public static bool PolycurveContainsXY(
            [NotNull] ISegmentList closedPolycurve,
            [NotNull] Linestring targetSegments,
            double tolerance,
            IEnumerable <SegmentIntersection> knownIntersections = null)
        {
            if (AreBoundsDisjoint(closedPolycurve, targetSegments, tolerance))
            {
                return(false);
            }

            if (knownIntersections == null)
            {
                knownIntersections =
                    SegmentIntersectionUtils.GetSegmentIntersectionsXY(
                        closedPolycurve, targetSegments, tolerance);
            }

            // TODO: GeomUtils.IEnumerable<IntersectionPoint3D> GetIntersectionPointsWithDeviation() for better performance
            var intersectionPoints =
                GeomTopoOpUtils.GetIntersectionPoints(closedPolycurve, targetSegments, tolerance,
                                                      knownIntersections, false);

            Pnt3D nonIntersectingTargetPnt =
                GetNonIntersectingTargetPoint(targetSegments, intersectionPoints);

            IEnumerable <Pnt3D> checkPoints = nonIntersectingTargetPnt != null
                                                                 ? new[] { nonIntersectingTargetPnt }
                                                                 : targetSegments.GetPoints();

            return(checkPoints.All(p => PolycurveContainsXY(closedPolycurve, p, tolerance)));

            // The check points are assumed not to be on the boundary!
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Gets the segment intersections between the specified path and multiline-string.
        /// </summary>
        /// <param name="segmentList1"></param>
        /// <param name="segmentList2"></param>
        /// <param name="tolerance"></param>
        /// <param name="optimizeLinearIntersections">If true, an optimiziation that improves the
        /// performance when linear intersections are present. If a segmentList1 segment is equal
        /// to a linestring2 segment it will directly be used. Other intersections will be missed.
        /// </param>
        /// <returns>The segment intersections with the index of the cut part of multiLinestring2</returns>
        public static IEnumerable <SegmentIntersection> GetSegmentIntersectionsXY(
            [NotNull] ISegmentList segmentList1,
            [NotNull] ISegmentList segmentList2,
            double tolerance,
            bool optimizeLinearIntersections = false)
        {
            if (GeomRelationUtils.AreBoundsDisjoint(segmentList1, segmentList2, tolerance))
            {
                yield break;
            }

            SegmentIntersection previousLinearIntersection = null;

            for (var lineIdx = 0; lineIdx < segmentList1.SegmentCount; lineIdx++)
            {
                Line3D line = segmentList1.GetSegment(lineIdx);

                foreach (SegmentIntersection result in GetSegmentIntersectionsXY(
                             lineIdx, line, segmentList2, tolerance,
                             previousLinearIntersection))
                {
                    if (optimizeLinearIntersections && result.SegmentsAreEqualInXy)
                    {
                        previousLinearIntersection = result;
                    }

                    yield return(result);
                }
            }
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Creates the IntersectionPoint3D of type <see cref="IntersectionPointType.LinearIntersectionEnd"/>
        /// that corresponds to the second intersection along the source segment.
        /// </summary>
        /// <param name="intersection">The intersection</param>
        /// <param name="sourceSegments"></param>
        /// <param name="targetSegments"></param>
        /// <returns></returns>
        public static IntersectionPoint3D GetLinearIntersectionEnd(
            [NotNull] SegmentIntersection intersection,
            [NotNull] ISegmentList sourceSegments,
            [NotNull] ISegmentList targetSegments)
        {
            Line3D sourceSegment = sourceSegments[intersection.SourceIndex];

            double endFactor;
            Pnt3D  toPoint =
                intersection.GetLinearIntersectionEnd(sourceSegment, out endFactor);

            int sourcePartIdx;
            int sourceSegmentIndex = sourceSegments.GetLocalSegmentIndex(
                intersection.SourceIndex, out sourcePartIdx);

            IntersectionPoint3D result =
                new IntersectionPoint3D(
                    toPoint, sourceSegmentIndex + endFactor, intersection)
            {
                Type            = IntersectionPointType.LinearIntersectionEnd,
                SourcePartIndex = sourcePartIdx
            };

            int targetPartIdx;

            result.VirtualTargetVertex = CalculateVirtualTargetVertex(
                targetSegments, result.Type, intersection, out targetPartIdx);

            result.TargetPartIndex = targetPartIdx;

            return(result);
        }
Ejemplo n.º 7
0
        private static bool IsTargetRingNullPoint(
            [NotNull] SegmentIntersection thisLinearIntersection,
            [CanBeNull] SegmentIntersection previousLinearIntersection,
            ISegmentList targetSegments)
        {
            if (previousLinearIntersection == null)
            {
                return(false);
            }

            if (thisLinearIntersection.TargetStartIntersects &&
                targetSegments.IsFirstSegmentInPart(thisLinearIntersection.TargetIndex) &&
                targetSegments.IsLastSegmentInPart(previousLinearIntersection.TargetIndex) &&
                targetSegments.IsClosed)
            {
                return(true);
            }

            // The linear intersections can be inverted, i.e. travelling backwards along target:
            if (thisLinearIntersection.TargetStartIntersects &&             // TargetEndIntersects??
                targetSegments.IsLastSegmentInPart(thisLinearIntersection.TargetIndex) &&
                targetSegments.IsFirstSegmentInPart(previousLinearIntersection.TargetIndex) &&
                targetSegments.IsClosed)
            {
                return(true);
            }

            return(false);
        }
Ejemplo n.º 8
0
        private static IEnumerable <SegmentIntersection> GetSegmentIntersectionsXY(
            int sourceLineIdx,
            [NotNull] Line3D sourceLine,
            [NotNull] ISegmentList segmentList,
            double tolerance,
            [CanBeNull] SegmentIntersection previousLinearIntersection)
        {
            if (previousLinearIntersection != null)
            {
                // speculation: this segment also runs along the next / previous target
                SegmentIntersection continuousIntersection =
                    TryGetContinuousLinearIntersection(
                        sourceLineIdx, sourceLine, segmentList, previousLinearIntersection,
                        tolerance);

                if (continuousIntersection != null)
                {
                    yield return(continuousIntersection);

                    yield break;
                }
            }

            IEnumerable <KeyValuePair <int, Line3D> > segmentsByIndex =
                segmentList.FindSegments(sourceLine, tolerance);

            foreach (SegmentIntersection intersection in
                     IntersectLineWithLinestringXY(
                         sourceLine, sourceLineIdx, segmentsByIndex, tolerance))
            {
                yield return(intersection);
            }
        }
Ejemplo n.º 9
0
        private bool TargetCrossesBetweenSourceSegments([CanBeNull] Line3D sourceLine1,
                                                        [CanBeNull] Line3D sourceLine2,
                                                        [NotNull] ISegmentList targetSegments,
                                                        double tolerance,
                                                        out bool?targetDeviatesToLeft)
        {
            targetDeviatesToLeft = null;

            if (sourceLine1 == null || sourceLine2 == null)
            {
                return(false);
            }

            Pnt3D targetBefore;
            Pnt3D targetAfter;

            GetNonIntersectingTargetPoints(targetSegments, sourceLine1, sourceLine2,
                                           tolerance,
                                           out targetBefore, out targetAfter);

            if (targetBefore == null && targetAfter == null)
            {
                return(false);
            }

            bool isRightTurn = sourceLine1.IsLeftXY(sourceLine2.EndPoint) < 0;

            if (targetBefore != null && targetAfter != null)
            {
                bool beforeIsRight = IsRightOfVertex(isRightTurn, sourceLine1,
                                                     sourceLine2,
                                                     targetBefore);
                bool afterIsRight =
                    IsRightOfVertex(isRightTurn, sourceLine1, sourceLine2, targetAfter);

                if (beforeIsRight != afterIsRight)
                {
                    return(true);
                }

                targetDeviatesToLeft = !beforeIsRight;
            }
            else
            {
                if (targetBefore != null)
                {
                    targetDeviatesToLeft =
                        !IsRightOfVertex(isRightTurn, sourceLine1, sourceLine2,
                                         targetBefore);
                }
                else
                {
                    targetDeviatesToLeft =
                        !IsRightOfVertex(isRightTurn, sourceLine1, sourceLine2,
                                         targetAfter);
                }
            }

            return(false);
        }
Ejemplo n.º 10
0
 protected SubcurveNavigator(ISegmentList source,
                             ISegmentList target,
                             double tolerance)
 {
     Source    = source;
     Target    = target;
     Tolerance = tolerance;
 }
Ejemplo n.º 11
0
        private static IEnumerable <SegmentIntersection> FilterIntersections(
            [NotNull] IEnumerable <SegmentIntersection> intersectionsForSourceSegment,
            [NotNull] ISegmentList source,
            [NotNull] IDictionary <int, HashSet <double> > usedIntersectionFactorsByPart)
        {
            foreach (SegmentIntersection intersection in intersectionsForSourceSegment)
            {
                var filter = false;

                if (!intersection.HasLinearIntersection &&
                    intersection.SingleInteriorIntersectionFactor == null)
                {
                    double intersectionFactor;
                    if (intersection.SourceStartIntersects)
                    {
                        intersectionFactor = 0;
                    }
                    else if (intersection.SourceEndIntersects)
                    {
                        intersectionFactor = 1;
                    }
                    else if (intersection.TargetStartIntersects)
                    {
                        intersectionFactor =
                            Assert.NotNull(intersection.TargetStartFactor).Value;
                    }
                    else
                    {
                        intersectionFactor =
                            Assert.NotNull(intersection.TargetEndFactor).Value;
                    }

                    int partIndex;
                    int localSegmentIndex =
                        source.GetLocalSegmentIndex(intersection.SourceIndex, out partIndex);

                    double intersectionFactorPartGlobal = localSegmentIndex + intersectionFactor;

                    // TODO: Extract class IntersectionFactors which encapsulates all the
                    // Contains, Add etc. methods, probably even the filtering
                    if (ContainsIntersection(usedIntersectionFactorsByPart, partIndex,
                                             intersectionFactorPartGlobal))
                    {
                        filter = true;
                    }
                    else
                    {
                        AddIntersectionFactor(intersectionFactorPartGlobal, partIndex,
                                              usedIntersectionFactorsByPart, source);
                    }
                }

                if (!filter)
                {
                    yield return(intersection);
                }
            }
        }
Ejemplo n.º 12
0
        private static void CollectIntersection(
            [NotNull] SegmentIntersection intersection,
            [NotNull] ISegmentList source,
            [NotNull] IDictionary <int, HashSet <double> > allLinearIntersectionFactors,
            [NotNull] ICollection <SegmentIntersection> intersectionsForCurrentSourceSegment)
        {
            // Collect segments for current index in list, unless they are clearly not needed
            // (and would need to be filtered by a later linear intersection if added)

            bool isLinear = intersection.HasLinearIntersection;

            if (isLinear)
            {
                int partIndex;
                int localSegmentIndex =
                    source.GetLocalSegmentIndex(intersection.SourceIndex, out partIndex);

                double linearIntersectionStartFactor =
                    localSegmentIndex +
                    intersection.GetLinearIntersectionStartFactor(true);

                double linearIntersectionEndFactor =
                    localSegmentIndex +
                    intersection.GetLinearIntersectionEndFactor(true);

                if (intersection.IsSourceZeroLength2D &&
                    ContainsIntersection(allLinearIntersectionFactors,
                                         partIndex, linearIntersectionEndFactor))
                {
                    // avoid double linear segments if the source segment is vertical
                    return;
                }

                AddIntersectionFactor(linearIntersectionStartFactor, partIndex,
                                      allLinearIntersectionFactors, source);

                AddIntersectionFactor(linearIntersectionEndFactor, partIndex,
                                      allLinearIntersectionFactors, source);
            }

            if (!isLinear && intersection.SourceStartIntersects &&
                source.IsFirstSegmentInPart(intersection.SourceIndex) && source.IsClosed)
            {
                // will be reported again at the end
                return;
            }

            if (!isLinear && intersection.SourceEndIntersects &&
                !source.IsLastSegmentInPart(intersection.SourceIndex))
            {
                // will be reported again at next segment
                return;
            }

            intersectionsForCurrentSourceSegment.Add(intersection);
        }
Ejemplo n.º 13
0
        public Line3D TryGetIntersectionLine([NotNull] ISegmentList source)
        {
            if (!HasLinearIntersection)
            {
                return(null);
            }

            Line3D sourceSegment = source[SourceIndex];

            return(TryGetIntersectionLine(sourceSegment));
        }
Ejemplo n.º 14
0
        public bool IsOnTheRightSide([NotNull] ISegmentList source,
                                     [NotNull] Pnt3D testPoint,
                                     bool disregardOrientation = false)
        {
            Assert.True(source.IsClosed, "Source must be closed ring(s)");

            Linestring sourceRing = source.GetPart(SourcePartIndex);

            double sourceRatio;
            int    sourceSegmentIdx =
                GetLocalSourceIntersectionSegmentIdx(sourceRing, out sourceRatio);

            Line3D sourceSegment = sourceRing[sourceSegmentIdx];

            if (sourceRatio > 0 && sourceRatio < 1)
            {
                // The intersection is on the source segment's interior
                return(sourceSegment.IsLeftXY(testPoint) < 0);
            }

            Line3D previousSegment, nextSegment;

            // Intersection at source vertex 0 or 1 -> get the 2 adjacent segments
            // ReSharper disable once CompareOfFloatsByEqualityOperator
            if (sourceRatio == 0)
            {
                previousSegment =
                    sourceRing.PreviousSegmentInRing(sourceSegmentIdx, true);

                nextSegment = SegmentIntersection.IsSourceZeroLength2D
                                                      ? sourceRing.NextSegmentInRing(sourceSegmentIdx, true)
                                                      : sourceSegment;
            }
            else             // sourceRatio == 1
            {
                previousSegment = SegmentIntersection.IsSourceZeroLength2D
                                                          ? sourceRing.PreviousSegmentInRing(
                    sourceSegmentIdx, true)
                                                          : sourceSegment;
                nextSegment = sourceRing.NextSegmentInRing(sourceSegmentIdx, true);
            }

            bool result = GeomTopoOpUtils.IsOnTheRightSide(previousSegment.StartPoint, Point,
                                                           nextSegment.EndPoint, testPoint);

            if (!disregardOrientation && sourceRing.ClockwiseOriented == false)
            {
                result = !result;
            }

            return(result);
        }
Ejemplo n.º 15
0
        private static IEnumerable <Linestring> GetUnused(ISegmentList linestrings,
                                                          HashSet <int> usedIndexes)
        {
            for (int i = 0; i < linestrings.PartCount; i++)
            {
                if (usedIndexes.Contains(i))
                {
                    continue;
                }

                Linestring cutLine = linestrings.GetPart(i);

                yield return(cutLine);
            }
        }
Ejemplo n.º 16
0
        public static bool LinesContainXY([NotNull] ISegmentList segments,
                                          [NotNull] Pnt3D testPoint,
                                          double tolerance)
        {
            foreach (KeyValuePair <int, Line3D> segmentsAroundPoint in
                     segments.FindSegments(testPoint, tolerance))
            {
                Line3D segment = segmentsAroundPoint.Value;

                if (segment.IntersectsPointXY(testPoint, tolerance))
                {
                    return(true);
                }
            }

            return(false);
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Determines whether the test point is completely contained (true) or
        /// on the boundary of the specified rings (e.e. intersecting the boundary).
        /// </summary>
        /// <param name="closedRings">The containing rings.</param>
        /// <param name="testPoint"></param>
        /// <param name="tolerance"></param>
        /// <returns>Null, if the point is on the boundary, true if the point is inside the ring.</returns>
        public static bool?AreaContainsXY([NotNull] ISegmentList closedRings,
                                          [NotNull] Pnt3D testPoint,
                                          double tolerance)
        {
            Assert.ArgumentCondition(closedRings.IsClosed, "Rings must be closed");

            if (AreBoundsDisjoint(closedRings, testPoint.X, testPoint.Y, tolerance))
            {
                return(false);
            }

            // Test boundary:
            if (LinesContainXY(closedRings, testPoint, tolerance))
            {
                return(null);
            }

            return(HasRayOddCrossingNumber(closedRings, testPoint, tolerance));
        }
Ejemplo n.º 18
0
        GetFilteredIntersectionsOrderedAlongSourceSegments(
            [NotNull] IEnumerable <SegmentIntersection> intersections,
            [NotNull] ISegmentList source)
        {
            var intersectionsForCurrentSourceSegment =
                new List <SegmentIntersection>(3);

            var allLinearIntersectionFactors = new Dictionary <int, HashSet <double> >();

            int currentIndex = -1;

            foreach (SegmentIntersection intersection in intersections)
            {
                if (intersection.SourceIndex != currentIndex)
                {
                    currentIndex = intersection.SourceIndex;

                    foreach (
                        SegmentIntersection collectedIntersection in
                        FilterIntersections(intersectionsForCurrentSourceSegment,
                                            source, allLinearIntersectionFactors)
                        .OrderBy(i => i.GetFirstIntersectionAlongSource()))
                    {
                        yield return(collectedIntersection);
                    }

                    intersectionsForCurrentSourceSegment.Clear();
                }

                CollectIntersection(intersection, source, allLinearIntersectionFactors,
                                    intersectionsForCurrentSourceSegment);
            }

            foreach (
                SegmentIntersection collectedIntersection in
                FilterIntersections(intersectionsForCurrentSourceSegment,
                                    source, allLinearIntersectionFactors)
                .OrderBy(i => i.GetFirstIntersectionAlongSource()))
            {
                yield return(collectedIntersection);
            }
        }
Ejemplo n.º 19
0
        private static void AddIntersectionFactor(
            double localIntersectionFactor,
            int partIndex,
            [NotNull] IDictionary <int, HashSet <double> > usedIntersectionFactorsByPart,
            [NotNull] ISegmentList source)
        {
            Linestring part = source.GetPart(partIndex);

            if (IsRingStartOrEnd(part, localIntersectionFactor))
            {
                // add both start and end point
                AddIntersectionFactor(0, partIndex, usedIntersectionFactorsByPart);
                AddIntersectionFactor(part.SegmentCount, partIndex, usedIntersectionFactorsByPart);
            }
            else
            {
                AddIntersectionFactor(localIntersectionFactor, partIndex,
                                      usedIntersectionFactorsByPart);
            }
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Determines whether the specified closed polycurve contains (including the boundary) the
        /// specified test point. This method ignores the orientation.
        /// </summary>
        /// <param name="closedPolycurve"></param>
        /// <param name="testPoint"></param>
        /// <param name="tolerance"></param>
        /// <returns></returns>
        public static bool PolycurveContainsXY([NotNull] ISegmentList closedPolycurve,
                                               [NotNull] Pnt3D testPoint,
                                               double tolerance)
        {
            if (AreBoundsDisjoint(closedPolycurve, testPoint.X, testPoint.Y, tolerance))
            {
                return(false);
            }

            // Test boundary:
            if (LinesContainXY(closedPolycurve, testPoint, tolerance))
            {
                return(true);
            }

            if (!closedPolycurve.IsClosed)
            {
                return(false);
            }

            return(HasRayOddCrossingNumber(closedPolycurve, testPoint, tolerance));
        }
Ejemplo n.º 21
0
        private static SegmentIntersection TryGetContinuousLinearIntersection(
            int lineIdx,
            [NotNull] Line3D line1,
            [NotNull] ISegmentList segmentList2,
            [CanBeNull] SegmentIntersection previous,
            double tolerance)
        {
            if (previous == null ||
                previous.SourceIndex + 1 != lineIdx)
            {
                // We jumped over some source segments
                return(null);
            }

            int?targetIdx = previous.LinearIntersectionInOppositeDirection
                                                 ? segmentList2.PreviousSegmentIndex(previous.TargetIndex)
                                                 : segmentList2.NextSegmentIndex(previous.TargetIndex);

            if (targetIdx == null)
            {
                return(null);
            }

            Line3D targetSegment =
                segmentList2.GetSegment(targetIdx.Value);

            if (targetSegment.EqualsXY(line1, tolerance))
            {
                SegmentIntersection resultIntersection =
                    SegmentIntersection.CreateCoincidenceIntersectionXY(
                        lineIdx, targetIdx.Value,
                        previous.LinearIntersectionInOppositeDirection);

                return(resultIntersection);
            }

            return(null);
        }
Ejemplo n.º 22
0
        /// <summary>
        /// Returns source rings disjoint from target and target rings disjoint from source.
        /// </summary>
        /// <param name="ringPredicate"></param>
        /// <returns></returns>
        private IEnumerable <Linestring> GetRingsDisjointFromOtherPoly(
            Predicate <Linestring> ringPredicate)
        {
            var result = new List <Linestring>();

            // W.r.t. AreaContainsXY returning null: if the start point is on the boundary there
            // are duplicate rings which need to be identified elsewhere.
            ISegmentList target = _subcurveNavigator.Target;

            foreach (Linestring ring in _subcurveNavigator.GetNonIntersectedSourceRings()
                     .Where(r => ringPredicate(r)))
            {
                bool?contains = GeomRelationUtils.AreaContainsXY(
                    target, ring.StartPoint, _subcurveNavigator.Tolerance);

                if (contains == false)
                {
                    // disjoint
                    result.Add(ring);
                }
            }

            ISegmentList source = _subcurveNavigator.Source;

            foreach (Linestring ring in _subcurveNavigator.GetNonIntersectedTargets()
                     .Where(r => ringPredicate(r)))
            {
                bool?contains = GeomRelationUtils.AreaContainsXY(
                    source, ring.StartPoint, _subcurveNavigator.Tolerance);

                if (contains == false)
                {
                    result.Add(ring);
                }
            }

            return(result);
        }
Ejemplo n.º 23
0
        /// <summary>
        /// Returns all self intersections except the intersection between consecutive segments.
        /// </summary>
        /// <param name="sourceLineGlobalIdx"></param>
        /// <param name="sourceLine"></param>
        /// <param name="containingSegmentList"></param>
        /// <param name="tolerance"></param>
        /// <returns></returns>
        public static IEnumerable <SegmentIntersection> GetRelevantSelfIntersectionsXY(
            int sourceLineGlobalIdx,
            [NotNull] Line3D sourceLine,
            [NotNull] ISegmentList containingSegmentList,
            double tolerance)
        {
            // a predicate, i.e. i != sourceGlobalIdx && i != sourceGlobalIdx - 1 && i != sourceGlobalIdx + 1
            Predicate <int> predicate = i => i != sourceLineGlobalIdx;

            IEnumerable <KeyValuePair <int, Line3D> > segmentsByGlobalIdx =
                containingSegmentList.FindSegments(sourceLine, tolerance, true,
                                                   predicate);

            foreach (SegmentIntersection intersection in
                     IntersectLineWithLinestringXY(
                         sourceLine, sourceLineGlobalIdx, segmentsByGlobalIdx, tolerance))
            {
                int?nextSegmentIndex =
                    containingSegmentList.NextSegmentIndex(intersection.SourceIndex);

                if (nextSegmentIndex == intersection.TargetIndex &&
                    !intersection.HasLinearIntersection)
                {
                    continue;
                }

                int?previousSegmentIndex =
                    containingSegmentList.PreviousSegmentIndex(intersection.SourceIndex);
                if (previousSegmentIndex == intersection.TargetIndex &&
                    !intersection.HasLinearIntersection)
                {
                    continue;
                }

                yield return(intersection);
            }
        }
Ejemplo n.º 24
0
        private static double CalculateVirtualTargetVertex(ISegmentList targetSegments,
                                                           IntersectionPointType intersectionType,
                                                           SegmentIntersection segmentIntersection,
                                                           out int targetPartIndex)
        {
            int targetSegmentIndex = targetSegments.GetLocalSegmentIndex(
                segmentIntersection.TargetIndex, out targetPartIndex);

            double result;

            switch (intersectionType)
            {
            case IntersectionPointType.LinearIntersectionStart:
                result = targetSegmentIndex +
                         segmentIntersection.GetRatioAlongTargetLinearStart();
                break;

            case IntersectionPointType.LinearIntersectionEnd:
            case IntersectionPointType.LinearIntersectionIntermediate:
                result = targetSegmentIndex +
                         segmentIntersection.GetRatioAlongTargetLinearEnd();
                break;

            case IntersectionPointType.Crossing:
            case IntersectionPointType.TouchingInPoint:
                result = targetSegmentIndex +
                         segmentIntersection.GetIntersectionPointFactorAlongTarget();
                break;

            default:
                throw new InvalidOperationException(
                          $"Unsupported type :{intersectionType}");
            }

            return(result);
        }
Ejemplo n.º 25
0
        /// <summary>
        /// Determines whether the horizontal ray from the test point to XMin crosses
        /// the specified segments an odd number of times.
        /// NOTE: For test points exactly on the boundary the result depends on whether
        /// the the point is on the right or the left boundary!
        /// </summary>
        /// <param name="segments"></param>
        /// <param name="testPoint"></param>
        /// <param name="tolerance"></param>
        /// <returns></returns>
        private static bool HasRayOddCrossingNumber([NotNull] ISegmentList segments,
                                                    [NotNull] IPnt testPoint,
                                                    double tolerance)
        {
            bool result = false;

            // Get the intersecting segments along the horizontal line from XMin to the testPoint
            IEnumerable <KeyValuePair <int, Line3D> > intersectingSegments =
                segments.FindSegments(segments.XMin, testPoint.Y, testPoint.X, testPoint.Y,
                                      tolerance);

            foreach (KeyValuePair <int, Line3D> path2Segment in intersectingSegments.OrderBy(
                         kvp => kvp.Key))
            {
                Line3D segment = path2Segment.Value;

                Pnt3D previous = segment.StartPoint;
                Pnt3D vertex   = segment.EndPoint;

                if (vertex.Y < testPoint.Y && previous.Y >= testPoint.Y ||               // downward crossing
                    previous.Y < testPoint.Y && vertex.Y >= testPoint.Y)                 // upward crossing
                {
                    double dX = previous.X - vertex.X;
                    double dY = previous.Y - vertex.Y;

                    double y = testPoint.Y - vertex.Y;

                    if (vertex.X + y * dX / dY < testPoint.X)
                    {
                        result = !result;
                    }
                }
            }

            return(result);
        }
Ejemplo n.º 26
0
        public int?GetNonIntersectingTargetSegmentIndex(
            [NotNull] ISegmentList target,
            bool forwardAlongTarget)
        {
            if (SegmentIntersection.HasLinearIntersection)
            {
                if (Type == IntersectionPointType.LinearIntersectionIntermediate)
                {
                    return(null);
                }

                // search the first non-intersecting point at the and of the linear intersection
                bool deviationIsBackward =
                    Type == IntersectionPointType.LinearIntersectionStart;

                if (SegmentIntersection.LinearIntersectionInOppositeDirection)
                {
                    deviationIsBackward = !deviationIsBackward;
                }

                if ((deviationIsBackward && forwardAlongTarget) ||
                    (!deviationIsBackward && !forwardAlongTarget))
                {
                    return(null);
                }

                // get the first non-intersecting point after the linear intersection, check its side:
                if (SegmentIntersection.TargetStartIntersects &&
                    SegmentIntersection.TargetEndIntersects)
                {
                    // Target is within source (or equal to source)
                    return(forwardAlongTarget
                                                       ? target.NextSegmentIndex(SegmentIntersection.TargetIndex)
                                                       : target.PreviousSegmentIndex(SegmentIntersection.TargetIndex));
                }

                if (!SegmentIntersection.TargetStartIntersects &&
                    !SegmentIntersection.TargetEndIntersects)
                {
                    // Source is completely within target
                    return(SegmentIntersection.TargetIndex);
                }

                // Either the source start or the source end intersects but not both
                // The same must be the case for the target
                Assert.True(
                    SegmentIntersection.TargetEndIntersects ^
                    SegmentIntersection.TargetStartIntersects,
                    "Either target start or end is expected to intersect");
            }

            if (SegmentIntersection.TargetStartIntersects)
            {
                return(forwardAlongTarget
                                               ? SegmentIntersection.TargetIndex
                                               : target.PreviousSegmentIndex(SegmentIntersection.TargetIndex));
            }

            if (SegmentIntersection.TargetEndIntersects)
            {
                return(forwardAlongTarget
                                               ? target.NextSegmentIndex(SegmentIntersection.TargetIndex)
                                               : SegmentIntersection.TargetIndex);
            }

            // By now all linear cases should have been handled
            Assert.False(SegmentIntersection.HasLinearIntersection,
                         "Not all linear cases were handled.");

            return(SegmentIntersection.TargetIndex);
        }
Ejemplo n.º 27
0
        /// <summary>
        /// Determines whether the two paths cross (i.e. the intersection is a point) in this intersection.
        /// </summary>
        /// <param name="sourceSegments"></param>
        /// <param name="targetSegments"></param>
        /// <param name="tolerance"></param>
        /// <param name="targetDeviatesToLeft">If there is no crossing: Whether the target segment deviates
        /// to the left of the source.</param>
        /// <returns></returns>
        public bool IsCrossingInPoint([NotNull] ISegmentList sourceSegments,
                                      [NotNull] ISegmentList targetSegments,
                                      double tolerance,
                                      out bool?targetDeviatesToLeft)
        {
            targetDeviatesToLeft = null;

            if (HasLinearIntersection)
            {
                return(false);
            }

            if (SingleInteriorIntersectionFactor != null)
            {
                // interior/interior
                targetDeviatesToLeft = true;

                return(true);
            }

            Line3D sourceLine = sourceSegments[SourceIndex];

            // Target start/end on source interior: check previous/next target segments
            if (TargetStartIsOnSourceInterior)
            {
                Line3D thisTargetSegment     = targetSegments[TargetIndex];
                Line3D previousTargetSegment = targetSegments.PreviousSegment(TargetIndex);

                if (previousTargetSegment == null)
                {
                    return(false);
                }

                if (ArePointsOnDifferentSide(sourceLine,
                                             previousTargetSegment.StartPoint,
                                             thisTargetSegment.EndPoint, tolerance,
                                             out targetDeviatesToLeft))
                {
                    return(true);
                }
            }

            if (TargetEndIsOnSourceInterior)
            {
                // check the sides of the target segment and the next target segment
                Line3D thisTargetSegment = targetSegments[TargetIndex];
                Line3D nextTargetSegment = targetSegments.NextSegment(TargetIndex);

                if (nextTargetSegment == null)
                {
                    return(false);
                }

                if (ArePointsOnDifferentSide(sourceLine, thisTargetSegment.StartPoint,
                                             nextTargetSegment.EndPoint, tolerance,
                                             out targetDeviatesToLeft))
                {
                    return(true);
                }
            }

            if (SourceStartIntersects)
            {
                Line3D previousSource =
                    sourceSegments.PreviousSegment(SourceIndex, true);

                return(TargetCrossesBetweenSourceSegments(previousSource, sourceLine,
                                                          targetSegments,
                                                          tolerance,
                                                          out targetDeviatesToLeft));
            }

            if (SourceEndIntersects)
            {
                Line3D nextSource =
                    sourceSegments.NextSegment(SourceIndex, true);

                return(TargetCrossesBetweenSourceSegments(sourceLine, nextSource,
                                                          targetSegments,
                                                          tolerance,
                                                          out targetDeviatesToLeft));
            }

            return(false);
        }
Ejemplo n.º 28
0
        public static IntersectionPoint3D CreateSingleIntersectionPoint(
            [NotNull] SegmentIntersection intersection,
            [NotNull] ISegmentList sourceSegments,
            [NotNull] ISegmentList targetSegments,
            double tolerance)
        {
            Line3D sourceSegment = sourceSegments.GetSegment(intersection.SourceIndex);
            double?targetIntersectionFactorOnSource =
                intersection.GetIntersectionPointFactorAlongSource();

            int sourcePartIdx;
            int sourceSegmentIndex = sourceSegments.GetLocalSegmentIndex(
                intersection.SourceIndex, out sourcePartIdx);

            Pnt3D  point;
            double sourceIndex;

            // ReSharper disable once CompareOfFloatsByEqualityOperator
            if (targetIntersectionFactorOnSource == 0)
            {
                point       = sourceSegment.StartPoint;
                sourceIndex = sourceSegmentIndex;
            }
            // ReSharper disable once CompareOfFloatsByEqualityOperator
            else if (targetIntersectionFactorOnSource == 1)
            {
                point       = sourceSegment.EndPoint;
                sourceIndex = sourceSegmentIndex + 1;
            }
            else
            {
                point = sourceSegment.GetPointAlong(
                    targetIntersectionFactorOnSource.Value, true);
                sourceIndex = sourceSegmentIndex +
                              targetIntersectionFactorOnSource.Value;
            }

            IntersectionPoint3D result = new IntersectionPoint3D(point, sourceIndex, intersection)
            {
                SourcePartIndex = sourcePartIdx
            };

            bool?targetDeviatesToLeft;

            result.Type = intersection.IsCrossingInPoint(
                sourceSegments, targetSegments, tolerance,
                out targetDeviatesToLeft)
                                              ? IntersectionPointType.Crossing
                                              : IntersectionPointType.TouchingInPoint;

            result.TargetDeviatesToLeftOfSource = targetDeviatesToLeft;

            int targetPartIdx;

            result.VirtualTargetVertex = CalculateVirtualTargetVertex(
                targetSegments, result.Type, intersection, out targetPartIdx);

            result.TargetPartIndex = targetPartIdx;

            return(result);
        }
Ejemplo n.º 29
0
        /// <summary>
        /// Collects the intersection points from the sorted and filtered intersections.
        /// </summary>
        /// <param name="sortedRelevantIntersections"></param>
        /// <param name="sourceSegments"></param>
        /// <param name="targetSegments"></param>
        /// <param name="tolerance"></param>
        /// <param name="includeLinearIntersectionIntermediatePoints">
        /// Includes all intermediate points along linear intersections.
        /// NOTE: They will not be ordered along the source segments when compared
        /// to other intersection point types.</param>
        /// <returns></returns>
        public static IList <IntersectionPoint3D> CollectIntersectionPoints(
            [NotNull] IEnumerable <SegmentIntersection> sortedRelevantIntersections,
            [NotNull] ISegmentList sourceSegments,
            [NotNull] ISegmentList targetSegments,
            double tolerance,
            bool includeLinearIntersectionIntermediatePoints = false)
        {
            var result = new List <IntersectionPoint3D>();

            IntersectionPoint3D startPoint = null;

            IntersectionPoint3D previousLinearEnd = null;

            foreach (SegmentIntersection intersection in sortedRelevantIntersections)
            {
                if (!intersection.HasLinearIntersection)
                {
                    // emit previous linear stretch (to maintain order along source)
                    TryAddLinearIntersectionStretch(startPoint, previousLinearEnd, result);
                    startPoint        = null;
                    previousLinearEnd = null;

                    result.Add(
                        IntersectionPoint3D.CreateSingleIntersectionPoint(
                            intersection, sourceSegments, targetSegments,
                            tolerance));
                    continue;
                }

                IntersectionPoint3D fromPoint =
                    IntersectionPoint3D.GetLinearIntersectionStart(
                        intersection, sourceSegments, targetSegments);

                IntersectionPoint3D toPoint =
                    IntersectionPoint3D.GetLinearIntersectionEnd(
                        intersection, sourceSegments, targetSegments);

                if (previousLinearEnd == null)
                {
                    startPoint = fromPoint;
                }

                // For symmetry reasons, also the target ring start/end should break linear intersections.
                // Otherwise the result is different in XY depending on the order of the arguments.
                bool isTargetRingNullPoint = IsTargetRingNullPoint(
                    fromPoint.SegmentIntersection,
                    previousLinearEnd?.SegmentIntersection,
                    targetSegments);

                if (previousLinearEnd == null ||
                    !isTargetRingNullPoint && previousLinearEnd.Point.Equals(fromPoint.Point))
                {
                    // first, or connected to previous -> continue:
                    if (previousLinearEnd != null &&
                        includeLinearIntersectionIntermediatePoints)
                    {
                        previousLinearEnd.Type =
                            IntersectionPointType.LinearIntersectionIntermediate;
                        result.Add(previousLinearEnd);
                    }

                    previousLinearEnd = toPoint;
                }
                else
                {
                    // emit
                    TryAddLinearIntersectionStretch(startPoint, previousLinearEnd, result);

                    // re-start with current from/to
                    startPoint        = fromPoint;              // isTargetRingNullPoint ? fromPoint : null;
                    previousLinearEnd = toPoint;                // isTargetRingNullPoint ? toPoint : null;
                }
            }

            TryAddLinearIntersectionStretch(startPoint, previousLinearEnd, result);

            return(result);
        }