public static float Intersect(Rect rect, LocalSegment3 segment) { Vector3 closestPointOnSegment_unused, closestPointOnRect_unused; return(Intersect(rect, segment, out closestPointOnRect_unused, out closestPointOnSegment_unused)); }
// https://stackoverflow.com/a/18543221 for line-plane intersection. /// <summary> /// Returns true if the line segment intersects with the plane, or false otherwise. /// /// Specify output parameters to receive more detailed information about the /// intersection, such as the point at which it occurs and whether the line lies on /// the plane. /// </summary> public static bool Intersect(LocalPlane plane, LocalSegment3 line) { Vector3 pointOnPlane_unused; float amountAlongSegment_unused; bool isLineCoplanar_unused; return(Intersect(plane, line, out pointOnPlane_unused, out amountAlongSegment_unused, out isLineCoplanar_unused)); }
/// <summary> /// Returns true if the line segment intersects with the plane, or false otherwise. /// /// If intersectInfiniteLine is specified, returns true if the line defined by the /// line segment intersects with the plane, or false otherwise. /// /// If this method returns true, no out parameters are set to NaN, and reasonable /// defaults are chosen in edge-cases (such as a coplanar line). If this method /// returns false, some or all output parameters may have no reasonable value and /// are set to NaN. /// /// pointOnPlane is the point along the line defined by the segment that intersects /// with the plane. If the line segment is parallel to the plane and _on_ the plane, /// pointOnPlane will be set to the center of the line segment as a convenience. /// Otherwise, it will be set to a Vector3 containing all NaNs. /// /// amountAlongSegment is the normalized amount from A to B along the line segment /// that intersects with the plane. The line segment intersects with the plane only /// if this value is between 0 and 1 (inclusive). If the line segment is parallel to /// the plane and _on_ the plane, amountAlongSegment will be set to 0.5f. Otherwise, /// amountAlongSegment will be set to NaN. /// /// isLineCoplanar is true if the line defined by the line segment is wholly on /// the plane, or false otherwise. /// </summary> public static bool Intersect(LocalPlane plane, LocalSegment3 line, out Vector3 pointOnPlane, out float amountAlongSegment, out bool isLineCoplanar, bool intersectInfiniteLine = false) { var planePosition = plane.position; var planeNormal = plane.normal; var a = line.a; var b = line.b; var u = b - a; var uDotN = planeNormal.Dot(u); if (uDotN.Abs() > float.Epsilon) { isLineCoplanar = false; var w = a - planePosition; amountAlongSegment = -(planeNormal.Dot(w)) / uDotN; pointOnPlane = a + u * amountAlongSegment; return(intersectInfiniteLine || (amountAlongSegment >= 0f && amountAlongSegment <= 1f)); } else { var pa = a - planePosition; if (planeNormal.Dot(pa).Abs() < float.Epsilon) { isLineCoplanar = true; } else { isLineCoplanar = false; } if (isLineCoplanar) { pointOnPlane = (a + b) / 2f; amountAlongSegment = 0.5f; return(true); } else { pointOnPlane = new Vector3(float.NaN, float.NaN, float.NaN); amountAlongSegment = float.NaN; return(false); } } }
// 2D intersection: // https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect // https://ideone.com/PnPJgb /// <summary> /// Returns true if the two segments are not parallel or colinear and intersect in 2D, /// ignoring the segments' Z components. /// </summary> public static bool Intersect2D(LocalSegment3 segment0, LocalSegment3 segment1, out Vector2 intersectionPoint, out float amountAlongSegment0, out float amountAlongSegment1) { Vector2 p = segment0.a, q = segment0.b, r = segment1.a, s = segment1.b; // t = (q − p) × s / (r × s) // u = (q − p) × r / (r × s) var denom = Fake2DCross(r, s); if (denom == 0) { // Lines are collinear or parallel. amountAlongSegment0 = float.NaN; amountAlongSegment1 = float.NaN; intersectionPoint = new Vector2(float.NaN, float.NaN); return(false); } var tNumer = Fake2DCross(q - p, s); var uNumer = Fake2DCross(q - p, r); amountAlongSegment0 = tNumer / denom; amountAlongSegment1 = uNumer / denom; if (amountAlongSegment0 < 0 || amountAlongSegment0 > 1 || amountAlongSegment1 < 0 || amountAlongSegment1 > 1) { // Line segments do not intersect within their ranges. intersectionPoint = default(Vector2); return(false); } intersectionPoint = p + r * amountAlongSegment0; return(true); }
/// <summary> /// Returns the closest point to point p on the segment. Also outputs the /// parameterization from 0 to 1 along ab that results in the closest point: /// closestPt(t) = a + t*(b - a). /// </summary> public static Vector3 ClosestPtPointSegment(LocalSegment3 segment, Vector3 p, out float t) { return(ClosestPtPointSegment(segment.a, segment.b, p, out t)); }
/// <summary> /// Returns the closest point to point p on the segment. /// </summary> public static Vector3 ClosestPtPointSegment(LocalSegment3 segment, Vector3 p) { float unusedT; return(ClosestPtPointSegment(segment.a, segment.b, p, out unusedT)); }
/// <summary> /// Returns the squared-distance of the point p from the segment. /// </summary> public static float SqrDistPointSegment(LocalSegment3 segment, Vector3 p) { return(SqrDistPointSegment(segment.a, segment.b, p)); }
/// <summary> /// Computes the squared distance between two 3D line segments, outputting the amount /// along each segment (0 to 1) corresponding to the closest points (t1 and t2), and /// outputting the closest points themselves (c1 and c2). /// </summary> public static float Intersect(LocalSegment3 seg1, LocalSegment3 seg2, out float t1, out float t2, out Vector3 c1, out Vector3 c2) { Vector3 d1 = seg1.b - seg1.a; // Direction vector of seg1. Vector3 d2 = seg2.b - seg2.a; // Direction vector of seg2. Vector3 r = seg1.a - seg2.a; float a = Dot(d1, d1); // Squared length of seg1. float e = Dot(d2, d2); // Squared length of seg2. float f = Dot(d2, r); // Check if either or both segments degenerate into points. if (a <= float.Epsilon && e <= float.Epsilon) { // Both segments degenerate into points. t1 = t2 = 0f; c1 = seg1.a; c2 = seg2.a; return(Dot(c1 - c2, c1 - c2)); } if (a <= float.Epsilon) { // First segment degenerates into a point. t1 = 0f; t2 = (f / e).Clamped01(); } else { float c = Dot(d1, r); if (e <= float.Epsilon) { // Second segment degenerates into a point. t2 = 0f; t1 = (-c / a).Clamped01(); } else { // General, non-degenerate case. float b = Dot(d1, d2); float denom = a * e - b * b; // Always non-negative. // If the segments are not parallel, compute the closest point on seg1 to seg2 // and clamp to seg1. Otherwise, pick an arbitrary t1 (here 0). if (denom != 0f) { t1 = ((b * f - c * e) / denom).Clamped01(); } else { t1 = 0f; } // Compute the point on seg2 closest to t1. float t2nom = b * t1 + f; // avoid dividing e until later. // If t2 in [0, 1], we're done. Otherwise, recompute t1 for the new value of // t2 and clamp to [0, 1]. if (t2nom < 0f) { t2 = 0f; t1 = (-c / a).Clamped01(); } else if (t2nom > e) { t2 = 1f; t1 = ((b - c) / a).Clamped01(); } else { t2 = t2nom / e; } } } c1 = seg1.a + d1 * t1; c2 = seg2.a + d2 * t2; return((c1 - c2).sqrMagnitude); }
public static float Intersect(Rect rect, LocalSegment3 segment, out Vector3 closestPointOnRect, out Vector3 closestPointOnSegment) { float closestSqrDist = float.PositiveInfinity; closestPointOnRect = closestPointOnSegment = default(Vector3); Vector3 segmentA_rect; bool aProjectsInside = rect.ContainsProjectedPoint(segment.a, out segmentA_rect); Vector3 segmentB_rect; bool bProjectsInside = rect.ContainsProjectedPoint(segment.b, out segmentB_rect); // Test if the segment intersects with the rect plane and is inside the rect. var plane_rect = rect.ToLocalPlane(); var segment_rect = new LocalSegment3(segmentA_rect, segmentB_rect); Vector3 pointOnPlane_rect; float amountAlongSegment; bool isLineCoplanar; var intersectsPlane = Intersect(plane_rect, segment_rect, out pointOnPlane_rect, out amountAlongSegment, out isLineCoplanar); if (intersectsPlane) { var absPointOnPlane_rect = pointOnPlane_rect.Abs(); var absRadii = rect.radii.Abs(); if (absPointOnPlane_rect.x <= absRadii.x && absPointOnPlane_rect.y <= absRadii.y) { closestPointOnRect = rect.matrix.MultiplyPoint3x4(pointOnPlane_rect); closestPointOnSegment = segment.Evaluate(amountAlongSegment); return(0f); } } // Must test the rect segments and plane-projection distances to find the closest // pair of points and return their squared-distance. // Segment point A <> plane, when A projects inside rect. if (aProjectsInside) { var testPointRect = rect.matrix.MultiplyPoint3x4(segmentA_rect.WithZ(0f)); var testSqrDist = (testPointRect - segment.a).sqrMagnitude; if (testSqrDist < closestSqrDist) { closestSqrDist = testSqrDist; closestPointOnRect = testPointRect; closestPointOnSegment = segment.a; } } // Segment point B <> plane, when B projects inside rect. if (bProjectsInside) { var testPointRect = rect.matrix.MultiplyPoint3x4(segmentB_rect.WithZ(0f)); var testSqrDist = (testPointRect - segment.b).sqrMagnitude; if (testSqrDist < closestSqrDist) { closestSqrDist = testSqrDist; closestPointOnRect = testPointRect; closestPointOnSegment = segment.b; } } if (!aProjectsInside || !bProjectsInside) { // Closest point segment <> {AB, BC, CD, DA}. foreach (var rectSegment in rect.segments) { Vector3 testClosestPointRectSegment; Vector3 testClosestPointSegment; float unusedT1, unusedT2; var testSqrDist = Intersect(rectSegment, segment, out unusedT1, out unusedT2, out testClosestPointRectSegment, out testClosestPointSegment); // Debug //RuntimeGizmos.RuntimeGizmoDrawer drawer; //if (RuntimeGizmos.RuntimeGizmoManager.TryGetGizmoDrawer(out drawer)) { // drawer.DrawLine(testClosestPointRectSegment, testClosestPointSegment); //} if (testSqrDist < closestSqrDist) { closestSqrDist = testSqrDist; closestPointOnRect = testClosestPointRectSegment; closestPointOnSegment = testClosestPointSegment; } } } return(closestSqrDist); }
public static float Intersect(LocalSegment3 segment, Rect rect, out Vector3 closestPointOnSegment, out Vector3 closestPointOnRect) { return(Intersect(rect, segment, out closestPointOnRect, out closestPointOnSegment)); }
//[ThreadStatic] //private static LocalSegment3[] _rectEdgesBuffer = new LocalSegment3[4]; public static float Intersect(LocalSegment3 segment, Rect rect) { return(Intersect(rect, segment)); }