using Unity.Mathematics;
namespace UnityEngine.Splines
{
///
/// Assorted utility functions for math equations commonly used when working with Splines.
///
public static class SplineMath
{
///
/// Returns the parameterization of a ray line projection. The parameter will be negative if the nearest point
/// between the ray/line is negative to 'lineOrigin', and greater than 1 if nearest intersection is past the end
/// off the line segment (lineOrigin + lineDir).
///
/// The ray origin point.
/// The ray direction (normalized vector).
/// Line segment first point.
/// Line segment direction (with magnitude).
/// The parameter of a ray line projection.
public static float RayLineParameter(float3 ro, float3 rd, float3 lineOrigin, float3 lineDir)
{
var v0 = ro - lineOrigin;
var v1 = math.cross(rd, math.cross(rd, lineDir));
// the parameter of a ray to line projection will be negative if the intersection is negative to line
// direction from 'a', and greater than 1 if intersection is past the line segment end 'b'
return math.dot(v0, v1) / math.dot(lineDir, v1);
}
///
/// Returns the shortest distance between a ray and line segment as a direction and magnitude.
///
/// The ray origin point.
/// The ray direction (normalized vector).
/// The line start point.
/// The line end point.
/// Returns the shortest distance between a ray and line segment as a direction and magnitude.
public static float3 RayLineDistance(float3 ro, float3 rd, float3 a, float3 b)
{
var points = RayLineNearestPoint(ro, rd, a, b);
return points.linePoint - points.rayPoint;
}
///
/// Returns the nearest points between a ray and line segment.
///
/// The ray origin point.
/// The ray direction (normalized vector).
/// The line start point.
/// The line end point.
/// Returns the nearest points between a ray and line segment.
public static (float3 rayPoint, float3 linePoint) RayLineNearestPoint(
float3 ro,
float3 rd,
float3 a,
float3 b)
{
return RayLineNearestPoint(ro, rd, a, b, out _, out _);
}
///
/// Returns the nearest points on a ray and a line segment to one another.
///
/// The ray origin point.
/// The ray direction (normalized vector).
/// The line start point.
/// The line end point.
/// The signed distance between point 'ro' and the projection of the line segment along the ray.
/// The signed distance between point 'a' and the projection of point 'p' on the line segment.
/// Returns the nearest points on a ray and a line segment to one another.
public static (float3 rayPoint, float3 linePoint) RayLineNearestPoint(
float3 ro,
float3 rd,
float3 a,
float3 b,
out float rayParam,
out float lineParam)
{
var lineDir = b - a;
lineParam = RayLineParameter(ro, rd, a, lineDir);
var linePoint = a + lineDir * math.saturate(lineParam);
rayParam = math.dot(rd, linePoint - ro);
var rayPoint = ro + rd * rayParam;
return (rayPoint, linePoint);
}
///
/// Returns the nearest point on a finite line segment to a point.
///
/// The point to compare to.
/// The line start point.
/// The line end point.
/// The signed distance between point 'a' and the projection of point 'p' on the line segment.
/// The nearest point on a line segment to another point.
public static float3 PointLineNearestPoint(float3 p, float3 a, float3 b, out float lineParam)
{
var dir = b - a;
var len = math.length(dir);
var nrm = math.select(0f, dir * (1f / len), len > math.FLT_MIN_NORMAL);
lineParam = math.dot(nrm, p - a);
return a + nrm * math.clamp(lineParam, 0f, len);
}
///
/// Gets the distance from a point to a line segment.
///
/// The point to compare against.
/// The start point of the line segment.
/// The end point of the line segment.
/// Returns the distance of the closest line from a point to a line segment.
public static float DistancePointLine(float3 p, float3 a, float3 b)
{
return math.length(PointLineNearestPoint(p, a, b, out _) - p);
}
internal static float GetUnitCircleTangentLength()
{
// https://mechanicalexpressions.com/explore/geometric-modeling/circle-spline-approximation.pdf
return (4f * (math.sqrt(2f) - 1f)) / 3f;
}
}
}