// Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #pragma once #include namespace anki { // Euler angles. Used for rotations. It cannot describe a rotation accurately though template class TEuler { public: // Data // // Skip some warnings cause we really nead anonymous structs inside unions #if ANKI_COMPILER_MSVC # pragma warning(push) # pragma warning(disable : 4201) #elif ANKI_COMPILER_GCC_COMPATIBLE # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wgnu-anonymous-struct" # pragma GCC diagnostic ignored "-Wnested-anon-types" #endif union { struct { T x; // Rotation around the x axiz T y; // Rotation around the y axiz T z; // Rotation around the z axiz }; Array m_arr; }; #if ANKI_COMPILER_MSVC # pragma warning(pop) #elif ANKI_COMPILER_GCC_COMPATIBLE # pragma GCC diagnostic pop #endif // Constructors // constexpr TEuler() : x(0) , y(0) , z(0) { } constexpr TEuler(const T x_, const T y_, const T z_) : x(x_) , y(y_) , z(z_) { } constexpr TEuler(const TEuler& b) : x(b.x) , y(b.y) , z(b.z) { } explicit TEuler(const TQuat& q) { const T test = q.x * q.y + q.z * q.w; if(test > T(0.499)) { y = T(2) * atan2(q.x, q.w); z = kPi / T(2); x = T(0); } else if(test < T(-0.499)) { y = -T(2) * atan2(q.x, q.w); z = -kPi / T(2); x = T(0); } else { const T sqx = q.x * q.x; const T sqy = q.y * q.y; const T sqz = q.z * q.z; y = atan2(T(2) * q.y * q.w - T(2) * q.x * q.z, T(1) - T(2) * sqy - T(2) * sqz); z = asin(T(2) * test); x = atan2(T(2) * q.x * q.w - T(2) * q.y * q.z, T(1) - T(2) * sqx - T(2) * sqz); } } explicit TEuler(const TMat& m3) { if(m3(1, 0) > T(0.998)) { // Singularity at north pole y = atan2(m3(0, 2), m3(2, 2)); z = kPi / T(2); x = T(0); } else if(m3(1, 0) < T(-0.998)) { // Singularity at south pole y = atan2(m3(0, 2), m3(2, 2)); z = -kPi / T(2); x = T(0); } else { y = atan2(-m3(2, 0), m3(0, 0)); z = asin(m3(1, 0)); x = atan2(-m3(1, 2), m3(1, 1)); } } // Accessors // T& operator[](const U i) { return m_arr[i]; } T operator[](const U i) const { return m_arr[i]; } // Operators with same type // TEuler& operator=(const TEuler& b) { x = b.x; y = b.y; z = b.z; return *this; } // Other // // Return lerp(this, v1, t) [[nodiscard]] TEuler lerp(const TEuler& v1, T t) const { TEuler out; for(U i = 0; i < 3; ++i) { out[i] = m_arr[i] * (T(1) - t) + v1.m_arr[i] * t; } return out; } String toString() const requires(std::is_floating_point::value) { return String().sprintf("%f %f %f", x, y, z); } String toStringDegrees() const requires(std::is_floating_point::value) { return String().sprintf("%f %f %f", toDegrees(x), toDegrees(y), toDegrees(z)); } }; using Euler = TEuler; using DEuler = TEuler; } // end namespace anki