in MREUnityRuntimeLib/ProceduralToolkit/Geometry/Distance3D.cs [203:298]
public static float SegmentSphere(Vector3 segmentA, Vector3 segmentB, Vector3 sphereCenter, float sphereRadius)
{
Vector3 segmentAToCenter = sphereCenter - segmentA;
Vector3 fromAtoB = segmentB - segmentA;
float segmentLength = fromAtoB.magnitude;
if (segmentLength < Geometry.Epsilon)
{
return segmentAToCenter.magnitude - sphereRadius;
}
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)
{
return segmentAToCenter.magnitude - sphereRadius;
}
return (sphereCenter - segmentB).magnitude - sphereRadius;
}
float sqrDistanceToA = segmentAToCenter.sqrMagnitude;
float sqrDistanceToLine = sqrDistanceToA - centerProjection*centerProjection;
float sqrDistanceToIntersection = sphereRadius*sphereRadius - sqrDistanceToLine;
if (sqrDistanceToIntersection < -Geometry.Epsilon)
{
// No intersection
if (centerProjection < -Geometry.Epsilon)
{
return Mathf.Sqrt(sqrDistanceToA) - sphereRadius;
}
if (centerProjection > segmentLength + Geometry.Epsilon)
{
return (sphereCenter - segmentB).magnitude - sphereRadius;
}
return Mathf.Sqrt(sqrDistanceToLine) - sphereRadius;
}
if (sqrDistanceToIntersection < Geometry.Epsilon)
{
if (centerProjection < -Geometry.Epsilon)
{
// No intersection
return Mathf.Sqrt(sqrDistanceToA) - sphereRadius;
}
if (centerProjection > segmentLength + Geometry.Epsilon)
{
// No intersection
return (sphereCenter - segmentB).magnitude - sphereRadius;
}
// Point intersection
return 0;
}
// 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)
{
// Two points intersection
return 0;
}
if (!pointAIsAfterSegmentA && !pointBIsBeforeSegmentB)
{
// The segment is inside, but no intersection
distanceB = -(distanceB - segmentLength);
return distanceA > distanceB ? distanceA : distanceB;
}
bool pointAIsBeforeSegmentB = distanceA < segmentLength + Geometry.Epsilon;
if (pointAIsAfterSegmentA && pointAIsBeforeSegmentB)
{
// Point A intersection
return 0;
}
bool pointBIsAfterSegmentA = distanceB > -Geometry.Epsilon;
if (pointBIsAfterSegmentA && pointBIsBeforeSegmentB)
{
// Point B intersection
return 0;
}
// No intersection
if (centerProjection < 0)
{
return Mathf.Sqrt(sqrDistanceToA) - sphereRadius;
}
return (sphereCenter - segmentB).magnitude - sphereRadius;
}