コード例 #1
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);
                }
            }
        }
コード例 #2
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);
        }
コード例 #3
0
        private static IEnumerable <SegmentIntersection> IntersectLineWithLinestringXY(
            [NotNull] Line3D line1, int line1Index,
            [NotNull] IEnumerable <KeyValuePair <int, Line3D> > linestring2Segments,
            double tolerance)
        {
            // Tolerance rules:
            // If there is an accurate intersection along the segment's interior but the source start AND end are
            // within the tolerance, the source line is used

            // If there is no accurate intersection:
            // The line1 start or the line1 end could be within distance of the other line -> add source point
            // the other line's start or end could be within distance of this line -> add target point
            // if at least 2 start/end points are within distance: create Line3D result from source line

            // TODO: Test for 0-length lines

            foreach (KeyValuePair <int, Line3D> path2Segment in
                     linestring2Segments.OrderBy(kvp => kvp.Key))
            {
                int    targetIdx = path2Segment.Key;
                Line3D otherLine = path2Segment.Value;

                // With the speculative optimization for continued linear intersections
                // providing a known target end intersection factor has no extra benefit.
                SegmentIntersection intersection =
                    SegmentIntersection.CalculateIntersectionXY(
                        line1Index, targetIdx, line1, otherLine, tolerance);

                if (intersection.HasIntersection)
                {
                    yield return(intersection);
                }
            }
        }
コード例 #4
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);
        }
コード例 #5
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);
            }
        }
コード例 #6
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);
        }
コード例 #7
0
        public static bool SourceInteriorIntersectsXY([NotNull] Line3D line1,
                                                      [NotNull] Line3D line2,
                                                      double tolerance)
        {
            SegmentIntersection segmentIntersection =
                SegmentIntersection.CalculateIntersectionXY(
                    0, 0, line1, line2, tolerance);

            return(segmentIntersection.HasSourceInteriorIntersection);
        }
コード例 #8
0
 public IntersectionPoint3D(
     [NotNull] Pnt3D point,
     double virtualRingVertexIndex,
     SegmentIntersection segmentIntersection = null,
     IntersectionPointType type = IntersectionPointType.Unknown)
 {
     Point = point;
     VirtualSourceVertex = virtualRingVertexIndex;
     SegmentIntersection = segmentIntersection;
     Type = type;
 }
コード例 #9
0
        /// <summary>
        /// Calculates intersection for two given segments.
        /// </summary>
        /// <param name="sourceLineIndex"></param>
        /// <param name="targetLineIndex"></param>
        /// <param name="sourceLine"></param>
        /// <param name="targetLine"></param>
        /// <param name="tolerance"></param>
        /// <returns></returns>
        public static SegmentIntersection CalculateIntersectionXY(
            int sourceLineIndex,
            int targetLineIndex,
            [NotNull] Line3D sourceLine,
            [NotNull] Line3D targetLine,
            double tolerance)
        {
            var intersection = new SegmentIntersection(
                sourceLineIndex, targetLineIndex, sourceLine,
                targetLine, tolerance);

            return(intersection);
        }
コード例 #10
0
        public Pnt3D GetNonIntersectingSourcePoint([NotNull] Linestring sourceRing,
                                                   double distanceFromIntersectionAsRatio)
        {
            Assert.NotNull(SegmentIntersection);

            double factor;

            var searchForward = true;

            if (Type == IntersectionPointType.LinearIntersectionStart)
            {
                searchForward = false;
                factor        = SegmentIntersection.GetLinearIntersectionStartFactor(true);
            }
            else if (Type == IntersectionPointType.LinearIntersectionEnd)
            {
                factor = SegmentIntersection.GetLinearIntersectionEndFactor(true);
            }
            else
            {
                factor = SegmentIntersection.GetIntersectionPointFactorAlongSource();
            }

            Line3D segment = sourceRing[SegmentIntersection.SourceIndex];

            if (searchForward)
            {
                factor += distanceFromIntersectionAsRatio;
            }
            else
            {
                factor -= distanceFromIntersectionAsRatio;
            }

            if (factor >= 1)
            {
                segment =
                    sourceRing[
                        sourceRing.NextIndexInRing(SegmentIntersection.SourceIndex)];
                factor -= 1;
            }
            else if (factor < 0)
            {
                segment =
                    sourceRing[
                        sourceRing.PreviousIndexInRing(SegmentIntersection.SourceIndex)];
                factor += 1;
            }

            return(segment.GetPointAlong(factor, true));
        }
コード例 #11
0
        /// <summary>
        /// Creates a segment intersection for two coincident segments.
        /// </summary>
        /// <param name="sourceLineIndex"></param>
        /// <param name="targetLineIndex"></param>
        /// <param name="inverted"></param>
        /// <returns></returns>
        public static SegmentIntersection CreateCoincidenceIntersectionXY(
            int sourceLineIndex,
            int targetLineIndex,
            bool inverted)
        {
            var intersection = new SegmentIntersection(
                sourceLineIndex, targetLineIndex, 0, 1, 1, 0)
            {
                SourceStartIntersects = true,
                SourceEndIntersects   = true,
                LinearIntersectionInOppositeDirection = inverted
            };

            return(intersection);
        }
コード例 #12
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);
        }
コード例 #13
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);
        }
コード例 #14
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);
        }