quaternion.inl 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*
  2. ---------------------------------------------------------------------------
  3. Open Asset Import Library (assimp)
  4. ---------------------------------------------------------------------------
  5. Copyright (c) 2006-2025, assimp team
  6. All rights reserved.
  7. Redistribution and use of this software in source and binary forms,
  8. with or without modification, are permitted provided that the following
  9. conditions are met:
  10. * Redistributions of source code must retain the above
  11. copyright notice, this list of conditions and the
  12. following disclaimer.
  13. * Redistributions in binary form must reproduce the above
  14. copyright notice, this list of conditions and the
  15. following disclaimer in the documentation and/or other
  16. materials provided with the distribution.
  17. * Neither the name of the assimp team, nor the names of its
  18. contributors may be used to endorse or promote products
  19. derived from this software without specific prior
  20. written permission of the assimp team.
  21. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  25. OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  26. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  27. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  28. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  29. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  31. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. ---------------------------------------------------------------------------
  33. */
  34. /** @file quaternion.inl
  35. * @brief Inline implementation of aiQuaterniont<TReal> operators
  36. */
  37. #pragma once
  38. #ifndef AI_QUATERNION_INL_INC
  39. #define AI_QUATERNION_INL_INC
  40. #ifdef __GNUC__
  41. # pragma GCC system_header
  42. #endif
  43. #ifdef __cplusplus
  44. #include <assimp/quaternion.h>
  45. #include <cmath>
  46. // ------------------------------------------------------------------------------------------------
  47. /** Transformation of a quaternion by a 4x4 matrix */
  48. template <typename TReal>
  49. AI_FORCE_INLINE
  50. aiQuaterniont<TReal> operator * (const aiMatrix4x4t<TReal>& pMatrix, const aiQuaterniont<TReal>& pQuaternion) {
  51. aiQuaterniont<TReal> res;
  52. res.x = pMatrix.a1 * pQuaternion.x + pMatrix.a2 * pQuaternion.y + pMatrix.a3 * pQuaternion.z + pMatrix.a4 * pQuaternion.w;
  53. res.y = pMatrix.b1 * pQuaternion.x + pMatrix.b2 * pQuaternion.y + pMatrix.b3 * pQuaternion.z + pMatrix.b4 * pQuaternion.w;
  54. res.z = pMatrix.c1 * pQuaternion.x + pMatrix.c2 * pQuaternion.y + pMatrix.c3 * pQuaternion.z + pMatrix.c4 * pQuaternion.w;
  55. res.w = pMatrix.d1 * pQuaternion.x + pMatrix.d2 * pQuaternion.y + pMatrix.d3 * pQuaternion.z + pMatrix.d4 * pQuaternion.w;
  56. return res;
  57. }
  58. // ---------------------------------------------------------------------------
  59. template<typename TReal>
  60. bool aiQuaterniont<TReal>::operator== (const aiQuaterniont& o) const
  61. {
  62. return x == o.x && y == o.y && z == o.z && w == o.w;
  63. }
  64. // ---------------------------------------------------------------------------
  65. template<typename TReal>
  66. bool aiQuaterniont<TReal>::operator!= (const aiQuaterniont& o) const
  67. {
  68. return !(*this == o);
  69. }
  70. // ------------------------------------------------------------------------------------------------
  71. template <typename TReal>
  72. AI_FORCE_INLINE
  73. aiQuaterniont<TReal>& aiQuaterniont<TReal>::operator *= (const aiMatrix4x4t<TReal>& mat){
  74. return (*this = mat * (*this));
  75. }
  76. // ------------------------------------------------------------------------------------------------
  77. // ---------------------------------------------------------------------------
  78. template<typename TReal>
  79. inline bool aiQuaterniont<TReal>::Equal(const aiQuaterniont& o, TReal epsilon) const {
  80. return
  81. std::abs(x - o.x) <= epsilon &&
  82. std::abs(y - o.y) <= epsilon &&
  83. std::abs(z - o.z) <= epsilon &&
  84. std::abs(w - o.w) <= epsilon;
  85. }
  86. // ---------------------------------------------------------------------------
  87. // Constructs a quaternion from a rotation matrix
  88. template<typename TReal>
  89. inline aiQuaterniont<TReal>::aiQuaterniont( const aiMatrix3x3t<TReal> &pRotMatrix)
  90. {
  91. TReal t = pRotMatrix.a1 + pRotMatrix.b2 + pRotMatrix.c3;
  92. // large enough
  93. if( t > static_cast<TReal>(0))
  94. {
  95. TReal s = std::sqrt(1 + t) * static_cast<TReal>(2.0);
  96. x = (pRotMatrix.c2 - pRotMatrix.b3) / s;
  97. y = (pRotMatrix.a3 - pRotMatrix.c1) / s;
  98. z = (pRotMatrix.b1 - pRotMatrix.a2) / s;
  99. w = static_cast<TReal>(0.25) * s;
  100. } // else we have to check several cases
  101. else if( pRotMatrix.a1 > pRotMatrix.b2 && pRotMatrix.a1 > pRotMatrix.c3 )
  102. {
  103. // Column 0:
  104. TReal s = std::sqrt( static_cast<TReal>(1.0) + pRotMatrix.a1 - pRotMatrix.b2 - pRotMatrix.c3) * static_cast<TReal>(2.0);
  105. x = static_cast<TReal>(0.25) * s;
  106. y = (pRotMatrix.b1 + pRotMatrix.a2) / s;
  107. z = (pRotMatrix.a3 + pRotMatrix.c1) / s;
  108. w = (pRotMatrix.c2 - pRotMatrix.b3) / s;
  109. }
  110. else if( pRotMatrix.b2 > pRotMatrix.c3)
  111. {
  112. // Column 1:
  113. TReal s = std::sqrt( static_cast<TReal>(1.0) + pRotMatrix.b2 - pRotMatrix.a1 - pRotMatrix.c3) * static_cast<TReal>(2.0);
  114. x = (pRotMatrix.b1 + pRotMatrix.a2) / s;
  115. y = static_cast<TReal>(0.25) * s;
  116. z = (pRotMatrix.c2 + pRotMatrix.b3) / s;
  117. w = (pRotMatrix.a3 - pRotMatrix.c1) / s;
  118. } else
  119. {
  120. // Column 2:
  121. TReal s = std::sqrt( static_cast<TReal>(1.0) + pRotMatrix.c3 - pRotMatrix.a1 - pRotMatrix.b2) * static_cast<TReal>(2.0);
  122. x = (pRotMatrix.a3 + pRotMatrix.c1) / s;
  123. y = (pRotMatrix.c2 + pRotMatrix.b3) / s;
  124. z = static_cast<TReal>(0.25) * s;
  125. w = (pRotMatrix.b1 - pRotMatrix.a2) / s;
  126. }
  127. }
  128. // ---------------------------------------------------------------------------
  129. // Construction from euler angles
  130. template<typename TReal>
  131. inline aiQuaterniont<TReal>::aiQuaterniont( TReal fPitch, TReal fYaw, TReal fRoll )
  132. {
  133. const TReal fSinPitch(std::sin(fPitch*static_cast<TReal>(0.5)));
  134. const TReal fCosPitch(std::cos(fPitch*static_cast<TReal>(0.5)));
  135. const TReal fSinYaw(std::sin(fYaw*static_cast<TReal>(0.5)));
  136. const TReal fCosYaw(std::cos(fYaw*static_cast<TReal>(0.5)));
  137. const TReal fSinRoll(std::sin(fRoll*static_cast<TReal>(0.5)));
  138. const TReal fCosRoll(std::cos(fRoll*static_cast<TReal>(0.5)));
  139. const TReal fCosPitchCosYaw(fCosPitch*fCosYaw);
  140. const TReal fSinPitchSinYaw(fSinPitch*fSinYaw);
  141. x = fSinRoll * fCosPitchCosYaw - fCosRoll * fSinPitchSinYaw;
  142. y = fCosRoll * fSinPitch * fCosYaw + fSinRoll * fCosPitch * fSinYaw;
  143. z = fCosRoll * fCosPitch * fSinYaw - fSinRoll * fSinPitch * fCosYaw;
  144. w = fCosRoll * fCosPitchCosYaw + fSinRoll * fSinPitchSinYaw;
  145. }
  146. // ---------------------------------------------------------------------------
  147. // Returns a matrix representation of the quaternion
  148. template<typename TReal>
  149. inline aiMatrix3x3t<TReal> aiQuaterniont<TReal>::GetMatrix() const
  150. {
  151. aiMatrix3x3t<TReal> resMatrix;
  152. resMatrix.a1 = static_cast<TReal>(1.0) - static_cast<TReal>(2.0) * (y * y + z * z);
  153. resMatrix.a2 = static_cast<TReal>(2.0) * (x * y - z * w);
  154. resMatrix.a3 = static_cast<TReal>(2.0) * (x * z + y * w);
  155. resMatrix.b1 = static_cast<TReal>(2.0) * (x * y + z * w);
  156. resMatrix.b2 = static_cast<TReal>(1.0) - static_cast<TReal>(2.0) * (x * x + z * z);
  157. resMatrix.b3 = static_cast<TReal>(2.0) * (y * z - x * w);
  158. resMatrix.c1 = static_cast<TReal>(2.0) * (x * z - y * w);
  159. resMatrix.c2 = static_cast<TReal>(2.0) * (y * z + x * w);
  160. resMatrix.c3 = static_cast<TReal>(1.0) - static_cast<TReal>(2.0) * (x * x + y * y);
  161. return resMatrix;
  162. }
  163. // ---------------------------------------------------------------------------
  164. // Construction from an axis-angle pair
  165. template<typename TReal>
  166. inline aiQuaterniont<TReal>::aiQuaterniont( aiVector3t<TReal> axis, TReal angle)
  167. {
  168. axis.Normalize();
  169. const TReal sin_a = std::sin( angle / 2 );
  170. const TReal cos_a = std::cos( angle / 2 );
  171. x = axis.x * sin_a;
  172. y = axis.y * sin_a;
  173. z = axis.z * sin_a;
  174. w = cos_a;
  175. }
  176. // ---------------------------------------------------------------------------
  177. // Construction from am existing, normalized quaternion
  178. template<typename TReal>
  179. inline aiQuaterniont<TReal>::aiQuaterniont( aiVector3t<TReal> normalized)
  180. {
  181. x = normalized.x;
  182. y = normalized.y;
  183. z = normalized.z;
  184. const TReal t = static_cast<TReal>(1.0) - (x*x) - (y*y) - (z*z);
  185. if (t < static_cast<TReal>(0.0)) {
  186. w = static_cast<TReal>(0.0);
  187. }
  188. else w = std::sqrt (t);
  189. }
  190. // ---------------------------------------------------------------------------
  191. // Performs a spherical interpolation between two quaternions
  192. // Implementation adopted from the gmtl project. All others I found on the net fail in some cases.
  193. // Congrats, gmtl!
  194. template<typename TReal>
  195. inline void aiQuaterniont<TReal>::Interpolate( aiQuaterniont& pOut, const aiQuaterniont& pStart, const aiQuaterniont& pEnd, TReal pFactor)
  196. {
  197. // calc cosine theta
  198. TReal cosom = pStart.x * pEnd.x + pStart.y * pEnd.y + pStart.z * pEnd.z + pStart.w * pEnd.w;
  199. // adjust signs (if necessary)
  200. aiQuaterniont end = pEnd;
  201. if( cosom < static_cast<TReal>(0.0))
  202. {
  203. cosom = -cosom;
  204. end.x = -end.x; // Reverse all signs
  205. end.y = -end.y;
  206. end.z = -end.z;
  207. end.w = -end.w;
  208. }
  209. // Calculate coefficients
  210. TReal sclp, sclq;
  211. if ((static_cast<TReal>(1.0) - cosom) > ai_epsilon) // 0.0001 -> some epsillon
  212. {
  213. // Standard case (slerp)
  214. TReal omega, sinom;
  215. omega = std::acos( cosom); // extract theta from dot product's cos theta
  216. sinom = std::sin( omega);
  217. sclp = std::sin( (static_cast<TReal>(1.0) - pFactor) * omega) / sinom;
  218. sclq = std::sin( pFactor * omega) / sinom;
  219. } else
  220. {
  221. // Very close, do linear interp (because it's faster)
  222. sclp = static_cast<TReal>(1.0) - pFactor;
  223. sclq = pFactor;
  224. }
  225. pOut.x = sclp * pStart.x + sclq * end.x;
  226. pOut.y = sclp * pStart.y + sclq * end.y;
  227. pOut.z = sclp * pStart.z + sclq * end.z;
  228. pOut.w = sclp * pStart.w + sclq * end.w;
  229. }
  230. // ---------------------------------------------------------------------------
  231. template<typename TReal>
  232. inline aiQuaterniont<TReal>& aiQuaterniont<TReal>::Normalize()
  233. {
  234. // compute the magnitude and divide through it
  235. const TReal mag = std::sqrt(x*x + y*y + z*z + w*w);
  236. if (mag)
  237. {
  238. const TReal invMag = static_cast<TReal>(1.0)/mag;
  239. x *= invMag;
  240. y *= invMag;
  241. z *= invMag;
  242. w *= invMag;
  243. }
  244. return *this;
  245. }
  246. // ---------------------------------------------------------------------------
  247. template<typename TReal>
  248. inline aiQuaterniont<TReal> aiQuaterniont<TReal>::operator* (const aiQuaterniont& t) const
  249. {
  250. return aiQuaterniont(w*t.w - x*t.x - y*t.y - z*t.z,
  251. w*t.x + x*t.w + y*t.z - z*t.y,
  252. w*t.y + y*t.w + z*t.x - x*t.z,
  253. w*t.z + z*t.w + x*t.y - y*t.x);
  254. }
  255. // ---------------------------------------------------------------------------
  256. template<typename TReal>
  257. inline aiQuaterniont<TReal>& aiQuaterniont<TReal>::Conjugate ()
  258. {
  259. x = -x;
  260. y = -y;
  261. z = -z;
  262. return *this;
  263. }
  264. // ---------------------------------------------------------------------------
  265. template<typename TReal>
  266. inline aiVector3t<TReal> aiQuaterniont<TReal>::Rotate (const aiVector3t<TReal>& v) const
  267. {
  268. aiQuaterniont q2(0.f,v.x,v.y,v.z), q = *this, qinv = q;
  269. qinv.Conjugate();
  270. q = q*q2*qinv;
  271. return aiVector3t<TReal>(q.x,q.y,q.z);
  272. }
  273. #endif
  274. #endif // AI_QUATERNION_INL_INC