/// <summary>
        /// Computes an intersection of the segment and the sphere
        /// </summary>
        public static bool SegmentSphere(Vector3 segmentA, Vector3 segmentB, Vector3 sphereCenter, float sphereRadius,
                                         out IntersectionSegmentSphere intersection)
        {
            Vector3 segmentAToCenter = sphereCenter - segmentA;
            Vector3 fromAtoB         = segmentB - segmentA;
            float   segmentLength    = fromAtoB.magnitude;

            if (segmentLength < Geometry.Epsilon)
            {
                float distanceToPoint = segmentAToCenter.magnitude;
                if (distanceToPoint < sphereRadius + Geometry.Epsilon)
                {
                    if (distanceToPoint > sphereRadius - Geometry.Epsilon)
                    {
                        intersection = IntersectionSegmentSphere.Point(segmentA);
                        return(true);
                    }
                    intersection = IntersectionSegmentSphere.None();
                    return(true);
                }
                intersection = IntersectionSegmentSphere.None();
                return(false);
            }

            Vector3 segmentDirection = fromAtoB.normalized;
            float   centerProjection = Vector3.Dot(segmentDirection, segmentAToCenter);

            if (centerProjection + sphereRadius < -Geometry.Epsilon ||
                centerProjection - sphereRadius > segmentLength + Geometry.Epsilon)
            {
                intersection = IntersectionSegmentSphere.None();
                return(false);
            }

            float sqrDistanceToLine         = segmentAToCenter.sqrMagnitude - centerProjection * centerProjection;
            float sqrDistanceToIntersection = sphereRadius * sphereRadius - sqrDistanceToLine;

            if (sqrDistanceToIntersection < -Geometry.Epsilon)
            {
                intersection = IntersectionSegmentSphere.None();
                return(false);
            }

            if (sqrDistanceToIntersection < Geometry.Epsilon)
            {
                if (centerProjection < -Geometry.Epsilon ||
                    centerProjection > segmentLength + Geometry.Epsilon)
                {
                    intersection = IntersectionSegmentSphere.None();
                    return(false);
                }
                intersection = IntersectionSegmentSphere.Point(segmentA + segmentDirection * centerProjection);
                return(true);
            }

            // Line intersection
            float distanceToIntersection = Mathf.Sqrt(sqrDistanceToIntersection);
            float distanceA = centerProjection - distanceToIntersection;
            float distanceB = centerProjection + distanceToIntersection;

            bool pointAIsAfterSegmentA  = distanceA > -Geometry.Epsilon;
            bool pointBIsBeforeSegmentB = distanceB < segmentLength + Geometry.Epsilon;

            if (pointAIsAfterSegmentA && pointBIsBeforeSegmentB)
            {
                Vector3 pointA = segmentA + segmentDirection * distanceA;
                Vector3 pointB = segmentA + segmentDirection * distanceB;
                intersection = IntersectionSegmentSphere.TwoPoints(pointA, pointB);
                return(true);
            }
            if (!pointAIsAfterSegmentA && !pointBIsBeforeSegmentB)
            {
                // The segment is inside, but no intersection
                intersection = IntersectionSegmentSphere.None();
                return(true);
            }

            bool pointAIsBeforeSegmentB = distanceA < segmentLength + Geometry.Epsilon;

            if (pointAIsAfterSegmentA && pointAIsBeforeSegmentB)
            {
                // Point A intersection
                intersection = IntersectionSegmentSphere.Point(segmentA + segmentDirection * distanceA);
                return(true);
            }
            bool pointBIsAfterSegmentA = distanceB > -Geometry.Epsilon;

            if (pointBIsAfterSegmentA && pointBIsBeforeSegmentB)
            {
                // Point B intersection
                intersection = IntersectionSegmentSphere.Point(segmentA + segmentDirection * distanceB);
                return(true);
            }

            intersection = IntersectionSegmentSphere.None();
            return(false);
        }
 /// <summary>
 /// Computes an intersection of the segment and the sphere
 /// </summary>
 public static bool SegmentSphere(Segment3 segment, Sphere sphere, out IntersectionSegmentSphere intersection)
 {
     return(SegmentSphere(segment.a, segment.b, sphere.center, sphere.radius, out intersection));
 }