/// <summary> /// Returns the signed distance (relative to the first segment) to the closest point on the second line segment. /// </summary> /// <param name="segment1Start">Segment 1 start point</param> /// <param name="segment1End">Segment 1 end point</param> /// <param name="segment2Start">Segment 2 start point</param> /// <param name="segment2End">Segment 2 end point</param> internal static float SignedDistanceFromSegmentToClosestPointOnOtherSegment(Vector2 segment1Start, Vector2 segment1End, Vector2 segment2Start, Vector2 segment2End) { var closestPoints = ClosestPointsBetweenSegments(segment1Start, segment1End, segment2Start, segment2End); var cross = Vector2Util.Cross2D(closestPoints.SecondPoint - segment1Start, segment1End - segment1Start); return(-Math.Sign(cross) * closestPoints.Distance);//- sign is to match with normal direction in Normal Util }
/// <summary> /// If a point is on the right-hand side of a segment. /// </summary> /// <param name="segmentStart">The segment start point.</param> /// <param name="segmentEnd">The segment end point.</param> /// <param name="point">The test point.</param> internal static bool PointIsOnRightSide(Vector2 segmentStart, Vector2 segmentEnd, Vector2 point) { var segmentDiff = segmentEnd - segmentStart; var pointDiff = point - segmentStart; var cross = Vector2Util.Cross2D(pointDiff, segmentDiff); return(cross >= 0f); }
/// <summary> /// Determines whether two 2D line segments (each defined by start and end points) intersect. /// </summary> /// <param name="segment1Start">Segment 1 start point</param> /// <param name="segment1End">Segment 1 end point</param> /// <param name="segment2Start">Segment 2 start point</param> /// <param name="segment2End">Segment 2 end point</param> /// <param name="intersectionPoint">Intersection point, if the segments intersect</param> /// <param name="segmentFraction1">Fraction along first segment of the intersection, if the segments intersect</param> /// <param name="segmentFraction2">Fraction along second segment of the intersection, if the segments intersect</param> public static bool GetLineSegmentIntersection(Vector2 segment1Start, Vector2 segment1End, Vector2 segment2Start, Vector2 segment2End, out Vector2 intersectionPoint, out float segmentFraction1, out float segmentFraction2) { bool ret = false; intersectionPoint = Vector2.zero; segmentFraction1 = 0; segmentFraction2 = 0; var diff1 = segment1End - segment1Start; var diff2 = segment2End - segment2Start; var crossDiff1Diff2 = Vector2Util.Cross2D(diff1, diff2); var vec1to2 = segment2Start - segment1Start; var vec1To2CrossDiff1 = Vector2Util.Cross2D(vec1to2, diff1); if (crossDiff1Diff2 == 0f) { if (vec1To2CrossDiff1 == 0f) { //collinear var diff1MagSq = diff1.sqrMagnitude; var diff2MagSq = diff2.sqrMagnitude; var t0 = Vector2.Dot(vec1to2, diff1) / diff1MagSq; var t1 = t0 + Vector2.Dot(diff1, diff2) / diff1MagSq; var min = Mathf.Min(t0, t1); var max = Mathf.Max(t0, t1); if (min <= 1f && max >= 0f && diff1MagSq > 0f && diff2MagSq > 0f) { ret = true; segmentFraction1 = 0.5f * (Mathf.Clamp01(min) + Mathf.Clamp01(max)); intersectionPoint = segment1Start + diff1 * segmentFraction1; segmentFraction2 = Vector2.Dot(intersectionPoint - segment2Start, diff2); } else { //range does not intsersect [0:1] } } else { //parallel, not collinear ret = false; } } else { var vec1To2CrossDiff2 = Vector2Util.Cross2D(vec1to2, diff2); segmentFraction1 = vec1To2CrossDiff2 / crossDiff1Diff2; segmentFraction2 = vec1To2CrossDiff1 / crossDiff1Diff2; if (segmentFraction1 >= 0 && segmentFraction2 >= 0 && segmentFraction1 <= 1f && segmentFraction2 <= 1f) { ret = true; intersectionPoint = segment1Start + diff1 * segmentFraction1; } } return(ret); }
/// <summary> /// Determines if two segment tangent directions emanating from a common point intersect. /// This does not take into account actual segment length or extrusion distance; only fractional distances are returned. /// They will intersect if the segments are 'concave' with respect to the extrusion sign. /// Note that the extrusion fraction for second tangent is negative that of the first. /// </summary> /// <param name="previousTangent">Tangent vector of previous segment.</param> /// <param name="nextTangent">Tangent vector of next segment</param> /// <param name="extrusionSign">Sign of the extrusion direction</param> /// <param name="extrusionMagnitudeFractionFirstTangent">Fraction of extrusion magnitude along the first tangent direction that the intersection will occur.</param> internal static bool DoNeighbouringSegmentTangentsFromCommonPointIntersect(Vector2 previousTangent, Vector2 nextTangent, float extrusionSign, out double extrusionMagnitudeFractionFirstTangent) { bool ret = false; var cross = Vector2Util.Cross2D(nextTangent, previousTangent); var dot = Vector2.Dot(previousTangent, nextTangent); var sign = Mathf.Sign(extrusionSign); if (cross == 0f) { extrusionMagnitudeFractionFirstTangent = 0f; ret = false; } else { extrusionMagnitudeFractionFirstTangent = sign * (1f - dot) / cross; ret = extrusionMagnitudeFractionFirstTangent <= 0f; } return(ret); }
/// <summary> Returns closest point, distances, and handedness information about the closest point on a 2D segment to a test point. </summary> /// <param name="segmentStart">Segment start point</param> /// <param name="segmentEnd">Segment end point</param> /// <param name="point">Test point</param> /// <param name="closestPoint"> The closest point on the segment to the test point </param> /// <param name="onRightSide">Whether the test point is on the right-hand side of the segment </param> /// <param name="segmentFraction">Fraction along the segment of the closest point to the test point</param> /// <param name="distance">Distance from the closest point to the test point</param> /// <param name="perpendicularDistance">Perpendicular distance from the closest point to the test point</param> /// <param name="tangentialDistance">Tangential distance from the closest point to the test point</param> internal static void GetClosestPointToSegmentInformation(Vector2 segmentStart, Vector2 segmentEnd, Vector2 point, out Vector2 closestPoint, out bool onRightSide, out float segmentFraction, out float distance, out float perpendicularDistance, out float tangentialDistance) { var segmentDiff = segmentEnd - segmentStart; Vector2 pointDiff = point - segmentStart; var dot = Vector2.Dot(pointDiff, segmentDiff); var segmentDiffMagSq = segmentDiff.sqrMagnitude; if (segmentDiffMagSq == 0f) { onRightSide = true; segmentFraction = 0f; closestPoint = segmentStart; distance = pointDiff.magnitude; perpendicularDistance = distance; tangentialDistance = distance; } else { var segmentMagnitude = segmentDiff.magnitude; var segmentDirection = segmentDiff / segmentMagnitude; segmentFraction = Mathf.Clamp01(dot / (segmentMagnitude * segmentMagnitude)); closestPoint = (segmentStart + segmentFraction * segmentDiff); var closestPointDiff = point - closestPoint; distance = closestPointDiff.magnitude; var tangentialSignedDistance = Vector2.Dot(segmentDirection, closestPointDiff); var perpendicularVector = closestPointDiff - tangentialSignedDistance * segmentDirection; tangentialDistance = Mathf.Abs(tangentialSignedDistance); perpendicularDistance = perpendicularVector.magnitude; var cross = Vector2Util.Cross2D(pointDiff, segmentDiff); onRightSide = cross >= 0f; } }