Euler.h 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Math/Common.h>
  7. namespace anki {
  8. // Euler angles. Used for rotations. It cannot describe a rotation accurately though
  9. template<typename T>
  10. class TEuler
  11. {
  12. public:
  13. // Data //
  14. // Skip some warnings cause we really nead anonymous structs inside unions
  15. #if ANKI_COMPILER_MSVC
  16. # pragma warning(push)
  17. # pragma warning(disable : 4201)
  18. #elif ANKI_COMPILER_GCC_COMPATIBLE
  19. # pragma GCC diagnostic push
  20. # pragma GCC diagnostic ignored "-Wgnu-anonymous-struct"
  21. # pragma GCC diagnostic ignored "-Wnested-anon-types"
  22. #endif
  23. union
  24. {
  25. struct
  26. {
  27. T x; // Rotation around the x axiz
  28. T y; // Rotation around the y axiz
  29. T z; // Rotation around the z axiz
  30. };
  31. Array<T, 3> m_arr;
  32. };
  33. #if ANKI_COMPILER_MSVC
  34. # pragma warning(pop)
  35. #elif ANKI_COMPILER_GCC_COMPATIBLE
  36. # pragma GCC diagnostic pop
  37. #endif
  38. // Constructors //
  39. constexpr TEuler()
  40. : x(0)
  41. , y(0)
  42. , z(0)
  43. {
  44. }
  45. constexpr TEuler(const T x_, const T y_, const T z_)
  46. : x(x_)
  47. , y(y_)
  48. , z(z_)
  49. {
  50. }
  51. constexpr TEuler(const TEuler& b)
  52. : x(b.x)
  53. , y(b.y)
  54. , z(b.z)
  55. {
  56. }
  57. explicit TEuler(const TQuat<T>& q)
  58. {
  59. const T test = q.x * q.y + q.z * q.w;
  60. if(test > T(0.499))
  61. {
  62. y = T(2) * atan2<T>(q.x, q.w);
  63. z = kPi / T(2);
  64. x = T(0);
  65. }
  66. else if(test < T(-0.499))
  67. {
  68. y = -T(2) * atan2<T>(q.x, q.w);
  69. z = -kPi / T(2);
  70. x = T(0);
  71. }
  72. else
  73. {
  74. const T sqx = q.x * q.x;
  75. const T sqy = q.y * q.y;
  76. const T sqz = q.z * q.z;
  77. y = atan2<T>(T(2) * q.y * q.w - T(2) * q.x * q.z, T(1) - T(2) * sqy - T(2) * sqz);
  78. z = asin<T>(T(2) * test);
  79. x = atan2<T>(T(2) * q.x * q.w - T(2) * q.y * q.z, T(1) - T(2) * sqx - T(2) * sqz);
  80. }
  81. }
  82. explicit TEuler(const TMat<T, 3, 3>& m3)
  83. {
  84. if(m3(1, 0) > T(0.998))
  85. {
  86. // Singularity at north pole
  87. y = atan2(m3(0, 2), m3(2, 2));
  88. z = kPi / T(2);
  89. x = T(0);
  90. }
  91. else if(m3(1, 0) < T(-0.998))
  92. {
  93. // Singularity at south pole
  94. y = atan2(m3(0, 2), m3(2, 2));
  95. z = -kPi / T(2);
  96. x = T(0);
  97. }
  98. else
  99. {
  100. y = atan2(-m3(2, 0), m3(0, 0));
  101. z = asin(m3(1, 0));
  102. x = atan2(-m3(1, 2), m3(1, 1));
  103. }
  104. }
  105. // Accessors //
  106. T& operator[](const U i)
  107. {
  108. return m_arr[i];
  109. }
  110. T operator[](const U i) const
  111. {
  112. return m_arr[i];
  113. }
  114. // Operators with same type //
  115. TEuler& operator=(const TEuler& b)
  116. {
  117. x = b.x;
  118. y = b.y;
  119. z = b.z;
  120. return *this;
  121. }
  122. // Other //
  123. // Return lerp(this, v1, t)
  124. [[nodiscard]] TEuler lerp(const TEuler& v1, T t) const
  125. {
  126. TEuler out;
  127. for(U i = 0; i < 3; ++i)
  128. {
  129. out[i] = m_arr[i] * (T(1) - t) + v1.m_arr[i] * t;
  130. }
  131. return out;
  132. }
  133. String toString() const requires(std::is_floating_point<T>::value)
  134. {
  135. return String().sprintf("%f %f %f", x, y, z);
  136. }
  137. String toStringDegrees() const requires(std::is_floating_point<T>::value)
  138. {
  139. return String().sprintf("%f %f %f", toDegrees(x), toDegrees(y), toDegrees(z));
  140. }
  141. };
  142. using Euler = TEuler<F32>;
  143. using DEuler = TEuler<F64>;
  144. } // end namespace anki