/// <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;
            }
        }