slerp method

Quaternion slerp(
  1. Quaternion qb,
  2. double t
)

Implementation

Quaternion slerp(Quaternion qb, double t) {
  if (t == 0) return this;
  if (t == 1) return setFrom(qb);

  final x = _x, y = _y, z = _z, w = _w;

  // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/

  double cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;

  if (cosHalfTheta < 0) {
    _w = -qb._w;
    _x = -qb._x;
    _y = -qb._y;
    _z = -qb._z;

    cosHalfTheta = -cosHalfTheta;
  } else {
    setFrom(qb);
  }

  if (cosHalfTheta >= 1.0) {
    _w = w;
    _x = x;
    _y = y;
    _z = z;

    return this;
  }

  final sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;

  if (sqrSinHalfTheta <= MathUtils.epsilon) {
    final s = 1 - t;
    _w = s * w + t * _w;
    _x = s * x + t * _x;
    _y = s * y + t * _y;
    _z = s * z + t * _z;

    normalize();
    onChangeCallback();

    return this;
  }

  final sinHalfTheta = math.sqrt(sqrSinHalfTheta);
  final halfTheta = math.atan2(sinHalfTheta, cosHalfTheta);
  final ratioA = math.sin((1 - t) * halfTheta) / sinHalfTheta,
      ratioB = math.sin(t * halfTheta) / sinHalfTheta;

  _w = (w * ratioA + _w * ratioB);
  _x = (x * ratioA + _x * ratioB);
  _y = (y * ratioA + _y * ratioB);
  _z = (z * ratioA + _z * ratioB);

  onChangeCallback();

  return this;
}