public static void SegmentSphere()

in MREUnityRuntimeLib/ProceduralToolkit/Geometry/Closest3D.cs [328:467]


		public static void SegmentSphere(Vector3 segmentA, Vector3 segmentB, Vector3 sphereCenter, float sphereRadius,
			out Vector3 segmentPoint, out Vector3 spherePoint)
		{
			Vector3 segmentAToCenter = sphereCenter - segmentA;
			Vector3 fromAtoB = segmentB - segmentA;
			float segmentLength = fromAtoB.magnitude;
			if (segmentLength < Geometry.Epsilon)
			{
				segmentPoint = segmentA;
				float distanceToPoint = segmentAToCenter.magnitude;
				if (distanceToPoint < sphereRadius + Geometry.Epsilon)
				{
					if (distanceToPoint > sphereRadius - Geometry.Epsilon)
					{
						spherePoint = segmentPoint;
						return;
					}
					if (distanceToPoint < Geometry.Epsilon)
					{
						spherePoint = segmentPoint;
						return;
					}
				}
				Vector3 toPoint = -segmentAToCenter/distanceToPoint;
				spherePoint = sphereCenter + toPoint*sphereRadius;
				return;
			}

			Vector3 segmentDirection = fromAtoB.normalized;
			float centerProjection = Vector3.Dot(segmentDirection, segmentAToCenter);
			if (centerProjection + sphereRadius < -Geometry.Epsilon ||
				centerProjection - sphereRadius > segmentLength + Geometry.Epsilon)
			{
				// No intersection
				if (centerProjection < 0)
				{
					segmentPoint = segmentA;
					spherePoint = sphereCenter - segmentAToCenter.normalized*sphereRadius;
					return;
				}
				segmentPoint = segmentB;
				spherePoint = sphereCenter - (sphereCenter - segmentB).normalized*sphereRadius;
				return;
			}

			float sqrDistanceToLine = segmentAToCenter.sqrMagnitude - centerProjection*centerProjection;
			float sqrDistanceToIntersection = sphereRadius*sphereRadius - sqrDistanceToLine;
			if (sqrDistanceToIntersection < -Geometry.Epsilon)
			{
				// No intersection
				if (centerProjection < -Geometry.Epsilon)
				{
					segmentPoint = segmentA;
					spherePoint = sphereCenter - segmentAToCenter.normalized*sphereRadius;
					return;
				}
				if (centerProjection > segmentLength + Geometry.Epsilon)
				{
					segmentPoint = segmentB;
					spherePoint = sphereCenter - (sphereCenter - segmentB).normalized*sphereRadius;
					return;
				}
				segmentPoint = segmentA + segmentDirection*centerProjection;
				spherePoint = sphereCenter + (segmentPoint - sphereCenter).normalized*sphereRadius;
				return;
			}

			if (sqrDistanceToIntersection < Geometry.Epsilon)
			{
				if (centerProjection < -Geometry.Epsilon)
				{
					// No intersection
					segmentPoint = segmentA;
					spherePoint = sphereCenter - segmentAToCenter.normalized*sphereRadius;
					return;
				}
				if (centerProjection > segmentLength + Geometry.Epsilon)
				{
					// No intersection
					segmentPoint = segmentB;
					spherePoint = sphereCenter - (sphereCenter - segmentB).normalized*sphereRadius;
					return;
				}
				// Point intersection
				segmentPoint = spherePoint = segmentA + segmentDirection*centerProjection;
				return;
			}

			// 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)
			{
				segmentPoint = spherePoint = segmentA + segmentDirection*distanceA;
				return;
			}
			if (!pointAIsAfterSegmentA && !pointBIsBeforeSegmentB)
			{
				// The segment is inside, but no intersection
				if (distanceA > -(distanceB - segmentLength))
				{
					segmentPoint = segmentA;
					spherePoint = segmentA + segmentDirection*distanceA;
					return;
				}
				segmentPoint = segmentB;
				spherePoint = segmentA + segmentDirection*distanceB;
				return;
			}

			bool pointAIsBeforeSegmentB = distanceA < segmentLength + Geometry.Epsilon;
			if (pointAIsAfterSegmentA && pointAIsBeforeSegmentB)
			{
				// Point A intersection
				segmentPoint = spherePoint = segmentA + segmentDirection*distanceA;
				return;
			}
			bool pointBIsAfterSegmentA = distanceB > -Geometry.Epsilon;
			if (pointBIsAfterSegmentA && pointBIsBeforeSegmentB)
			{
				// Point B intersection
				segmentPoint = spherePoint = segmentA + segmentDirection*distanceB;
				return;
			}

			// No intersection
			if (centerProjection < 0)
			{
				segmentPoint = segmentA;
				spherePoint = sphereCenter - segmentAToCenter.normalized*sphereRadius;
				return;
			}
			segmentPoint = segmentB;
			spherePoint = sphereCenter - (sphereCenter - segmentB).normalized*sphereRadius;
		}