in MREUnityRuntimeLib/ProceduralToolkit/Geometry/Distance2D.cs [404:537]
public static float RaySegment(Vector2 rayOrigin, Vector2 rayDirection, Vector2 segmentA, Vector2 segmentB)
{
Vector2 segmentAToOrigin = rayOrigin - segmentA;
Vector2 segmentDirection = segmentB - segmentA;
float denominator = VectorE.PerpDot(rayDirection, segmentDirection);
float perpDotA = VectorE.PerpDot(rayDirection, segmentAToOrigin);
// Normalized direction gives more stable results
float perpDotB = VectorE.PerpDot(segmentDirection.normalized, segmentAToOrigin);
if (Mathf.Abs(denominator) < Geometry.Epsilon)
{
// Parallel
float segmentAProjection = -Vector2.Dot(rayDirection, segmentAToOrigin);
Vector2 originToSegmentB = segmentB - rayOrigin;
float segmentBProjection = Vector2.Dot(rayDirection, originToSegmentB);
if (Mathf.Abs(perpDotA) > Geometry.Epsilon || Mathf.Abs(perpDotB) > Geometry.Epsilon)
{
// Not collinear
if (segmentAProjection > -Geometry.Epsilon)
{
float distanceSqr = segmentAToOrigin.sqrMagnitude - segmentAProjection*segmentAProjection;
// distanceSqr can be negative
return distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr);
}
if (segmentBProjection > -Geometry.Epsilon)
{
float distanceSqr = originToSegmentB.sqrMagnitude - segmentBProjection*segmentBProjection;
// distanceSqr can be negative
return distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr);
}
if (segmentAProjection > segmentBProjection)
{
return Vector2.Distance(rayOrigin, segmentA);
}
return Vector2.Distance(rayOrigin, segmentB);
}
// Collinear
if (segmentAProjection > -Geometry.Epsilon || segmentBProjection > -Geometry.Epsilon)
{
// Point or segment intersection
return 0;
}
// No intersection
return segmentAProjection > segmentBProjection ? -segmentAProjection : -segmentBProjection;
}
// Not parallel
float rayDistance = perpDotB/denominator;
float segmentDistance = perpDotA/denominator;
if (rayDistance < -Geometry.Epsilon ||
segmentDistance < -Geometry.Epsilon || segmentDistance > 1 + Geometry.Epsilon)
{
// No intersection
bool codirected = Vector2.Dot(rayDirection, segmentDirection) > 0;
Vector2 segmentBToOrigin;
if (!codirected)
{
PTUtils.Swap(ref segmentA, ref segmentB);
segmentDirection = -segmentDirection;
segmentBToOrigin = segmentAToOrigin;
segmentAToOrigin = rayOrigin - segmentA;
segmentDistance = 1 - segmentDistance;
}
else
{
segmentBToOrigin = rayOrigin - segmentB;
}
float segmentAProjection = -Vector2.Dot(rayDirection, segmentAToOrigin);
float segmentBProjection = -Vector2.Dot(rayDirection, segmentBToOrigin);
bool segmentAOnRay = segmentAProjection > -Geometry.Epsilon;
bool segmentBOnRay = segmentBProjection > -Geometry.Epsilon;
if (segmentAOnRay && segmentBOnRay)
{
if (segmentDistance < 0)
{
Vector2 rayPoint = rayOrigin + rayDirection*segmentAProjection;
Vector2 segmentPoint = segmentA;
return Vector2.Distance(rayPoint, segmentPoint);
}
else
{
Vector2 rayPoint = rayOrigin + rayDirection*segmentBProjection;
Vector2 segmentPoint = segmentB;
return Vector2.Distance(rayPoint, segmentPoint);
}
}
else if (!segmentAOnRay && segmentBOnRay)
{
if (segmentDistance < 0)
{
Vector2 rayPoint = rayOrigin;
Vector2 segmentPoint = segmentA;
return Vector2.Distance(rayPoint, segmentPoint);
}
else if (segmentDistance > 1 + Geometry.Epsilon)
{
Vector2 rayPoint = rayOrigin + rayDirection*segmentBProjection;
Vector2 segmentPoint = segmentB;
return Vector2.Distance(rayPoint, segmentPoint);
}
else
{
Vector2 rayPoint = rayOrigin;
float originProjection = Vector2.Dot(segmentDirection, segmentAToOrigin);
Vector2 segmentPoint = segmentA + segmentDirection*originProjection/segmentDirection.sqrMagnitude;
return Vector2.Distance(rayPoint, segmentPoint);
}
}
else
{
// Not on ray
Vector2 rayPoint = rayOrigin;
float originProjection = Vector2.Dot(segmentDirection, segmentAToOrigin);
float sqrSegmentLength = segmentDirection.sqrMagnitude;
if (originProjection < 0)
{
return Vector2.Distance(rayPoint, segmentA);
}
else if (originProjection > sqrSegmentLength)
{
return Vector2.Distance(rayPoint, segmentB);
}
else
{
Vector2 segmentPoint = segmentA + segmentDirection*originProjection/sqrSegmentLength;
return Vector2.Distance(rayPoint, segmentPoint);
}
}
}
// Point intersection
return 0;
}