/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2011-2018 Danny Robson */ #ifndef __UTIL_QUATERNION_HPP #define __UTIL_QUATERNION_HPP #include "coord/traits.hpp" #include "maths.hpp" #include "vector.hpp" #include "matrix.hpp" #include namespace cruft { /// Represents a quaternion value. /// /// Quaternion's are _just_ different enough to other coord types that we /// special case as a distinct POD type and provide many of the same /// functions as distinct declarations. /// /// Considerations include: /// * strictly 4 dimensions /// * scalar operations sometimes don't make sense on the w component /// * objects must be normalised to make sense template struct quaternion { T w, x, y, z; static constexpr std::size_t size (void) { return 4; } /// Construct a quaternion that represents a rotation of `radians` /// around the unit-vector `axis`. static quaternion angle_axis (T radians, vector<3,T> axis); /// Construct a quaternion that represents a sequence of euler angle /// rotations in radians. Equivalent to the concatentation of x, y, /// and then z rotations. static quaternion from_euler (vector<3,T>); /// Constructs a quaternion that represents the rotation of a unit /// vector `a` to the unit vector `b`. static quaternion from_to (vector<3,T> a, vector<3,T> b); /// Constructs a quaternion that represents the rotation needed to /// look along the unit vector `fwd` with the unit vector `up` /// denoting the upward direction. static quaternion look (vector<3,T> fwd, vector<3,T> up); /// Converts a rotation quaternion into an equivalent matrix form. matrix4 as_matrix (void) const; /// Negate all components quaternion operator- () const noexcept; /// Constructs a identity rotation quaternion. static constexpr quaternion identity (void) { return { 1, 0, 0, 0 }; } }; //------------------------------------------------------------------------- template struct arity,void> :std::integral_constant { }; /////////////////////////////////////////////////////////////////////////// /// Returns the result of rotating the unit vector `dir` using the /// quaternion `q`. template vector3 rotate (vector3 dir, quaternion q); ///------------------------------------------------------------------------ /// Returns the result of rotating the unit vector `v` by the quaternion `q`. template vector3 operator* (quaternion const q, vector3 const v) { return rotate (v, q); } /////////////////////////////////////////////////////////////////////////// /// Returns the square of the L2 norm of the quaternion `q`. template constexpr T norm2 (quaternion q) { return q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z; } ///------------------------------------------------------------------------ /// Returns the L2 norm of the quaternion `q`. template constexpr T norm (quaternion q) { return std::sqrt (norm2 (q)); } ///------------------------------------------------------------------------ /// Returns true if the quaternion has a unit L2 norm. template constexpr bool is_normalised (quaternion q) { return almost_equal (T{1}, norm2 (q)); } ///------------------------------------------------------------------------ /// Returns the normalised form of quaternion `q`. template constexpr quaternion normalised (quaternion q) { return q / norm (q); } /////////////////////////////////////////////////////////////////////////// template quaternion slerp (quaternion a, quaternion b, T t); //------------------------------------------------------------------------- template quaternion nlerp (quaternion a, quaternion b, T t); /////////////////////////////////////////////////////////////////////////// template quaternion conjugate (quaternion); /////////////////////////////////////////////////////////////////////////// template T dot (quaternion, quaternion); /////////////////////////////////////////////////////////////////////////// template quaternion operator* (quaternion, T); template quaternion operator* (T, quaternion); /////////////////////////////////////////////////////////////////////////// template quaternion operator+ (quaternion, quaternion); //------------------------------------------------------------------------- template quaternion operator* (quaternion, quaternion); //------------------------------------------------------------------------- template quaternion& operator*= (quaternion&, quaternion); //------------------------------------------------------------------------- template quaternion operator/ (quaternion, quaternion); //------------------------------------------------------------------------- template constexpr quaternion operator/ (quaternion q, T t) { return { q.w / t, q.x / t, q.y / t, q.z / t }; } /////////////////////////////////////////////////////////////////////////// template matrix<4,4,T> operator* (quaternion q, matrix<4,4,T> m) { return q.as_matrix () * m; } //------------------------------------------------------------------------- template matrix<4,4,T> operator* (matrix<4,4,T> m, quaternion q) { return m * q.as_matrix (); } /////////////////////////////////////////////////////////////////////////// template constexpr bool operator== (quaternion a, quaternion b) { return exactly_equal (a.w, b.w) && exactly_equal (a.x, b.x) && exactly_equal (a.y, b.y) && exactly_equal (a.z, b.z); } //------------------------------------------------------------------------- template bool almost_equal (quaternion, quaternion); /////////////////////////////////////////////////////////////////////////// typedef quaternion quaternionf; typedef quaternion quaterniond; /////////////////////////////////////////////////////////////////////////// template std::ostream& operator<< (std::ostream&, quaternion); } #endif