Code/HumanoidMocap/Core/Motion/CaptureLegReach.cs
using System;

namespace HumanoidMocapX.Core.Motion;

using Vector3 = System.Numerics.Vector3;

/// <summary>Leaves a small knee bend when moving the pelvis to reach captured foot targets.</summary>
internal static class CaptureLegReach
{
	// Exact full extension is singular: a millimetre of ankle travel can unfold the knee
	// by centimetres. Reserve half a percent of reach and enter the correction smoothly.
	internal const float ReachFraction = .995f;

	internal static float Lowering( Vector3 hipToFoot, Vector3 up, float length )
	{
		var vertical = Vector3.Dot( hipToFoot, up );
		var horizontal = hipToFoot - up * vertical;
		var reach = length * ReachFraction;
		if ( length <= 0 || vertical <= 0 || horizontal.LengthSquared() >= reach * reach ) return 0;

		var deficit = vertical - MathF.Sqrt( reach * reach - horizontal.LengthSquared() );
		var ease = length * .01f;
		// Smooth positive part, evaluated without subtracting two nearly equal numbers.
		var diagonal = MathF.Sqrt( deficit * deficit + ease * ease );
		return deficit >= 0 ? (deficit + diagonal) * .5f : ease * ease / (2 * (diagonal - deficit));
	}
}