/// <summary> /// Finds, provided it exists, the intersection point with the specified <see cref="LineSegment"/>. /// </summary> /// /// <param name="other"><see cref="LineSegment"/> to find intersection with.</param> /// /// <returns>Returns intersection point with the specified <see cref="LineSegment"/>, or <see langword="null"/>, if /// the two segments do not intersect.</returns> /// /// <remarks><para>If the two segments do not intersect, the method returns <see langword="null"/>. If the two /// segments share multiple points, this throws an <see cref="InvalidOperationException"/>. /// </para></remarks> /// /// <exception cref="InvalidOperationException">Thrown if the segments overlap - if they have /// multiple points in common.</exception> /// public DoublePoint?GetIntersectionWith(LineSegment other) { DoublePoint?result = null; if ((line.Slope == other.line.Slope) || (line.IsVertical && other.line.IsVertical)) { if (line.Intercept == other.line.Intercept) { // Collinear segments. Inspect and handle. // Consider this segment AB and other as CD. (start/end in both cases) // There are three cases: // 0 shared points: C and D both project onto the same ray of AB // 1 shared point: One of A or B equals one of C or D, and the other of C/D // projects on the correct ray. // Many shared points. ProjectionLocation projC = LocateProjection(other.start), projD = LocateProjection(other.end); if ((projC != ProjectionLocation.SegmentAB) && (projC == projD)) { // no shared points result = null; } else if (((start == other.start) && (projD == ProjectionLocation.RayA)) || ((start == other.end) && (projC == ProjectionLocation.RayA))) { // shared start point result = start; } else if (((end == other.start) && (projD == ProjectionLocation.RayB)) || ((end == other.end) && (projC == ProjectionLocation.RayB))) { // shared end point result = end; } else { // overlapping throw new InvalidOperationException("Overlapping segments do not have a single intersection point."); } } } else { result = GetIntersectionWith(other.line); if ((result.HasValue) && (other.LocateProjection(result.Value) != ProjectionLocation.SegmentAB)) { // the intersection is on the extended line of this segment result = null; } } return(result); }
// Get type of point's projections to this line segment private ProjectionLocation LocateProjection(DoublePoint point) { // Modified from http://www.codeguru.com/forum/showthread.php?t=194400 /* How do I find the distance from a point to a line segment? * * Let the point be C (Cx,Cy) and the line be AB (Ax,Ay) to (Bx,By). * Let P be the point of perpendicular projection of C on AB. The parameter * r, which indicates P's position along AB, is computed by the dot product * of AC and AB divided by the square of the length of AB: * * (1) AC dot AB * r = --------- ||AB||^2 * * r has the following meaning: * * r=0 P = A * r=1 P = B * r<0 P is on the backward extension of AB (and distance C-AB is distance C-A) * r>1 P is on the forward extension of AB (and distance C-AB is distance C-B) * 0<r<1 P is interior to AB (and distance C-AB(segment) is distance C-AB(line)) * * The length of the line segment AB is computed by: * * L = sqrt( (Bx-Ax)^2 + (By-Ay)^2 ) * * and the dot product of two 2D vectors, U dot V, is computed: * * D = (Ux * Vx) + (Uy * Vy) * * So (1) expands to: * * (Cx-Ax)(Bx-Ax) + (Cy-Ay)(By-Ay) * r = ------------------------------- * (Bx-Ax)^2 + (By-Ay)^2 */ // the above is modified here to compare the numerator and denominator, rather than doing the division DoublePoint abDelta = end - start; DoublePoint acDelta = point - start; double numerator = acDelta.X * abDelta.X + acDelta.Y * abDelta.Y; double denomenator = abDelta.X * abDelta.X + abDelta.Y * abDelta.Y; ProjectionLocation result = (numerator < 0) ? ProjectionLocation.RayA : (numerator > denomenator) ? ProjectionLocation.RayB : ProjectionLocation.SegmentAB; return(result); }
public Point?GetIntersectionWith(LineSegment other) { Point?result = null; if (line.Slope == other.line.Slope || (line.IsVertical && other.line.IsVertical)) { if (line.Intercept == other.line.Intercept) { ProjectionLocation projectionLocation = LocateProjection(other.start); ProjectionLocation projectionLocation2 = LocateProjection(other.end); if (projectionLocation != ProjectionLocation.SegmentAB && projectionLocation == projectionLocation2) { result = null; } else if ((start == other.start && projectionLocation2 == ProjectionLocation.RayA) || (start == other.end && projectionLocation == ProjectionLocation.RayA)) { result = start; } else { if ((!(end == other.start) || projectionLocation2 != ProjectionLocation.RayB) && (!(end == other.end) || projectionLocation != ProjectionLocation.RayB)) { throw new InvalidOperationException("Overlapping segments do not have a single intersection point."); } result = end; } } } else { result = GetIntersectionWith(other.line); if (result.HasValue && other.LocateProjection(result.Value) != ProjectionLocation.SegmentAB) { result = null; } } return(result); }