예제 #1
0
        /// <summary>
        /// Finds the endpoint of the segments P and Q which
        /// is closest to the other segment.
        /// This is a reasonable surrogate for the true
        /// intersection points in ill-conditioned cases
        /// (e.g. where two segments are nearly coincident,
        /// or where the endpoint of one segment lies almost on the other segment).
        /// </summary>
        /// <remarks>
        /// This replaces the older CentralEndpoint heuristic,
        /// which chose the wrong endpoint in some cases
        /// where the segments had very distinct slopes
        /// and one endpoint lay almost on the other segment.
        /// </remarks>
        /// <param name="p1">an endpoint of segment P</param>
        /// <param name="p2">an endpoint of segment P</param>
        /// <param name="q1">an endpoint of segment Q</param>
        /// <param name="q2">an endpoint of segment Q</param>
        /// <returns>the nearest endpoint to the other segment</returns>
        private static Coordinate NearestEndpoint(Coordinate p1, Coordinate p2,
                                                  Coordinate q1, Coordinate q2)
        {
            var    nearestPt = p1;
            double minDist   = DistanceComputer.PointToSegment(p1, q1, q2);

            double dist = DistanceComputer.PointToSegment(p2, q1, q2);

            if (dist < minDist)
            {
                minDist   = dist;
                nearestPt = p2;
            }
            dist = DistanceComputer.PointToSegment(q1, p1, p2);
            if (dist < minDist)
            {
                minDist   = dist;
                nearestPt = q1;
            }
            dist = DistanceComputer.PointToSegment(q2, p1, p2);
            if (dist < minDist)
            {
                minDist   = dist;
                nearestPt = q2;
            }
            return(nearestPt);
        }
예제 #2
0
        /// <summary>
        /// Computes the distance from a point to a sequence of line segments.
        /// </summary>
        /// <param name="p">A point</param>
        /// <param name="line">A sequence of contiguous line segments defined by their vertices</param>
        /// <returns>The minimum distance between the point and the line segments</returns>
        public static double PointToSegmentString(Coordinate p, Coordinate[] line)
        {
            if (line.Length == 0)
            {
                throw new ArgumentException(
                          "Line array must contain at least one vertex");
            }
            // this handles the case of length = 1
            double minDistance = p.Distance(line[0]);

            for (int i = 0; i < line.Length - 1; i++)
            {
                double dist = DistanceComputer.PointToSegment(p, line[i], line[i + 1]);
                if (dist < minDistance)
                {
                    minDistance = dist;
                }
            }
            return(minDistance);
        }
예제 #3
0
        /// <summary>
        /// Computes the distance from a point to a sequence of line segments.
        /// </summary>
        /// <param name="p">A point</param>
        /// <param name="line">A sequence of contiguous line segments defined by their vertices</param>
        /// <returns>The minimum distance between the point and the line segments</returns>
        public static double PointToSegmentString(Coordinate p, ICoordinateSequence line)
        {
            if (line.Count == 0)
            {
                throw new ArgumentException(
                          "Line array must contain at least one vertex");
            }
            // this handles the case of length = 1
            var    lastStart   = line.GetCoordinate(0);
            double minDistance = p.Distance(lastStart);

            for (int i = 1; i < line.Count - 1; i++)
            {
                var    currentEnd = line.GetCoordinate(i);
                double dist       = DistanceComputer.PointToSegment(p, lastStart, currentEnd);
                if (dist < minDistance)
                {
                    minDistance = dist;
                }
                lastStart = currentEnd;
            }
            return(minDistance);
        }
예제 #4
0
 public static double DistanceLineLine(Coordinate A, Coordinate B, Coordinate C, Coordinate D)
 {
     return(DistanceComputer.SegmentToSegment(A, B, C, D));
 }
예제 #5
0
 public static double DistancePointLine(Coordinate p, Coordinate[] line)
 {
     return(DistanceComputer.PointToSegmentString(p, line));
 }
예제 #6
0
 public static double DistancePointLinePerpendicular(Coordinate p, Coordinate A, Coordinate B)
 {
     return(DistanceComputer.PointToLinePerpendicular(p, A, B));
 }
예제 #7
0
 public static double DistancePointLine(Coordinate p, Coordinate A, Coordinate B)
 {
     return(DistanceComputer.PointToSegment(p, A, B));
 }
예제 #8
0
        /// <summary>
        /// Computes the distance from a line segment AB to a line segment CD
        /// <para/>
        /// Note: NON-ROBUST!
        /// </summary>
        /// <param name="A">The first point of the first line</param>
        /// <param name="B">The second point of the first line (must be different to A)</param>
        /// <param name="C">The first point of the second line</param>
        /// <param name="D">The second point of the second line (must be different to C)</param>
        /// <returns>The distance from a line segment AB to a line segment CD</returns>
        public static double SegmentToSegment(Coordinate A, Coordinate B,
                                              Coordinate C, Coordinate D)
        {
            // check for zero-length segments
            if (A.Equals(B))
            {
                return(DistanceComputer.PointToSegment(A, C, D));
            }
            if (C.Equals(D))
            {
                return(DistanceComputer.PointToSegment(D, A, B));
            }

            // AB and CD are line segments

            /*
             * from comp.graphics.algo
             *
             * Solving the above for r and s yields
             *
             *     (Ay-Cy)(Dx-Cx)-(Ax-Cx)(Dy-Cy)
             * r = ----------------------------- (eqn 1)
             *     (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)
             *
             *     (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
             * s = ----------------------------- (eqn 2)
             *     (Bx-Ax)(Dy-Cy)-(By-Ay)(Dx-Cx)
             *
             * Let P be the position vector of the
             * intersection point, then
             *   P=A+r(B-A) or
             *   Px=Ax+r(Bx-Ax)
             *   Py=Ay+r(By-Ay)
             * By examining the values of r & s, you can also determine some other limiting
             * conditions:
             *   If 0<=r<=1 & 0<=s<=1, intersection exists
             *      r<0 or r>1 or s<0 or s>1 line segments do not intersect
             *   If the denominator in eqn 1 is zero, AB & CD are parallel
             *   If the numerator in eqn 1 is also zero, AB & CD are collinear.
             */

            bool noIntersection = false;

            if (!Envelope.Intersects(A, B, C, D))
            {
                noIntersection = true;
            }
            else
            {
                double denom = (B.X - A.X) * (D.Y - C.Y) - (B.Y - A.Y) * (D.X - C.X);

                if (denom == 0)
                {
                    noIntersection = true;
                }
                else
                {
                    double r_num = (A.Y - C.Y) * (D.X - C.X) - (A.X - C.X) * (D.Y - C.Y);
                    double s_num = (A.Y - C.Y) * (B.X - A.X) - (A.X - C.X) * (B.Y - A.Y);

                    double s = s_num / denom;
                    double r = r_num / denom;

                    if ((r < 0) || (r > 1) || (s < 0) || (s > 1))
                    {
                        noIntersection = true;
                    }
                }
            }
            if (noIntersection)
            {
                return(MathUtil.Min(
                           DistanceComputer.PointToSegment(A, C, D),
                           DistanceComputer.PointToSegment(B, C, D),
                           DistanceComputer.PointToSegment(C, A, B),
                           DistanceComputer.PointToSegment(D, A, B)));
            }
            // segments intersect
            return(0.0);
        }