/// <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); }
/// <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); }
/// <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); }
public static double DistanceLineLine(Coordinate A, Coordinate B, Coordinate C, Coordinate D) { return(DistanceComputer.SegmentToSegment(A, B, C, D)); }
public static double DistancePointLine(Coordinate p, Coordinate[] line) { return(DistanceComputer.PointToSegmentString(p, line)); }
public static double DistancePointLinePerpendicular(Coordinate p, Coordinate A, Coordinate B) { return(DistanceComputer.PointToLinePerpendicular(p, A, B)); }
public static double DistancePointLine(Coordinate p, Coordinate A, Coordinate B) { return(DistanceComputer.PointToSegment(p, A, B)); }
/// <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); }