/* * 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 util { // 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. // // issues 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; } static quaternion angle_axis (T radians, vector<3,T> axis); static quaternion from_euler (vector<3,T>); /// build a quaternion that represents the rotation from a to b static quaternion from_to (vector<3,T> a, vector<3,T> b); /// build a quaternion that represents the rotation needed to look at /// a direction with a given up direction static quaternion look (vector<3,T> fwd, vector<3,T> up); matrix4 as_matrix (void) const; static constexpr quaternion identity (void) { return { 1, 0, 0, 0 }; } }; //------------------------------------------------------------------------- template struct arity,void> :std::integral_constant { }; /////////////////////////////////////////////////////////////////////////// template vector3 rotate (vector3, quaternion); //------------------------------------------------------------------------- template vector3 operator* (quaternion const q, vector3 const v) { return rotate (v, q); } /////////////////////////////////////////////////////////////////////////// template constexpr T norm2 (quaternion q) { return q.w * q.w + q.x * q.x + q.y * q.y + q.z * q.z; } //------------------------------------------------------------------------- template constexpr T norm (quaternion q) { return std::sqrt (norm2 (q)); } //------------------------------------------------------------------------- template constexpr bool is_normalised (quaternion q) { return almost_equal (T{1}, norm2 (q)); } //------------------------------------------------------------------------- template constexpr quaternion normalised (quaternion q) { return q / norm (q); } /////////////////////////////////////////////////////////////////////////// template quaternion conjugate (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