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