using UnityEngine.Scripting.APIUpdating;
namespace UnityEngine.U2D.IK
{
///
/// Utility for 2D based Cyclic Coordinate Descent (CCD) IK Solver.
///
[MovedFrom("UnityEngine.Experimental.U2D.IK")]
public static class CCD2D
{
///
/// Solve IK Chain based on CCD.
///
/// Target position.
/// Forward vector for solver.
/// Solver iteration count.
/// Target position's tolerance.
/// Velocity towards target position.
/// Chain positions.
/// Returns true if solver successfully completes within iteration limit. False otherwise.
public static bool Solve(Vector3 targetPosition, Vector3 forward, int solverLimit, float tolerance, float velocity, ref Vector3[] positions)
{
var last = positions.Length - 1;
var iterations = 0;
var sqrTolerance = tolerance * tolerance;
var sqrDistanceToTarget = (targetPosition - positions[last]).sqrMagnitude;
while (sqrDistanceToTarget > sqrTolerance)
{
DoIteration(targetPosition, forward, last, velocity, ref positions);
sqrDistanceToTarget = (targetPosition - positions[last]).sqrMagnitude;
if (++iterations >= solverLimit)
break;
}
return iterations != 0;
}
static void DoIteration(Vector3 targetPosition, Vector3 forward, int last, float velocity, ref Vector3[] positions)
{
for (var i = last - 1; i >= 0; --i)
{
var toTarget = targetPosition - positions[i];
var toLast = positions[last] - positions[i];
var angle = Vector3.SignedAngle(toLast, toTarget, forward);
angle = Mathf.Lerp(0f, angle, velocity);
var deltaRotation = Quaternion.AngleAxis(angle, forward);
for (var j = last; j > i; --j)
positions[j] = RotatePositionFrom(positions[j], positions[i], deltaRotation);
}
}
static Vector3 RotatePositionFrom(Vector3 position, Vector3 pivot, Quaternion rotation)
{
var v = position - pivot;
v = rotation * v;
return pivot + v;
}
}
}