Exemple #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;
                }
            }
        }
Exemple #2
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!
        }
Exemple #3
0
        private static bool ArePointsOnDifferentSide(Line3D ofLine, Pnt3D point1,
                                                     Pnt3D point2,
                                                     double tolerance,
                                                     out bool?anyPointAtLeft)
        {
            anyPointAtLeft = null;

            if (point1 == null || point2 == null)
            {
                return(false);
            }

            double d1 = ofLine.GetDistanceXYPerpendicularSigned(point1);

            if (Math.Abs(d1) < tolerance)
            {
                d1 = 0;
            }

            double d2 = ofLine.GetDistanceXYPerpendicularSigned(point2);

            if (Math.Abs(d2) < tolerance)
            {
                d2 = 0;
            }

            anyPointAtLeft = d1 > 0 || d2 > 0;

            return(d1 * d2 < 0);
        }
Exemple #4
0
        /// <summary>
        /// The dot product (scalar product) of u and v.
        /// </summary>
        /// <param name="u"></param>
        /// <param name="v"></param>
        /// <returns></returns>
        public static double DotProduct(Pnt3D u, Vector v)
        {
            Assert.AreEqual(u.Dimension, v.Dimension,
                            "Dimensions of input are not equal");

            return(DotProduct(u[0], u[1], u[2], v[0], v[1], v[2]));
        }
Exemple #5
0
        public static bool Equals3D([NotNull] Pnt3D p0,
                                    [NotNull] Pnt3D p1,
                                    double tolerance)
        {
            if (tolerance <= 0)
            {
                // Equals also if difference is non-significant
                return(MathUtils.AreSignificantDigitsEqual(p0.X, p1.X) &&
                       MathUtils.AreSignificantDigitsEqual(p0.Y, p1.Y) &&
                       MathUtils.AreSignificantDigitsEqual(p0.Z, p1.Z));
            }

            return(MathUtils.IsWithinTolerance(Math.Abs(p0.X - p1.X), tolerance,
                                               MathUtils.GetDoubleSignificanceEpsilon(
                                                   p0.X,
                                                   p1.X)) &&
                   MathUtils.IsWithinTolerance(Math.Abs(p0.Y - p1.Y), tolerance,
                                               MathUtils.GetDoubleSignificanceEpsilon(
                                                   p0.Y,
                                                   p1.Y)) &&
                   MathUtils.IsWithinTolerance(Math.Abs(p0.Z - p1.Z), tolerance,
                                               MathUtils.GetDoubleSignificanceEpsilon(
                                                   p0.Z,
                                                   p1.Z)));
        }
        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);
        }
Exemple #7
0
        private static Pnt3D GetNonIntersectingTargetPoint(
            Linestring targetRing,
            IEnumerable <IntersectionPoint3D> intersectionPoints)
        {
            foreach (IntersectionPoint3D intersectionPoint in intersectionPoints)
            {
                if (intersectionPoint.Type == IntersectionPointType.LinearIntersectionIntermediate)
                {
                    continue;
                }

                if (intersectionPoint.Type == IntersectionPointType.LinearIntersectionStart &&
                    MathUtils.AreEqual(intersectionPoint.VirtualSourceVertex, 0))
                {
                    // Do not use the first point, there might be no proper deviation
                    // because it is actually an intermediate intersection point in a closed ring.
                    continue;
                }

                Pnt3D nonIntersectingTargetPnt =
                    intersectionPoint.GetNonIntersectingTargetPoint(targetRing, 0.5);

                return(nonIntersectingTargetPnt);
            }

            return(null);
        }
Exemple #8
0
        private List <Line3D> FromPoints(IEnumerable <Pnt3D> points,
                                         bool updateBounds = true)
        {
            var result = new List <Line3D>();

            Pnt3D p1 = null;

            var idx = 0;

            foreach (Pnt3D point in points)
            {
                if (updateBounds)
                {
                    UpdateBounds(point, idx, result, p1);
                }

                if (p1 != null)
                {
                    result.Add(new Line3D(p1, point));
                }

                p1 = point;
                idx++;
            }

            return(result);
        }
Exemple #9
0
        public void ReplacePoint(int pointIndex, Pnt3D newPoint)
        {
            Line3D segment1 = null;
            Line3D segment2 = null;

            if (pointIndex == SegmentCount && IsClosed)
            {
                // Last point index in closed ring
                pointIndex = 0;
            }

            // Update EndPoint of previous segment and StartPoint of this index' segment
            int?previousIdx = PreviousSegmentIndex(pointIndex);

            if (previousIdx != null)
            {
                segment1 = PreviousSegmentInRing(pointIndex);
            }

            if (pointIndex < SegmentCount)
            {
                segment2 = _segments[pointIndex];
            }

            segment1?.SetEndPoint(newPoint);
            segment2?.SetStartPoint(newPoint);

            // TODO: To avoid grow-only bounds changes, make sure the replaced point was not an extreme point
            //       ... if replacedPoint.X == XMax -> re-create envelope
            UpdateBounds(newPoint, pointIndex, Segments, null);
        }
Exemple #10
0
        /// <summary>
        /// Determines the intersection point's factor of this line and the other line, if there is an
        /// intersection.
        /// </summary>
        /// <param name="other">The other line</param>
        /// <param name="thisFactor">The factor to calculate the intersection point along this line.</param>
        /// <param name="otherFactor">The factor to calculate the intersection point along the other line.</param>
        /// <returns></returns>
        public bool TryGetIntersectionPointFactorsXY(
            [NotNull] Line3D other,
            out double thisFactor, out double otherFactor)
        {
            thisFactor  = double.NaN;
            otherFactor = double.NaN;

            // TODO: Pnt.VectorProduct is the same as the Perp Product but should probably be called VectorProductXY or PerpProduct?
            //       The vector product is not well-defined in 2D
            double d = PerpProduct(DeltaX, DeltaY,
                                   other.DeltaX, other.DeltaY);

            if (MathUtils.AreEqual(d, 0))
            {
                // parallel in XY plane
                return(false);
            }

            Pnt3D w = StartPoint - other.StartPoint;

            thisFactor =
                PerpProduct(other.DeltaX, other.DeltaY, w.X, w.Y) / d;

            otherFactor = PerpProduct(DeltaX, DeltaY, w.X, w.Y) / d;

            return(true);
        }
Exemple #11
0
        public void UpdatePoint(int pointIndex, double x, double y, double z)
        {
            var newPoint = new Pnt3D(x, y, z);

            // Do not update the existing point to avoid (even temporary) gaps between segments (IsClosed is called everywhere all the time...)
            ReplacePoint(pointIndex, newPoint);
        }
Exemple #12
0
        /// <summary>
        /// Determines whether the test point is completely contained (true) or
        /// on the boundary of the specified ring (i.e. intersecting the linestring).
        /// </summary>
        /// <param name="closedRing">The containing ring.</param>
        /// <param name="testPoint">The test point.</param>
        /// <param name="tolerance">The tolerance.</param>
        /// <param name="disregardingOrientation">Whether the orientation should be disregarded.
        /// If false, a point inside the ring is considered outside if the ring orientation is
        /// counter-clockwise.</param>
        /// <returns>Null, if the point is on the boundary, true if the point is inside the ring.</returns>
        public static bool?AreaContainsXY([NotNull] Linestring closedRing,
                                          [NotNull] Pnt3D testPoint,
                                          double tolerance,
                                          bool disregardingOrientation = false)
        {
            Assert.ArgumentCondition(closedRing.IsClosed, "Ring must be closed");

            if (AreBoundsDisjoint(closedRing, testPoint.X, testPoint.Y, tolerance))
            {
                return(disregardingOrientation ? false : closedRing.ClockwiseOriented == false);
            }

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

            bool result = HasRayOddCrossingNumber(closedRing, testPoint, tolerance);

            if (disregardingOrientation)
            {
                return(result);
            }

            if (closedRing.ClockwiseOriented == false)
            {
                result = !result;
            }

            return(result);
        }
Exemple #13
0
        public bool IntersectsPointXY([NotNull] Pnt3D point, double tolerance)
        {
            if (!ExtentIntersects(point, tolerance, true))
            {
                return(false);
            }

            double distanceAlong;
            double distanceFrom =
                GetDistanceXYPerpendicularSigned(point, out distanceAlong);

            if (Math.Abs(distanceFrom) > tolerance)
            {
                return(false);
            }

            double toleranceFactor = tolerance / Length3D;

            if (distanceAlong < 0 - toleranceFactor ||
                distanceAlong > 1 + toleranceFactor)
            {
                return(false);
            }

            return(true);
        }
Exemple #14
0
        public double GetDistanceAlong(Pnt3D point, bool asRatio = false)
        {
            Pnt3D relativeToStart = point - StartPoint;

            double distanceRatio = DirectionVector.GetFactor(relativeToStart);

            return(asRatio ? distanceRatio : Length3D *distanceRatio);
        }
Exemple #15
0
 public Pnt3D VectorProduct(Pnt3D other)
 {
     return(new Pnt3D(
                Y * other.Z - Z * other.Y,
                Z * other.X - X * other.Z,
                X * other.Y - Y * other.X
                ));
 }
Exemple #16
0
        public Line3D(Pnt3D startPoint, Pnt3D endPoint)
        {
            StartPoint = startPoint;
            EndPoint   = endPoint;

            // Avoid / defer the (expensive) _extent creation
            UpdateBounds(startPoint, endPoint);
        }
 public IntersectionRun(IntersectionPoint3D nextIntersection,
                        Linestring subcurve,
                        Pnt3D includedRingStartPoint)
 {
     _includedRingStartPoint = includedRingStartPoint;
     NextIntersection        = nextIntersection;
     Subcurve = subcurve;
 }
Exemple #18
0
        /// <summary>
        /// The perpendicular distance of the infinite line defined by the Start/End points of this
        /// line to the specified point.
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public double GetDistancePerpendicular(Pnt3D point)
        {
            var sp = new Line3D(StartPoint, point);

            Vector vectorProduct = GeomUtils.CrossProduct(DirectionVector,
                                                          sp.DirectionVector);

            return(Math.Abs(vectorProduct.Length / DirectionVector.Length));
        }
Exemple #19
0
        public double GetDistancePerpendicular(Pnt3D point, bool inXY)
        {
            // Could theoretically be faster with using the cross-product variant with Z=0
            double distanceAlongRatio;
            Pnt3D  pointOnLine;

            return(GetDistancePerpendicular(point, inXY, out distanceAlongRatio,
                                            out pointOnLine));
        }
Exemple #20
0
        public void SetConstantZ(int startVertexIndex, int endVertexIndex, double z)
        {
            for (int i = startVertexIndex; i <= endVertexIndex; i++)
            {
                Pnt3D point = GetPoint3D(i);

                UpdatePoint(i, point.X, point.Y, z);
            }
        }
Exemple #21
0
        public bool EqualsXY(Pnt3D other, double tolerance)
        {
            if (other == null)
            {
                return(false);
            }

            return(MathUtils.AreEqual(Coordinates[0], other.X, tolerance) &&
                   MathUtils.AreEqual(Coordinates[1], other.Y, tolerance));
        }
Exemple #22
0
        private void UpdateBounds(Pnt3D startPoint, Pnt3D endPoint)
        {
            XMin = Math.Min(startPoint.X, endPoint.X);
            YMin = Math.Min(startPoint.Y, endPoint.Y);
            ZMin = Math.Min(startPoint.Z, endPoint.Z);

            XMax = Math.Max(startPoint.X, endPoint.X);
            YMax = Math.Max(startPoint.Y, endPoint.Y);
            ZMax = Math.Max(startPoint.Z, endPoint.Z);
        }
Exemple #23
0
        public bool IsPotentialPseudoLinearIntersection([NotNull] Line3D sourceLine,
                                                        [NotNull] Line3D targetLine,
                                                        double tolerance)
        {
            // NOTE: Acute intersections can have 'pseudo-linear' intersections:
            //       These can result in incorrect touches calculation (same as ArcObjects).

            //   |
            //   |
            //   |\
            //     \
            //      \

            //   |\   this piece will be considered a linear intersecting if the tolerance
            //        is smaller than the lenght of | but large enough that the bottom point
            //        of the vertical line is within the tolerance of the \ line's interior!
            //
            // The condition is (tolerance / sin(alpha)) > dist(intersection point along source) - source start/end)
            // that indicates if this might be a 'pseudo-linear' intersection.
            // -> If the adjacent segment has a (proper) linear intersection along the same
            //    stretch, the pseudo-linear intersection can be safely ignored. In TouchesXY()
            //    probably all pseudo-linear intersections should be ignored?!

            if ((SourceStartIntersects ^ SourceEndIntersects) &&
                (TargetStartIntersects ^ TargetEndIntersects))
            {
                Pnt3D sourcePoint = SourceStartIntersects
                                                            ? sourceLine.StartPoint
                                                            : sourceLine.EndPoint;

                Pnt3D nonIntersectingTargetPnt =
                    TargetStartIntersects ? targetLine.EndPoint : targetLine.StartPoint;

                if (SourceStartIntersects && _source1Factor > 0 && _source1Factor < 1)
                {
                    double sourceEndFactor;
                    Pnt3D  touchPoint = GetLinearIntersectionEnd(sourceLine, out sourceEndFactor);

                    return(IsBelowThreshold(sourcePoint, touchPoint, nonIntersectingTargetPnt,
                                            tolerance));
                }

                if (SourceEndIntersects && _source2Factor > 0 && _source2Factor < 1)
                {
                    double sourceInteriorFactor;
                    Pnt3D  touchPoint =
                        GetLinearIntersectionStart(sourceLine, out sourceInteriorFactor);

                    return(IsBelowThreshold(sourcePoint, touchPoint, nonIntersectingTargetPnt,
                                            tolerance));
                }
            }

            return(false);
        }
Exemple #24
0
        private void UpdateBounds([NotNull] IPnt point,
                                  int pointIndex,
                                  [NotNull] IList <Line3D> currentSegments,
                                  [CanBeNull] Pnt3D previouslyAdded)
        {
            if (point.X < XMin)
            {
                XMin = point.X;
            }

            if (point.X > XMax)
            {
                XMax = point.X;
            }

            if (point.Y < YMin)
            {
                YMin = point.Y;
                RightMostBottomIndex = pointIndex;
            }
            else if (!(point.Y > YMin))
            {
                Pnt3D currentRightMostLowestPnt;
                if (currentSegments.Count == RightMostBottomIndex)
                {
                    if (previouslyAdded != null)
                    {
                        currentRightMostLowestPnt = Assert.NotNull(previouslyAdded);
                    }
                    else
                    {
                        currentRightMostLowestPnt =
                            currentSegments[currentSegments.Count - 1].EndPoint;
                    }
                }
                else
                {
                    currentRightMostLowestPnt =
                        currentSegments[RightMostBottomIndex].StartPoint;
                }

                if (point.X > currentRightMostLowestPnt.X)
                {
                    // equally low, but more to the right
                    RightMostBottomIndex = pointIndex;
                }
            }

            if (point.Y > YMax)
            {
                YMax = point.Y;
            }

            _boundingBox = null;
        }
Exemple #25
0
 public IntersectionPoint3D(
     [NotNull] Pnt3D point,
     double virtualRingVertexIndex,
     SegmentIntersection segmentIntersection = null,
     IntersectionPointType type = IntersectionPointType.Unknown)
 {
     Point = point;
     VirtualSourceVertex = virtualRingVertexIndex;
     SegmentIntersection = segmentIntersection;
     Type = type;
 }
Exemple #26
0
        public void ReverseOrientation()
        {
            _directionVector = null;

            Pnt3D tmp = StartPoint;

            StartPoint = EndPoint;
            EndPoint   = tmp;

            UpdateDeltas();
        }
            public bool ContainsSourceStart(out Pnt3D startPoint)
            {
                if (_includedRingStartPoint != null)
                {
                    startPoint = _includedRingStartPoint;

                    return(true);
                }

                startPoint = null;
                return(false);
            }
Exemple #28
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);
        }
Exemple #29
0
        public int?FindPointIdx([NotNull] Pnt3D point, bool inXY,
                                double tolerance   = double.Epsilon,
                                bool allowIndexing = true)
        {
            if (SpatialIndex == null && allowIndexing &&
                SegmentCount > AllowIndexingThreshold)
            {
                SpatialIndex = SpatialHashSearcher <int> .CreateSpatialSearcher(this);
            }

            if (SpatialIndex != null)
            {
                foreach (int foundSegmentIdx in SpatialIndex.Search(point, tolerance))
                {
                    Line3D segment = this[foundSegmentIdx];

                    bool found = inXY
                                                             ? segment.StartPoint.EqualsXY(point, tolerance)
                                                             : segment.StartPoint.Equals(point, tolerance);

                    if (found)
                    {
                        return(foundSegmentIdx);
                    }
                }
            }
            else
            {
                for (var i = 0; i < SegmentCount; i++)
                {
                    bool found = inXY
                                                             ? _segments[i].StartPoint.EqualsXY(point, tolerance)
                                                             : _segments[i].StartPoint.Equals(point, tolerance);

                    if (found)
                    {
                        return(i);
                    }
                }
            }

            bool isEndPoint = inXY
                                                  ? EndPoint.EqualsXY(point, tolerance)
                                                  : EndPoint.Equals(point, tolerance);

            if (isEndPoint)
            {
                return(PointCount - 1);
            }

            return(null);
        }
Exemple #30
0
        public double GetDistanceSigned(double x, double y, double z)
        {
            if (!IsDefined)
            {
                throw new InvalidOperationException("Plane is not defined.");
            }

            var v = new Pnt3D(x, y, z);

            double dotProd = GeomUtils.DotProduct(v, A, B, C);

            return((dotProd - D) / LengthOfNormal);
        }