in MREUnityRuntimeLib/ProceduralToolkit/Geometry/Closest2D.cs [1144:1283]
public static void SegmentCircle(Vector2 segmentA, Vector2 segmentB, Vector2 circleCenter, float circleRadius,
out Vector2 segmentPoint, out Vector2 circlePoint)
{
Vector2 segmentAToCenter = circleCenter - segmentA;
Vector2 fromAtoB = segmentB - segmentA;
float segmentLength = fromAtoB.magnitude;
if (segmentLength < Geometry.Epsilon)
{
segmentPoint = segmentA;
float distanceToPoint = segmentAToCenter.magnitude;
if (distanceToPoint < circleRadius + Geometry.Epsilon)
{
if (distanceToPoint > circleRadius - Geometry.Epsilon)
{
circlePoint = segmentPoint;
return;
}
if (distanceToPoint < Geometry.Epsilon)
{
circlePoint = segmentPoint;
return;
}
}
Vector2 toPoint = -segmentAToCenter/distanceToPoint;
circlePoint = circleCenter + toPoint*circleRadius;
return;
}
Vector2 segmentDirection = fromAtoB.normalized;
float centerProjection = Vector2.Dot(segmentDirection, segmentAToCenter);
if (centerProjection + circleRadius < -Geometry.Epsilon ||
centerProjection - circleRadius > segmentLength + Geometry.Epsilon)
{
// No intersection
if (centerProjection < 0)
{
segmentPoint = segmentA;
circlePoint = circleCenter - segmentAToCenter.normalized*circleRadius;
return;
}
segmentPoint = segmentB;
circlePoint = circleCenter - (circleCenter - segmentB).normalized*circleRadius;
return;
}
float sqrDistanceToLine = segmentAToCenter.sqrMagnitude - centerProjection*centerProjection;
float sqrDistanceToIntersection = circleRadius*circleRadius - sqrDistanceToLine;
if (sqrDistanceToIntersection < -Geometry.Epsilon)
{
// No intersection
if (centerProjection < -Geometry.Epsilon)
{
segmentPoint = segmentA;
circlePoint = circleCenter - segmentAToCenter.normalized*circleRadius;
return;
}
if (centerProjection > segmentLength + Geometry.Epsilon)
{
segmentPoint = segmentB;
circlePoint = circleCenter - (circleCenter - segmentB).normalized*circleRadius;
return;
}
segmentPoint = segmentA + segmentDirection*centerProjection;
circlePoint = circleCenter + (segmentPoint - circleCenter).normalized*circleRadius;
return;
}
if (sqrDistanceToIntersection < Geometry.Epsilon)
{
if (centerProjection < -Geometry.Epsilon)
{
// No intersection
segmentPoint = segmentA;
circlePoint = circleCenter - segmentAToCenter.normalized*circleRadius;
return;
}
if (centerProjection > segmentLength + Geometry.Epsilon)
{
// No intersection
segmentPoint = segmentB;
circlePoint = circleCenter - (circleCenter - segmentB).normalized*circleRadius;
return;
}
// Point intersection
segmentPoint = circlePoint = 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 = circlePoint = segmentA + segmentDirection*distanceA;
return;
}
if (!pointAIsAfterSegmentA && !pointBIsBeforeSegmentB)
{
// The segment is inside, but no intersection
if (distanceA > -(distanceB - segmentLength))
{
segmentPoint = segmentA;
circlePoint = segmentA + segmentDirection*distanceA;
return;
}
segmentPoint = segmentB;
circlePoint = segmentA + segmentDirection*distanceB;
return;
}
bool pointAIsBeforeSegmentB = distanceA < segmentLength + Geometry.Epsilon;
if (pointAIsAfterSegmentA && pointAIsBeforeSegmentB)
{
// Point A intersection
segmentPoint = circlePoint = segmentA + segmentDirection*distanceA;
return;
}
bool pointBIsAfterSegmentA = distanceB > -Geometry.Epsilon;
if (pointBIsAfterSegmentA && pointBIsBeforeSegmentB)
{
// Point B intersection
segmentPoint = circlePoint = segmentA + segmentDirection*distanceB;
return;
}
// No intersection
if (centerProjection < 0)
{
segmentPoint = segmentA;
circlePoint = circleCenter - segmentAToCenter.normalized*circleRadius;
return;
}
segmentPoint = segmentB;
circlePoint = circleCenter - (circleCenter - segmentB).normalized*circleRadius;
}