| 1 | #include "scalar_constants.hpp" |
| 2 | |
| 3 | namespace glm |
| 4 | { |
| 5 | template<typename T, qualifier Q> |
| 6 | GLM_FUNC_QUALIFIER qua<T, Q> exp(qua<T, Q> const& q) |
| 7 | { |
| 8 | vec<3, T, Q> u(q.x, q.y, q.z); |
| 9 | T const Angle = glm::length(u); |
| 10 | if (Angle < epsilon<T>()) |
| 11 | return qua<T, Q>(); |
| 12 | |
| 13 | vec<3, T, Q> const v(u / Angle); |
| 14 | return qua<T, Q>(cos(Angle), sin(Angle) * v); |
| 15 | } |
| 16 | |
| 17 | template<typename T, qualifier Q> |
| 18 | GLM_FUNC_QUALIFIER qua<T, Q> log(qua<T, Q> const& q) |
| 19 | { |
| 20 | vec<3, T, Q> u(q.x, q.y, q.z); |
| 21 | T Vec3Len = length(u); |
| 22 | |
| 23 | if (Vec3Len < epsilon<T>()) |
| 24 | { |
| 25 | if(q.w > static_cast<T>(0)) |
| 26 | return qua<T, Q>::wxyz(log(q.w), static_cast<T>(0), static_cast<T>(0), static_cast<T>(0)); |
| 27 | else if(q.w < static_cast<T>(0)) |
| 28 | return qua<T, Q>::wxyz(log(-q.w), pi<T>(), static_cast<T>(0), static_cast<T>(0)); |
| 29 | else |
| 30 | return qua<T, Q>::wxyz(std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity()); |
| 31 | } |
| 32 | else |
| 33 | { |
| 34 | T t = atan(Vec3Len, T(q.w)) / Vec3Len; |
| 35 | T QuatLen2 = Vec3Len * Vec3Len + q.w * q.w; |
| 36 | return qua<T, Q>::wxyz(static_cast<T>(0.5) * log(QuatLen2), t * q.x, t * q.y, t * q.z); |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | template<typename T, qualifier Q> |
| 41 | GLM_FUNC_QUALIFIER qua<T, Q> pow(qua<T, Q> const& x, T y) |
| 42 | { |
| 43 | //Raising to the power of 0 should yield 1 |
| 44 | //Needed to prevent a division by 0 error later on |
| 45 | if(y > -epsilon<T>() && y < epsilon<T>()) |
| 46 | return qua<T, Q>::wxyz(1,0,0,0); |
| 47 | |
| 48 | //To deal with non-unit quaternions |
| 49 | T magnitude = sqrt(x.x * x.x + x.y * x.y + x.z * x.z + x.w *x.w); |
| 50 | |
| 51 | T Angle; |
| 52 | if(abs(x.w / magnitude) > cos_one_over_two<T>()) |
| 53 | { |
| 54 | //Scalar component is close to 1; using it to recover angle would lose precision |
| 55 | //Instead, we use the non-scalar components since sin() is accurate around 0 |
| 56 | |
| 57 | //Prevent a division by 0 error later on |
| 58 | T VectorMagnitude = x.x * x.x + x.y * x.y + x.z * x.z; |
| 59 | //Despite the compiler might say, we actually want to compare |
| 60 | //VectorMagnitude to 0. here; we could use denorm_int() compiling a |
| 61 | //project with unsafe maths optimizations might make the comparison |
| 62 | //always false, even when VectorMagnitude is 0. |
| 63 | if (VectorMagnitude < (std::numeric_limits<T>::min)()) { |
| 64 | //Equivalent to raising a real number to a power |
| 65 | return qua<T, Q>::wxyz(pow(x.w, y), 0, 0, 0); |
| 66 | } |
| 67 | |
| 68 | Angle = asin(sqrt(VectorMagnitude) / magnitude); |
| 69 | } |
| 70 | else |
| 71 | { |
| 72 | //Scalar component is small, shouldn't cause loss of precision |
| 73 | Angle = acos(x.w / magnitude); |
| 74 | } |
| 75 | |
| 76 | T NewAngle = Angle * y; |
| 77 | T Div = sin(NewAngle) / sin(Angle); |
| 78 | T Mag = pow(magnitude, y - static_cast<T>(1)); |
| 79 | return qua<T, Q>::wxyz(cos(NewAngle) * magnitude * Mag, x.x * Div * Mag, x.y * Div * Mag, x.z * Div * Mag); |
| 80 | } |
| 81 | |
| 82 | template<typename T, qualifier Q> |
| 83 | GLM_FUNC_QUALIFIER qua<T, Q> sqrt(qua<T, Q> const& x) |
| 84 | { |
| 85 | return pow(x, static_cast<T>(0.5)); |
| 86 | } |
| 87 | }//namespace glm |
| 88 | |
| 89 | |