public final Quaternion interpolate(Quaternion q, float alpha) {
    // From "Advanced Animation and Rendering Techniques"
    // by Watt and Watt pg. 364, function as implemented appeared to be
    // incorrect. Fails to choose the same quaternion for the float
    // covering. Resulting in change of direction for rotations.
    // Fixed function to negate the first quaternion in the case that the
    // dot product of q and this is negative. Second case was not needed.
    float dot, s1, s2, om, sinom;

    dot = x * q.x + y * q.y + z * q.z + w * q.w;

    if (dot < 0) {
      q = q.negate();
      dot = -dot;
    }

    if ((1.0 - dot) > EPS) {
      om = (float) Math.acos(dot);
      sinom = (float) Math.sin(om);
      s1 = (float) Math.sin((1.0 - alpha) * om) / sinom;
      s2 = (float) Math.sin(alpha * om) / sinom;
    } else {
      s1 = 1.0f - alpha;
      s2 = alpha;
    }

    return new Quaternion(s1 * w + s2 * q.w, s1 * x + s2 * q.x, s1 * y + s2
        * q.y, s1 * z + s2 * q.z);
  }