| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- // 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 <AnKi/Math/Common.h>
- namespace anki {
- // Euler angles. Used for rotations. It cannot describe a rotation accurately though
- template<typename T>
- 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<T, 3> 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<T>& q)
- {
- const T test = q.x * q.y + q.z * q.w;
- if(test > T(0.499))
- {
- y = T(2) * atan2<T>(q.x, q.w);
- z = kPi / T(2);
- x = T(0);
- }
- else if(test < T(-0.499))
- {
- y = -T(2) * atan2<T>(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>(T(2) * q.y * q.w - T(2) * q.x * q.z, T(1) - T(2) * sqy - T(2) * sqz);
- z = asin<T>(T(2) * test);
- x = atan2<T>(T(2) * q.x * q.w - T(2) * q.y * q.z, T(1) - T(2) * sqx - T(2) * sqz);
- }
- }
- explicit TEuler(const TMat<T, 3, 3>& 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<T>::value)
- {
- return String().sprintf("%f %f %f", x, y, z);
- }
- String toStringDegrees() const requires(std::is_floating_point<T>::value)
- {
- return String().sprintf("%f %f %f", toDegrees(x), toDegrees(y), toDegrees(z));
- }
- };
- using Euler = TEuler<F32>;
- using DEuler = TEuler<F64>;
- } // end namespace anki
|