/// <summary> /// Returns the subcurve consisting of the points between the specified locations along the /// linestring. The from location must be before the end location, unless the linestring is /// closed in which case the new subcurve will cross the original's from/to point. /// </summary> /// <param name="fromSegment"></param> /// <param name="fromSegmentRatio"></param> /// <param name="toSegment"></param> /// <param name="toSegmentRatio"></param> /// <param name="clonePoints"></param> /// <returns></returns> public Linestring GetSubcurve(int fromSegment, double fromSegmentRatio, int toSegment, double toSegmentRatio, bool clonePoints) { Line3D startSegment = _segments[fromSegment]; Pnt3D startPoint = fromSegmentRatio > 0 ? startSegment.GetPointAlong( fromSegmentRatio, asRatio: true) : clonePoints ? startSegment.StartPointCopy : startSegment.StartPoint; Line3D endSegment = _segments[toSegment]; Pnt3D endPoint = toSegmentRatio > 0 ? endSegment.GetPointAlong( toSegmentRatio, asRatio: true) : clonePoints ? endSegment.StartPointCopy : endSegment.StartPoint; var resultPoints = new List <Pnt3D>(); resultPoints.Add(startPoint); double epsilon = MathUtils.GetDoubleSignificanceEpsilon(startPoint.X, startPoint.Y); bool fromBeforeTo = fromSegmentRatio - toSegmentRatio < epsilon; if (fromSegment == toSegment && fromBeforeTo) { resultPoints.Add(endPoint); } else { int currentIndex = fromSegment; if (toSegment <= fromSegment) { // must go across the From/To point Assert.True(IsClosed, "Cannot get subcurve from non-closed linestring with from point after to point."); } while ((currentIndex = NextIndexInRing(currentIndex)) != toSegment) { if (fromSegmentRatio < 1) { resultPoints.Add(_segments[currentIndex].StartPoint); } } if (toSegmentRatio > 0) { resultPoints.Add(endSegment.StartPoint); } resultPoints.Add(endPoint); } return(new Linestring(resultPoints)); }
/// <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); }
/// <summary> /// Collects the relevant information of the line vertices that intersect (i.e. are within the tolerance) of /// the other line. /// </summary> /// <param name="thisLine"></param> /// <param name="otherLine"></param> /// <param name="tolerance"></param> /// <param name="knownTargetEndFactor"></param> private void CollectVertexIntersectionInfos( [NotNull] Line3D thisLine, [NotNull] Line3D otherLine, double tolerance, double?knownTargetEndFactor = null) { _source1Factor = GetPointFactorWithinLine(otherLine, thisLine.StartPoint, tolerance); // Consider removing extra property SourceStartIntersects and compute like this: //SingleInteriorIntersectionFactor == null && _source1Factor >= 0 && _source1Factor <= 1; SourceStartIntersects = _source1Factor >= 0 && _source1Factor <= 1; _source2Factor = GetPointFactorWithinLine(otherLine, thisLine.EndPoint, tolerance); SourceEndIntersects = _source2Factor >= 0 && _source2Factor <= 1; double targetStartFactor = knownTargetEndFactor ?? GetPointFactorWithinLine( thisLine, otherLine.StartPoint, tolerance); if (!double.IsNaN(targetStartFactor)) { TargetStartFactor = targetStartFactor; } double targetEndFactor = GetPointFactorWithinLine( thisLine, otherLine.EndPoint, tolerance); if (!double.IsNaN(targetEndFactor)) { TargetEndFactor = targetEndFactor; } // Determine if the linear intersection has opposite line direction if (!double.IsNaN(_source1Factor) && !double.IsNaN(_source2Factor)) { LinearIntersectionInOppositeDirection = _source1Factor > _source2Factor; } else if (!double.IsNaN(targetStartFactor) && !double.IsNaN(targetEndFactor)) { LinearIntersectionInOppositeDirection = targetStartFactor > targetEndFactor; } else { if (!(double.IsNaN(targetStartFactor) && double.IsNaN(targetEndFactor))) { if (SourceStartIntersects) { LinearIntersectionInOppositeDirection = GetTargetStartIntersectionFactor() > 0; } else if (SourceEndIntersects) { LinearIntersectionInOppositeDirection = GetTargetEndIntersectionFactor() < 1; } } } }
public Pnt3D GetLinearIntersectionEndOnTarget([NotNull] Line3D targetSegment) { double factorAlongTarget; return(GetLinearIntersectionEndOnTarget(targetSegment, out factorAlongTarget)); }
public IEnumerable <KeyValuePair <int, Line3D> > FindSegments( double xMin, double yMin, double xMax, double yMax, double tolerance, bool allowIndexing = true, Predicate <int> predicate = null) { if (SpatialIndex == null && allowIndexing && SegmentCount > AllowIndexingThreshold) { SpatialIndex = SpatialHashSearcher <SegmentIndex> .CreateSpatialSearcher(this); } Predicate <SegmentIndex> multipartIndexPredicate = null; if (predicate != null) { multipartIndexPredicate = found => { int globalIdx = GetGlobalSegmentIndex(found.PartIndex, found.LocalIndex); return(predicate(globalIdx)); }; } // NOTE: Using SpatialHashSearcher<int> and converting to local segment indexes is much slower! // -> consider optimized MultiLinestring that is based off one long array of points (WKSPoint structs?) if (SpatialIndex != null) { foreach (SegmentIndex segmentIndex in SpatialIndex.Search( xMin, yMin, xMax, yMax, this, tolerance, multipartIndexPredicate)) { Line3D segment = GetSegment(segmentIndex.PartIndex, segmentIndex.LocalIndex); if (segment.ExtentIntersectsXY( xMin, yMin, xMax, yMax, tolerance)) { yield return(new KeyValuePair <int, Line3D>( GetGlobalSegmentIndex(segmentIndex.PartIndex, segmentIndex.LocalIndex), segment)); } } } else { int i = 0; foreach (Line3D segment in this) { if (predicate != null && !predicate(i)) { continue; } if (segment.ExtentIntersectsXY( xMin, yMin, xMax, yMax, tolerance)) { //var identifier = new SegmentIndex(p, s); yield return(new KeyValuePair <int, Line3D>(i, segment)); } i++; } } }