/******************************************************************************
* Copyright (C) Ultraleap, Inc. 2011-2021. *
* *
* Use subject to the terms of the Apache License 2.0 available at *
* http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
* between Ultraleap and you, your company or other organization. *
******************************************************************************/
using System;
using UnityEngine;
namespace Leap.Unity.Animation
{
///
/// Represents a spline that travels from one point in space
/// to another over a specified time frame. The two endpoints
/// are specified, as well as the instantaneous velocity at
/// these two endpoints.
///
/// You may ask for the position or the velocity at any time
/// during the splines duration.
///
[Serializable]
public struct HermiteSpline3
{
public float t0, t1;
public Vector3 pos0, pos1;
public Vector3 vel0, vel1;
///
/// Constructs a spline by specifying the positions of the
/// two endpoints. The velocity at each endpoint is zero,
/// and the time range of the spline is 0 to 1.
///
public HermiteSpline3(Vector3 pos0, Vector3 pos1)
{
t0 = 0;
t1 = 1;
vel0 = default(Vector3);
vel1 = default(Vector3);
this.pos0 = pos0;
this.pos1 = pos1;
}
///
/// Constructs a spline by specifying the positions and
/// velocities of the two endpoints. The time range of
/// the spline is 0 to 1.
///
public HermiteSpline3(Vector3 pos0, Vector3 pos1, Vector3 vel0, Vector3 vel1)
{
t0 = 0;
t1 = 1;
this.vel0 = vel0;
this.vel1 = vel1;
this.pos0 = pos0;
this.pos1 = pos1;
}
///
/// Constructs a spline by specifying the positions and
/// velocities of the two endpoints. The time range of
/// the spline is 0 to length.
///
public HermiteSpline3(Vector3 pos0, Vector3 pos1, Vector3 vel0, Vector3 vel1, float length)
{
t0 = 0;
t1 = length;
this.vel0 = vel0;
this.vel1 = vel1;
this.pos0 = pos0;
this.pos1 = pos1;
}
///
/// Constructs a spline by specifying the positions,
/// velocities, and times of the endpoints.
///
public HermiteSpline3(float t0, float t1, Vector3 pos0, Vector3 pos1, Vector3 vel0, Vector3 vel1)
{
this.t0 = t0;
this.t1 = t1;
this.vel0 = vel0;
this.vel1 = vel1;
this.pos0 = pos0;
this.pos1 = pos1;
}
///
/// Gets the position at time t along this spline.
/// The time is clamped to t0, but can extrapolate
/// beyond t1.
///
public Vector3 PositionAt(float t)
{
if (t > t1)
{
float i = ((t - t0) / (t1 - t0)) - 1f;
return pos1 + (vel1 * i);
}
else
{
float i = Mathf.Clamp01((t - t0) / (t1 - t0));
float i2 = i * i;
float i3 = i2 * i;
Vector3 h00 = (2 * i3 - 3 * i2 + 1) * pos0;
Vector3 h10 = (i3 - 2 * i2 + i) * (t1 - t0) * vel0;
Vector3 h01 = (-2 * i3 + 3 * i2) * pos1;
Vector3 h11 = (i3 - i2) * (t1 - t0) * vel1;
return h00 + h10 + h01 + h11;
}
}
///
/// Gets the first derivative of position at time t.
/// The time is clamped within the t0 - t1 range
/// (thus velocity is unaffected by extrapolation).
///
public Vector3 VelocityAt(float t)
{
float C00 = t1 - t0;
float C1 = 1.0f / C00;
float i, i2;
float i_, i2_, i3_;
{
i = Mathf.Clamp01((t - t0) * C1);
i_ = C1;
i2 = i * i;
i2_ = 2 * i * i_;
i3_ = i2_ * i + i_ * i2;
}
Vector3 h00_ = (i3_ * 2 - i2_ * 3) * pos0;
Vector3 h10_ = (i3_ - 2 * i2_ + i_) * C00 * vel0;
Vector3 h01_ = (i2_ * 3 - 2 * i3_) * pos1;
Vector3 h11_ = (i3_ - i2_) * C00 * vel1;
return h00_ + h01_ + h10_ + h11_;
}
///
/// Gets both the position and the first derivative of position
/// at time ti. The time is clamped within the t0 - t1 range.
/// If you wish to extrapolate, use PositionAt(t).
///
public void PositionAndVelAt(float t, out Vector3 position, out Vector3 velocity)
{
float C00 = t1 - t0;
float C1 = 1.0f / C00;
float i, i2, i3;
float i_, i2_, i3_;
{
i = Mathf.Clamp01((t - t0) * C1);
i_ = C1;
i2 = i * i;
i2_ = 2 * i * i_;
i3 = i2 * i;
i3_ = i2_ * i + i_ * i2;
}
Vector3 h00 = (2 * i3 - 3 * i2 + 1) * pos0;
Vector3 h00_ = (i3_ * 2 - i2_ * 3) * pos0;
Vector3 h10 = (i3 - 2 * i2 + i) * C00 * vel0;
Vector3 h10_ = (i3_ - 2 * i2_ + i_) * C00 * vel0;
Vector3 h01 = (3 * i2 - 2 * i3) * pos1;
Vector3 h01_ = (i2_ * 3 - 2 * i3_) * pos1;
Vector3 h11 = (i3 - i2) * C00 * vel1;
Vector3 h11_ = (i3_ - i2_) * C00 * vel1;
position = h00 + h01 + h10 + h11;
velocity = h00_ + h01_ + h10_ + h11_;
}
}
}