/// <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); } } }
/// <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); }
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); } } }
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); }
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); } }
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); }
public static bool SourceInteriorIntersectsXY([NotNull] Line3D line1, [NotNull] Line3D line2, double tolerance) { SegmentIntersection segmentIntersection = SegmentIntersection.CalculateIntersectionXY( 0, 0, line1, line2, tolerance); return(segmentIntersection.HasSourceInteriorIntersection); }
public IntersectionPoint3D( [NotNull] Pnt3D point, double virtualRingVertexIndex, SegmentIntersection segmentIntersection = null, IntersectionPointType type = IntersectionPointType.Unknown) { Point = point; VirtualSourceVertex = virtualRingVertexIndex; SegmentIntersection = segmentIntersection; Type = type; }
/// <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); }
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)); }
/// <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); }
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); }
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); }
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); }