quat_operations.hpp 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573
  1. #ifndef BOOST_QVM_QUAT_OPERATIONS
  2. #define BOOST_QVM_QUAT_OPERATIONS
  3. // Copyright 2008-2022 Emil Dotchevski and Reverge Studios, Inc.
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #include <boost/qvm/detail/quat_assign.hpp>
  7. #include <boost/qvm/deduce_quat.hpp>
  8. #include <boost/qvm/mat_traits.hpp>
  9. #include <boost/qvm/scalar_traits.hpp>
  10. #include <boost/qvm/math.hpp>
  11. #include <boost/qvm/assert.hpp>
  12. #include <boost/qvm/error.hpp>
  13. #include <boost/qvm/throw_exception.hpp>
  14. #include <boost/qvm/to_string.hpp>
  15. namespace boost { namespace qvm {
  16. namespace
  17. qvm_detail
  18. {
  19. BOOST_QVM_INLINE_CRITICAL
  20. void const *
  21. get_valid_ptr_quat_operations()
  22. {
  23. static int const obj=0;
  24. return &obj;
  25. }
  26. }
  27. ////////////////////////////////////////////////
  28. namespace
  29. msvc_parse_bug_workaround
  30. {
  31. template <class A,class B>
  32. struct
  33. quats
  34. {
  35. static bool const value=is_quat<A>::value && is_quat<B>::value;
  36. };
  37. }
  38. template <class A>
  39. inline
  40. typename enable_if_c<
  41. is_quat<A>::value,
  42. std::string>::type
  43. to_string( A const & a )
  44. {
  45. using namespace qvm_to_string_detail;
  46. return '('+
  47. to_string(quat_traits<A>::template read_element<0>(a))+','+
  48. to_string(quat_traits<A>::template read_element<1>(a))+','+
  49. to_string(quat_traits<A>::template read_element<2>(a))+','+
  50. to_string(quat_traits<A>::template read_element<3>(a))+')';
  51. }
  52. ////////////////////////////////////////////////
  53. template <class A,class B,class Cmp>
  54. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  55. typename enable_if_c<
  56. is_quat<A>::value && is_quat<B>::value,
  57. bool>::type
  58. cmp( A const & a, B const & b, Cmp f )
  59. {
  60. typedef typename quat_traits<A>::scalar_type T;
  61. typedef typename quat_traits<B>::scalar_type U;
  62. T q1[4] =
  63. {
  64. quat_traits<A>::template read_element<0>(a),
  65. quat_traits<A>::template read_element<1>(a),
  66. quat_traits<A>::template read_element<2>(a),
  67. quat_traits<A>::template read_element<3>(a)
  68. };
  69. U q2[4] =
  70. {
  71. quat_traits<B>::template read_element<0>(b),
  72. quat_traits<B>::template read_element<1>(b),
  73. quat_traits<B>::template read_element<2>(b),
  74. quat_traits<B>::template read_element<3>(b)
  75. };
  76. int i=0;
  77. for( ; i!=4; ++i )
  78. if( !f(q1[i],q2[i]) )
  79. break;
  80. if( i==4 )
  81. return true;
  82. for( i=0; i!=4; ++i )
  83. if( !f(q1[i],-q2[i]) )
  84. return false;
  85. return true;
  86. }
  87. ////////////////////////////////////////////////
  88. template <class R,class A>
  89. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  90. typename enable_if_c<
  91. is_quat<R>::value && is_quat<A>::value,
  92. R>::type
  93. convert_to( A const & a )
  94. {
  95. R r;
  96. write_quat_element<0>(r,quat_traits<A>::template read_element<0>(a));
  97. write_quat_element<1>(r,quat_traits<A>::template read_element<1>(a));
  98. write_quat_element<2>(r,quat_traits<A>::template read_element<2>(a));
  99. write_quat_element<3>(r,quat_traits<A>::template read_element<3>(a));
  100. return r;
  101. }
  102. template <class R,class A>
  103. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  104. typename enable_if_c<
  105. is_quat<R>::value && is_mat<A>::value &&
  106. mat_traits<A>::rows==3 && mat_traits<A>::cols==3,
  107. R>::type
  108. convert_to( A const & a )
  109. {
  110. typedef typename mat_traits<A>::scalar_type T;
  111. T const mat[3][3] =
  112. {
  113. { mat_traits<A>::template read_element<0,0>(a), mat_traits<A>::template read_element<0,1>(a), mat_traits<A>::template read_element<0,2>(a) },
  114. { mat_traits<A>::template read_element<1,0>(a), mat_traits<A>::template read_element<1,1>(a), mat_traits<A>::template read_element<1,2>(a) },
  115. { mat_traits<A>::template read_element<2,0>(a), mat_traits<A>::template read_element<2,1>(a), mat_traits<A>::template read_element<2,2>(a) }
  116. };
  117. R r;
  118. if( mat[0][0]+mat[1][1]+mat[2][2] > scalar_traits<T>::value(0) )
  119. {
  120. T t = mat[0][0] + mat[1][1] + mat[2][2] + scalar_traits<T>::value(1);
  121. T s = (scalar_traits<T>::value(1)/sqrt(t))/2;
  122. write_quat_element<0>(r,s*t);
  123. write_quat_element<1>(r,(mat[2][1]-mat[1][2])*s);
  124. write_quat_element<2>(r,(mat[0][2]-mat[2][0])*s);
  125. write_quat_element<3>(r,(mat[1][0]-mat[0][1])*s);
  126. }
  127. else if( mat[0][0]>mat[1][1] && mat[0][0]>mat[2][2] )
  128. {
  129. T t = mat[0][0] - mat[1][1] - mat[2][2] + scalar_traits<T>::value(1);
  130. T s = (scalar_traits<T>::value(1)/sqrt(t))/2;
  131. write_quat_element<0>(r,(mat[2][1]-mat[1][2])*s);
  132. write_quat_element<1>(r,s*t);
  133. write_quat_element<2>(r,(mat[1][0]+mat[0][1])*s);
  134. write_quat_element<3>(r,(mat[0][2]+mat[2][0])*s);
  135. }
  136. else if( mat[1][1]>mat[2][2] )
  137. {
  138. T t = - mat[0][0] + mat[1][1] - mat[2][2] + scalar_traits<T>::value(1);
  139. T s = (scalar_traits<T>::value(1)/sqrt(t))/2;
  140. write_quat_element<0>(r,(mat[0][2]-mat[2][0])*s);
  141. write_quat_element<1>(r,(mat[1][0]+mat[0][1])*s);
  142. write_quat_element<2>(r,s*t);
  143. write_quat_element<3>(r,(mat[2][1]+mat[1][2])*s);
  144. }
  145. else
  146. {
  147. T t = - mat[0][0] - mat[1][1] + mat[2][2] + scalar_traits<T>::value(1);
  148. T s = (scalar_traits<T>::value(1)/sqrt(t))/2;
  149. write_quat_element<0>(r,(mat[1][0]-mat[0][1])*s);
  150. write_quat_element<1>(r,(mat[0][2]+mat[2][0])*s);
  151. write_quat_element<2>(r,(mat[2][1]+mat[1][2])*s);
  152. write_quat_element<3>(r,s*t);
  153. }
  154. return r;
  155. }
  156. ////////////////////////////////////////////////
  157. template <class A>
  158. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  159. typename lazy_enable_if_c<
  160. is_quat<A>::value,
  161. deduce_quat<A> >::type
  162. conjugate( A const & a )
  163. {
  164. typedef typename deduce_quat<A>::type R;
  165. R r;
  166. write_quat_element<0>(r,quat_traits<A>::template read_element<0>(a));
  167. write_quat_element<1>(r,-quat_traits<A>::template read_element<1>(a));
  168. write_quat_element<2>(r,-quat_traits<A>::template read_element<2>(a));
  169. write_quat_element<3>(r,-quat_traits<A>::template read_element<3>(a));
  170. return r;
  171. }
  172. ////////////////////////////////////////////////
  173. namespace
  174. qvm_detail
  175. {
  176. template <class T>
  177. class
  178. identity_quat_
  179. {
  180. identity_quat_( identity_quat_ const & );
  181. identity_quat_ & operator=( identity_quat_ const & );
  182. ~identity_quat_();
  183. public:
  184. template <class R
  185. #if __cplusplus >= 201103L
  186. , class = typename enable_if<is_quat<R> >::type
  187. #endif
  188. >
  189. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  190. operator R() const
  191. {
  192. R r;
  193. assign(r,*this);
  194. return r;
  195. }
  196. };
  197. }
  198. template <class T>
  199. struct
  200. quat_traits< qvm_detail::identity_quat_<T> >
  201. {
  202. typedef qvm_detail::identity_quat_<T> this_quaternion;
  203. typedef T scalar_type;
  204. template <int I>
  205. static
  206. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  207. scalar_type
  208. read_element( this_quaternion const & )
  209. {
  210. BOOST_QVM_STATIC_ASSERT(I>=0);
  211. BOOST_QVM_STATIC_ASSERT(I<4);
  212. return scalar_traits<T>::value(I==0);
  213. }
  214. static
  215. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  216. scalar_type
  217. read_element_idx( int i, this_quaternion const & )
  218. {
  219. BOOST_QVM_ASSERT(i>=0);
  220. BOOST_QVM_ASSERT(i<4);
  221. return scalar_traits<T>::value(i==0);
  222. }
  223. };
  224. template <class T>
  225. struct
  226. deduce_quat< qvm_detail::identity_quat_<T> >
  227. {
  228. typedef quat<T> type;
  229. };
  230. template <class T>
  231. struct
  232. deduce_quat2< qvm_detail::identity_quat_<T>, qvm_detail::identity_quat_<T> >
  233. {
  234. typedef quat<T> type;
  235. };
  236. template <class T>
  237. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  238. qvm_detail::identity_quat_<T> const &
  239. identity_quat()
  240. {
  241. return *(qvm_detail::identity_quat_<T> const *)qvm_detail::get_valid_ptr_quat_operations();
  242. }
  243. template <class A>
  244. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  245. typename enable_if_c<
  246. is_quat<A>::value,
  247. void>::type
  248. set_identity( A & a )
  249. {
  250. typedef typename quat_traits<A>::scalar_type T;
  251. T const zero=scalar_traits<T>::value(0);
  252. T const one=scalar_traits<T>::value(1);
  253. write_quat_element<0>(a,one);
  254. write_quat_element<1>(a,zero);
  255. write_quat_element<2>(a,zero);
  256. write_quat_element<3>(a,zero);
  257. }
  258. ////////////////////////////////////////////////
  259. namespace
  260. qvm_detail
  261. {
  262. template <class OriginalType,class Scalar>
  263. class
  264. quaternion_scalar_cast_
  265. {
  266. quaternion_scalar_cast_( quaternion_scalar_cast_ const & );
  267. quaternion_scalar_cast_ & operator=( quaternion_scalar_cast_ const & );
  268. ~quaternion_scalar_cast_();
  269. public:
  270. template <class T>
  271. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  272. quaternion_scalar_cast_ &
  273. operator=( T const & x )
  274. {
  275. assign(*this,x);
  276. return *this;
  277. }
  278. template <class R
  279. #if __cplusplus >= 201103L
  280. , class = typename enable_if<is_quat<R> >::type
  281. #endif
  282. >
  283. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  284. operator R() const
  285. {
  286. R r;
  287. assign(r,*this);
  288. return r;
  289. }
  290. };
  291. template <bool> struct scalar_cast_quaternion_filter { };
  292. template <> struct scalar_cast_quaternion_filter<true> { typedef int type; };
  293. }
  294. template <class OriginalType,class Scalar>
  295. struct
  296. quat_traits< qvm_detail::quaternion_scalar_cast_<OriginalType,Scalar> >
  297. {
  298. typedef Scalar scalar_type;
  299. typedef qvm_detail::quaternion_scalar_cast_<OriginalType,Scalar> this_quaternion;
  300. template <int I>
  301. static
  302. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  303. scalar_type
  304. read_element( this_quaternion const & x )
  305. {
  306. BOOST_QVM_STATIC_ASSERT(I>=0);
  307. BOOST_QVM_STATIC_ASSERT(I<4);
  308. return scalar_type(quat_traits<OriginalType>::template read_element<I>(reinterpret_cast<OriginalType const &>(x)));
  309. }
  310. static
  311. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  312. scalar_type
  313. read_element_idx( int i, this_quaternion const & x )
  314. {
  315. BOOST_QVM_ASSERT(i>=0);
  316. BOOST_QVM_ASSERT(i<4);
  317. return scalar_type(quat_traits<OriginalType>::read_element_idx(i,reinterpret_cast<OriginalType const &>(x)));
  318. }
  319. };
  320. template <class Scalar,class T>
  321. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  322. qvm_detail::quaternion_scalar_cast_<T,Scalar> const &
  323. scalar_cast( T const & x, typename qvm_detail::scalar_cast_quaternion_filter<is_quat<T>::value>::type=0 )
  324. {
  325. return reinterpret_cast<qvm_detail::quaternion_scalar_cast_<T,Scalar> const &>(x);
  326. }
  327. ////////////////////////////////////////////////
  328. template <class A,class B>
  329. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  330. typename enable_if_c<
  331. is_quat<A>::value && is_scalar<B>::value,
  332. A &>::type
  333. operator/=( A & a, B b )
  334. {
  335. write_quat_element<0>(a,quat_traits<A>::template read_element<0>(a)/b);
  336. write_quat_element<1>(a,quat_traits<A>::template read_element<1>(a)/b);
  337. write_quat_element<2>(a,quat_traits<A>::template read_element<2>(a)/b);
  338. write_quat_element<3>(a,quat_traits<A>::template read_element<3>(a)/b);
  339. return a;
  340. }
  341. template <class A,class B>
  342. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  343. typename lazy_enable_if_c<
  344. is_quat<A>::value && is_scalar<B>::value,
  345. deduce_quat2<A,B> >::type
  346. operator/( A const & a, B b )
  347. {
  348. typedef typename deduce_quat2<A,B>::type R;
  349. R r;
  350. write_quat_element<0>(r,quat_traits<A>::template read_element<0>(a)/b);
  351. write_quat_element<1>(r,quat_traits<A>::template read_element<1>(a)/b);
  352. write_quat_element<2>(r,quat_traits<A>::template read_element<2>(a)/b);
  353. write_quat_element<3>(r,quat_traits<A>::template read_element<3>(a)/b);
  354. return r;
  355. }
  356. template <class A,class B>
  357. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  358. typename lazy_enable_if_c<
  359. is_quat<A>::value && is_quat<B>::value,
  360. deduce_scalar<typename quat_traits<A>::scalar_type,typename quat_traits<B>::scalar_type> >::type
  361. dot( A const & a, B const & b )
  362. {
  363. typedef typename quat_traits<A>::scalar_type Ta;
  364. typedef typename quat_traits<B>::scalar_type Tb;
  365. typedef typename deduce_scalar<Ta,Tb>::type Tr;
  366. Ta const a0=quat_traits<A>::template read_element<0>(a);
  367. Ta const a1=quat_traits<A>::template read_element<1>(a);
  368. Ta const a2=quat_traits<A>::template read_element<2>(a);
  369. Ta const a3=quat_traits<A>::template read_element<3>(a);
  370. Tb const b0=quat_traits<B>::template read_element<0>(b);
  371. Tb const b1=quat_traits<B>::template read_element<1>(b);
  372. Tb const b2=quat_traits<B>::template read_element<2>(b);
  373. Tb const b3=quat_traits<B>::template read_element<3>(b);
  374. Tr const dp=a0*b0+a1*b1+a2*b2+a3*b3;
  375. return dp;
  376. }
  377. template <class A,class B>
  378. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  379. typename enable_if_c<
  380. is_quat<A>::value && is_quat<B>::value,
  381. bool>::type
  382. operator==( A const & a, B const & b )
  383. {
  384. return
  385. quat_traits<A>::template read_element<0>(a)==quat_traits<B>::template read_element<0>(b) &&
  386. quat_traits<A>::template read_element<1>(a)==quat_traits<B>::template read_element<1>(b) &&
  387. quat_traits<A>::template read_element<2>(a)==quat_traits<B>::template read_element<2>(b) &&
  388. quat_traits<A>::template read_element<3>(a)==quat_traits<B>::template read_element<3>(b);
  389. }
  390. template <class A>
  391. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  392. typename lazy_enable_if_c<
  393. is_quat<A>::value,
  394. deduce_quat<A> >::type
  395. inverse( A const & a )
  396. {
  397. typedef typename deduce_quat<A>::type R;
  398. typedef typename quat_traits<A>::scalar_type TA;
  399. TA aa = quat_traits<A>::template read_element<0>(a);
  400. TA ab = quat_traits<A>::template read_element<1>(a);
  401. TA ac = quat_traits<A>::template read_element<2>(a);
  402. TA ad = quat_traits<A>::template read_element<3>(a);
  403. TA m2 = ab*ab + ac*ac + ad*ad + aa*aa;
  404. if( m2==scalar_traits<TA>::value(0) )
  405. BOOST_QVM_THROW_EXCEPTION(zero_magnitude_error());
  406. TA rm=scalar_traits<TA>::value(1)/m2;
  407. R r;
  408. write_quat_element<0>(r,aa*rm);
  409. write_quat_element<1>(r,-ab*rm);
  410. write_quat_element<2>(r,-ac*rm);
  411. write_quat_element<3>(r,-ad*rm);
  412. return r;
  413. }
  414. template <class A>
  415. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  416. typename enable_if_c<
  417. is_quat<A>::value,
  418. typename quat_traits<A>::scalar_type>::type
  419. mag_sqr( A const & a )
  420. {
  421. typedef typename quat_traits<A>::scalar_type T;
  422. T x=quat_traits<A>::template read_element<0>(a);
  423. T y=quat_traits<A>::template read_element<1>(a);
  424. T z=quat_traits<A>::template read_element<2>(a);
  425. T w=quat_traits<A>::template read_element<3>(a);
  426. return x*x+y*y+z*z+w*w;
  427. }
  428. template <class A>
  429. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  430. typename enable_if_c<
  431. is_quat<A>::value,
  432. typename quat_traits<A>::scalar_type>::type
  433. mag( A const & a )
  434. {
  435. typedef typename quat_traits<A>::scalar_type T;
  436. T x=quat_traits<A>::template read_element<0>(a);
  437. T y=quat_traits<A>::template read_element<1>(a);
  438. T z=quat_traits<A>::template read_element<2>(a);
  439. T w=quat_traits<A>::template read_element<3>(a);
  440. return sqrt(x*x+y*y+z*z+w*w);
  441. }
  442. template <class A,class B>
  443. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  444. typename enable_if<
  445. msvc_parse_bug_workaround::quats<A,B>,
  446. A &>::type
  447. operator-=( A & a, B const & b )
  448. {
  449. write_quat_element<0>(a,quat_traits<A>::template read_element<0>(a)-quat_traits<B>::template read_element<0>(b));
  450. write_quat_element<1>(a,quat_traits<A>::template read_element<1>(a)-quat_traits<B>::template read_element<1>(b));
  451. write_quat_element<2>(a,quat_traits<A>::template read_element<2>(a)-quat_traits<B>::template read_element<2>(b));
  452. write_quat_element<3>(a,quat_traits<A>::template read_element<3>(a)-quat_traits<B>::template read_element<3>(b));
  453. return a;
  454. }
  455. template <class A,class B>
  456. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  457. typename lazy_enable_if_c<
  458. is_quat<A>::value && is_quat<B>::value,
  459. deduce_quat2<A,B> >::type
  460. operator-( A const & a, B const & b )
  461. {
  462. typedef typename deduce_quat2<A,B>::type R;
  463. R r;
  464. write_quat_element<0>(r,quat_traits<A>::template read_element<0>(a)-quat_traits<B>::template read_element<0>(b));
  465. write_quat_element<1>(r,quat_traits<A>::template read_element<1>(a)-quat_traits<B>::template read_element<1>(b));
  466. write_quat_element<2>(r,quat_traits<A>::template read_element<2>(a)-quat_traits<B>::template read_element<2>(b));
  467. write_quat_element<3>(r,quat_traits<A>::template read_element<3>(a)-quat_traits<B>::template read_element<3>(b));
  468. return r;
  469. }
  470. template <class A>
  471. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  472. typename lazy_enable_if_c<
  473. is_quat<A>::value,
  474. deduce_quat<A> >::type
  475. operator-( A const & a )
  476. {
  477. typedef typename deduce_quat<A>::type R;
  478. R r;
  479. write_quat_element<0>(r,-quat_traits<A>::template read_element<0>(a));
  480. write_quat_element<1>(r,-quat_traits<A>::template read_element<1>(a));
  481. write_quat_element<2>(r,-quat_traits<A>::template read_element<2>(a));
  482. write_quat_element<3>(r,-quat_traits<A>::template read_element<3>(a));
  483. return r;
  484. }
  485. template <class A,class B>
  486. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  487. typename enable_if<
  488. msvc_parse_bug_workaround::quats<A,B>,
  489. A &>::type
  490. operator*=( A & a, B const & b )
  491. {
  492. typedef typename quat_traits<A>::scalar_type TA;
  493. typedef typename quat_traits<B>::scalar_type TB;
  494. TA const aa=quat_traits<A>::template read_element<0>(a);
  495. TA const ab=quat_traits<A>::template read_element<1>(a);
  496. TA const ac=quat_traits<A>::template read_element<2>(a);
  497. TA const ad=quat_traits<A>::template read_element<3>(a);
  498. TB const ba=quat_traits<B>::template read_element<0>(b);
  499. TB const bb=quat_traits<B>::template read_element<1>(b);
  500. TB const bc=quat_traits<B>::template read_element<2>(b);
  501. TB const bd=quat_traits<B>::template read_element<3>(b);
  502. write_quat_element<0>(a,aa*ba - ab*bb - ac*bc - ad*bd);
  503. write_quat_element<1>(a,aa*bb + ab*ba + ac*bd - ad*bc);
  504. write_quat_element<2>(a,aa*bc + ac*ba + ad*bb - ab*bd);
  505. write_quat_element<3>(a,aa*bd + ad*ba + ab*bc - ac*bb);
  506. return a;
  507. }
  508. template <class A,class B>
  509. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  510. typename enable_if_c<
  511. is_quat<A>::value && is_scalar<B>::value,
  512. A &>::type
  513. operator*=( A & a, B b )
  514. {
  515. write_quat_element<0>(a, quat_traits<A>::template read_element<0>(a)*b);
  516. write_quat_element<1>(a, quat_traits<A>::template read_element<1>(a)*b);
  517. write_quat_element<2>(a, quat_traits<A>::template read_element<2>(a)*b);
  518. write_quat_element<3>(a, quat_traits<A>::template read_element<3>(a)*b);
  519. return a;
  520. }
  521. template <class A,class B>
  522. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  523. typename lazy_enable_if_c<
  524. is_quat<A>::value && is_quat<B>::value,
  525. deduce_quat2<A,B> >::type
  526. operator*( A const & a, B const & b )
  527. {
  528. typedef typename deduce_quat2<A,B>::type R;
  529. typedef typename quat_traits<A>::scalar_type TA;
  530. typedef typename quat_traits<B>::scalar_type TB;
  531. TA const aa=quat_traits<A>::template read_element<0>(a);
  532. TA const ab=quat_traits<A>::template read_element<1>(a);
  533. TA const ac=quat_traits<A>::template read_element<2>(a);
  534. TA const ad=quat_traits<A>::template read_element<3>(a);
  535. TB const ba=quat_traits<B>::template read_element<0>(b);
  536. TB const bb=quat_traits<B>::template read_element<1>(b);
  537. TB const bc=quat_traits<B>::template read_element<2>(b);
  538. TB const bd=quat_traits<B>::template read_element<3>(b);
  539. R r;
  540. write_quat_element<0>(r,aa*ba - ab*bb - ac*bc - ad*bd);
  541. write_quat_element<1>(r,aa*bb + ab*ba + ac*bd - ad*bc);
  542. write_quat_element<2>(r,aa*bc + ac*ba + ad*bb - ab*bd);
  543. write_quat_element<3>(r,aa*bd + ad*ba + ab*bc - ac*bb);
  544. return r;
  545. }
  546. template <class A,class B>
  547. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  548. typename lazy_enable_if_c2<
  549. is_quat<A>::value && is_scalar<B>::value,
  550. deduce_quat2<A,B> >::type
  551. operator*( A const & a, B b )
  552. {
  553. typedef typename deduce_quat2<A,B>::type R;
  554. R r;
  555. write_quat_element<0>(r,quat_traits<A>::template read_element<0>(a)*b);
  556. write_quat_element<1>(r,quat_traits<A>::template read_element<1>(a)*b);
  557. write_quat_element<2>(r,quat_traits<A>::template read_element<2>(a)*b);
  558. write_quat_element<3>(r,quat_traits<A>::template read_element<3>(a)*b);
  559. return r;
  560. }
  561. template <class A,class B>
  562. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  563. typename enable_if_c<
  564. is_quat<A>::value && is_quat<B>::value,
  565. bool>::type
  566. operator!=( A const & a, B const & b )
  567. {
  568. return
  569. quat_traits<A>::template read_element<0>(a)!=quat_traits<B>::template read_element<0>(b) ||
  570. quat_traits<A>::template read_element<1>(a)!=quat_traits<B>::template read_element<1>(b) ||
  571. quat_traits<A>::template read_element<2>(a)!=quat_traits<B>::template read_element<2>(b) ||
  572. quat_traits<A>::template read_element<3>(a)!=quat_traits<B>::template read_element<3>(b);
  573. }
  574. template <class A>
  575. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  576. typename lazy_enable_if_c<
  577. is_quat<A>::value,
  578. deduce_quat<A> >::type
  579. normalized( A const & a )
  580. {
  581. typedef typename quat_traits<A>::scalar_type T;
  582. T const a0=quat_traits<A>::template read_element<0>(a);
  583. T const a1=quat_traits<A>::template read_element<1>(a);
  584. T const a2=quat_traits<A>::template read_element<2>(a);
  585. T const a3=quat_traits<A>::template read_element<3>(a);
  586. T const m2=a0*a0+a1*a1+a2*a2+a3*a3;
  587. if( m2==scalar_traits<typename quat_traits<A>::scalar_type>::value(0) )
  588. BOOST_QVM_THROW_EXCEPTION(zero_magnitude_error());
  589. T const rm=scalar_traits<T>::value(1)/sqrt(m2);
  590. typedef typename deduce_quat<A>::type R;
  591. R r;
  592. write_quat_element<0>(r,a0*rm);
  593. write_quat_element<1>(r,a1*rm);
  594. write_quat_element<2>(r,a2*rm);
  595. write_quat_element<3>(r,a3*rm);
  596. return r;
  597. }
  598. template <class A>
  599. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  600. typename enable_if_c<
  601. is_quat<A>::value,
  602. void>::type
  603. normalize( A & a )
  604. {
  605. typedef typename quat_traits<A>::scalar_type T;
  606. T const a0=quat_traits<A>::template read_element<0>(a);
  607. T const a1=quat_traits<A>::template read_element<1>(a);
  608. T const a2=quat_traits<A>::template read_element<2>(a);
  609. T const a3=quat_traits<A>::template read_element<3>(a);
  610. T const m2=a0*a0+a1*a1+a2*a2+a3*a3;
  611. if( m2==scalar_traits<typename quat_traits<A>::scalar_type>::value(0) )
  612. BOOST_QVM_THROW_EXCEPTION(zero_magnitude_error());
  613. T const rm=scalar_traits<T>::value(1)/sqrt(m2);
  614. write_quat_element<0>(a,quat_traits<A>::template read_element<0>(a)*rm);
  615. write_quat_element<1>(a,quat_traits<A>::template read_element<1>(a)*rm);
  616. write_quat_element<2>(a,quat_traits<A>::template read_element<2>(a)*rm);
  617. write_quat_element<3>(a,quat_traits<A>::template read_element<3>(a)*rm);
  618. }
  619. template <class A,class B>
  620. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  621. typename enable_if<
  622. msvc_parse_bug_workaround::quats<A,B>,
  623. A &>::type
  624. operator+=( A & a, B const & b )
  625. {
  626. write_quat_element<0>(a,quat_traits<A>::template read_element<0>(a)+quat_traits<B>::template read_element<0>(b));
  627. write_quat_element<1>(a,quat_traits<A>::template read_element<1>(a)+quat_traits<B>::template read_element<1>(b));
  628. write_quat_element<2>(a,quat_traits<A>::template read_element<2>(a)+quat_traits<B>::template read_element<2>(b));
  629. write_quat_element<3>(a,quat_traits<A>::template read_element<3>(a)+quat_traits<B>::template read_element<3>(b));
  630. return a;
  631. }
  632. template <class A,class B>
  633. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  634. typename lazy_enable_if_c<
  635. is_quat<A>::value && is_quat<B>::value,
  636. deduce_quat2<A,B> >::type
  637. operator+( A const & a, B const & b )
  638. {
  639. typedef typename deduce_quat2<A,B>::type R;
  640. R r;
  641. write_quat_element<0>(r,quat_traits<A>::template read_element<0>(a)+quat_traits<B>::template read_element<0>(b));
  642. write_quat_element<1>(r,quat_traits<A>::template read_element<1>(a)+quat_traits<B>::template read_element<1>(b));
  643. write_quat_element<2>(r,quat_traits<A>::template read_element<2>(a)+quat_traits<B>::template read_element<2>(b));
  644. write_quat_element<3>(r,quat_traits<A>::template read_element<3>(a)+quat_traits<B>::template read_element<3>(b));
  645. return r;
  646. }
  647. template <class A,class B,class C>
  648. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  649. typename lazy_enable_if_c<
  650. is_quat<A>::value && is_quat<B>::value && is_scalar<C>::value,
  651. deduce_quat2<A,B> >::type
  652. slerp360( A const & a, B const & b, C t )
  653. {
  654. typedef typename deduce_quat2<A,B>::type R;
  655. typedef typename quat_traits<R>::scalar_type TR;
  656. TR const one = scalar_traits<TR>::value(1);
  657. TR const threshold = one - one / scalar_traits<TR>::value(2000); //0.9995
  658. TR const dp = dot(a,b);
  659. TR const abs_dp = abs(dp);
  660. if( abs_dp > threshold )
  661. return a*(one-t) + b*t;
  662. TR const th = acos(dp);
  663. TR const invsinth = one / sin(th);
  664. return a * (sin(th * (one-t)) * invsinth) + b * (sin(th * t) * invsinth);
  665. }
  666. template <class A,class B,class C>
  667. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  668. typename lazy_enable_if_c<
  669. is_quat<A>::value && is_quat<B>::value && is_scalar<C>::value,
  670. deduce_quat2<A,B> >::type
  671. slerp180( A const & a, B const & b, C t )
  672. {
  673. typedef typename deduce_quat2<A,B>::type R;
  674. typedef typename quat_traits<R>::scalar_type TR;
  675. TR const one = scalar_traits<TR>::value(1);
  676. TR const threshold = one - one / scalar_traits<TR>::value(2000); //0.9995
  677. TR const dp = dot(a,b);
  678. TR const abs_dp = abs(dp);
  679. if( abs_dp > threshold )
  680. return a*(one-t)*sign(dp) + b*t;
  681. TR const th = acos(abs_dp);
  682. TR const invsinth = one / sin(th);
  683. return a * (sin(th * (one-t)) * invsinth * sign(dp)) + b * (sin(th * t) * invsinth);
  684. }
  685. template <class A,class B,class C>
  686. BOOST_QVM_DEPRECATED("please use slerp180 or slerp360")
  687. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  688. typename lazy_enable_if_c<
  689. is_quat<A>::value && is_quat<B>::value && is_scalar<C>::value,
  690. deduce_quat2<A,B> >::type
  691. slerp( A const & a, B const & b, C t )
  692. {
  693. return slerp360(a, b, t);
  694. }
  695. ////////////////////////////////////////////////
  696. namespace
  697. qvm_detail
  698. {
  699. template <class T>
  700. class
  701. qref_
  702. {
  703. qref_( qref_ const & );
  704. qref_ & operator=( qref_ const & );
  705. ~qref_();
  706. public:
  707. template <class R>
  708. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  709. qref_ &
  710. operator=( R const & x )
  711. {
  712. assign(*this,x);
  713. return *this;
  714. }
  715. template <class R
  716. #if __cplusplus >= 201103L
  717. , class = typename enable_if<is_quat<R> >::type
  718. #endif
  719. >
  720. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  721. operator R() const
  722. {
  723. R r;
  724. assign(r,*this);
  725. return r;
  726. }
  727. };
  728. template <class Q,bool WriteElementRef=quat_write_element_ref<Q>::value>
  729. struct qref_write_traits;
  730. template <class Q>
  731. struct
  732. qref_write_traits<Q,true>
  733. {
  734. typedef typename quat_traits<Q>::scalar_type scalar_type;
  735. typedef qvm_detail::qref_<Q> this_quaternion;
  736. template <int I>
  737. static
  738. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  739. scalar_type &
  740. write_element( this_quaternion & x )
  741. {
  742. BOOST_QVM_STATIC_ASSERT(I>=0);
  743. BOOST_QVM_STATIC_ASSERT(I<4);
  744. return quat_traits<Q>::template write_element<I>(reinterpret_cast<Q &>(x));
  745. }
  746. };
  747. template <class Q>
  748. struct
  749. qref_write_traits<Q,false>
  750. {
  751. typedef typename quat_traits<Q>::scalar_type scalar_type;
  752. typedef qvm_detail::qref_<Q> this_quaternion;
  753. template <int I>
  754. static
  755. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  756. void
  757. write_element( this_quaternion & x, scalar_type s )
  758. {
  759. BOOST_QVM_STATIC_ASSERT(I>=0);
  760. BOOST_QVM_STATIC_ASSERT(I<4);
  761. quat_traits<Q>::template write_element<I>(reinterpret_cast<Q &>(x), s);
  762. }
  763. };
  764. }
  765. template <class Q>
  766. struct quat_traits;
  767. template <class Q>
  768. struct
  769. quat_traits< qvm_detail::qref_<Q> >:
  770. qvm_detail::qref_write_traits<Q>
  771. {
  772. typedef typename quat_traits<Q>::scalar_type scalar_type;
  773. typedef qvm_detail::qref_<Q> this_quaternion;
  774. template <int I>
  775. static
  776. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  777. scalar_type
  778. read_element( this_quaternion const & x )
  779. {
  780. BOOST_QVM_STATIC_ASSERT(I>=0);
  781. BOOST_QVM_STATIC_ASSERT(I<4);
  782. return quat_traits<Q>::template read_element<I>(reinterpret_cast<Q const &>(x));
  783. }
  784. };
  785. template <class Q>
  786. struct
  787. deduce_quat< qvm_detail::qref_<Q> >
  788. {
  789. typedef quat<typename quat_traits<Q>::scalar_type> type;
  790. };
  791. template <class Q>
  792. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  793. typename enable_if_c<
  794. is_quat<Q>::value,
  795. qvm_detail::qref_<Q> const &>::type
  796. qref( Q const & a )
  797. {
  798. return reinterpret_cast<qvm_detail::qref_<Q> const &>(a);
  799. }
  800. template <class Q>
  801. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  802. typename enable_if_c<
  803. is_quat<Q>::value,
  804. qvm_detail::qref_<Q> &>::type
  805. qref( Q & a )
  806. {
  807. return reinterpret_cast<qvm_detail::qref_<Q> &>(a);
  808. }
  809. ////////////////////////////////////////////////
  810. namespace
  811. qvm_detail
  812. {
  813. template <class T>
  814. class
  815. zero_q_
  816. {
  817. zero_q_( zero_q_ const & );
  818. zero_q_ & operator=( zero_q_ const & );
  819. ~zero_q_();
  820. public:
  821. template <class R
  822. #if __cplusplus >= 201103L
  823. , class = typename enable_if<is_quat<R> >::type
  824. #endif
  825. >
  826. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  827. operator R() const
  828. {
  829. R r;
  830. assign(r,*this);
  831. return r;
  832. }
  833. };
  834. }
  835. template <class T>
  836. struct
  837. quat_traits< qvm_detail::zero_q_<T> >
  838. {
  839. typedef qvm_detail::zero_q_<T> this_quaternion;
  840. typedef T scalar_type;
  841. template <int I>
  842. static
  843. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  844. scalar_type
  845. read_element( this_quaternion const & )
  846. {
  847. BOOST_QVM_STATIC_ASSERT(I>=0);
  848. BOOST_QVM_STATIC_ASSERT(I<4);
  849. return scalar_traits<scalar_type>::value(0);
  850. }
  851. static
  852. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  853. scalar_type
  854. read_element_idx( int i, this_quaternion const & )
  855. {
  856. BOOST_QVM_ASSERT(i>=0);
  857. BOOST_QVM_ASSERT(i<4);
  858. return scalar_traits<scalar_type>::value(0);
  859. }
  860. };
  861. template <class T>
  862. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  863. qvm_detail::zero_q_<T> const &
  864. zero_quat()
  865. {
  866. return *(qvm_detail::zero_q_<T> const *)qvm_detail::get_valid_ptr_quat_operations();
  867. }
  868. template <class A>
  869. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  870. typename enable_if_c<
  871. is_quat<A>::value,
  872. void>::type
  873. set_zero( A & a )
  874. {
  875. typedef typename quat_traits<A>::scalar_type T;
  876. T const zero=scalar_traits<T>::value(0);
  877. write_quat_element<0>(a,zero);
  878. write_quat_element<1>(a,zero);
  879. write_quat_element<2>(a,zero);
  880. write_quat_element<3>(a,zero);
  881. }
  882. ////////////////////////////////////////////////
  883. namespace
  884. qvm_detail
  885. {
  886. template <class V>
  887. struct
  888. rot_quat_
  889. {
  890. typedef typename vec_traits<V>::scalar_type scalar_type;
  891. scalar_type a[4];
  892. template <class Angle>
  893. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE
  894. rot_quat_( V const & axis, Angle angle )
  895. {
  896. scalar_type const x=vec_traits<V>::template read_element<0>(axis);
  897. scalar_type const y=vec_traits<V>::template read_element<1>(axis);
  898. scalar_type const z=vec_traits<V>::template read_element<2>(axis);
  899. scalar_type const m2=x*x+y*y+z*z;
  900. if( m2==scalar_traits<scalar_type>::value(0) )
  901. BOOST_QVM_THROW_EXCEPTION(zero_magnitude_error());
  902. scalar_type const rm=scalar_traits<scalar_type>::value(1)/sqrt(m2);
  903. angle/=2;
  904. scalar_type const s=sin(angle);
  905. a[0] = cos(angle);
  906. a[1] = rm*x*s;
  907. a[2] = rm*y*s;
  908. a[3] = rm*z*s;
  909. }
  910. template <class R
  911. #if __cplusplus >= 201103L
  912. , class = typename enable_if<is_quat<R> >::type
  913. #endif
  914. >
  915. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  916. operator R() const
  917. {
  918. R r;
  919. assign(r,*this);
  920. return r;
  921. }
  922. };
  923. }
  924. template <class V>
  925. struct
  926. quat_traits< qvm_detail::rot_quat_<V> >
  927. {
  928. typedef qvm_detail::rot_quat_<V> this_quaternion;
  929. typedef typename this_quaternion::scalar_type scalar_type;
  930. template <int I>
  931. static
  932. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  933. scalar_type
  934. read_element( this_quaternion const & x )
  935. {
  936. BOOST_QVM_STATIC_ASSERT(I>=0);
  937. BOOST_QVM_STATIC_ASSERT(I<4);
  938. return x.a[I];
  939. }
  940. };
  941. template <class V>
  942. struct
  943. deduce_quat< qvm_detail::rot_quat_<V> >
  944. {
  945. typedef quat<typename vec_traits<V>::scalar_type> type;
  946. };
  947. template <class A,class Angle>
  948. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE
  949. typename enable_if_c<
  950. is_vec<A>::value && vec_traits<A>::dim==3,
  951. qvm_detail::rot_quat_<A> >::type
  952. rot_quat( A const & axis, Angle angle )
  953. {
  954. return qvm_detail::rot_quat_<A>(axis,angle);
  955. }
  956. template <class A,class B,class Angle>
  957. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  958. typename enable_if_c<
  959. is_quat<A>::value &&
  960. is_vec<B>::value && vec_traits<B>::dim==3,
  961. void>::type
  962. set_rot( A & a, B const & axis, Angle angle )
  963. {
  964. assign(a,rot_quat(axis,angle));
  965. }
  966. template <class A,class B,class Angle>
  967. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  968. typename enable_if_c<
  969. is_quat<A>::value &&
  970. is_vec<B>::value && vec_traits<B>::dim==3,
  971. void>::type
  972. rotate( A & a, B const & axis, Angle angle )
  973. {
  974. a *= rot_quat(axis,angle);
  975. }
  976. ////////////////////////////////////////////////
  977. namespace
  978. qvm_detail
  979. {
  980. template <class T>
  981. struct
  982. rotx_quat_
  983. {
  984. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  985. rotx_quat_()
  986. {
  987. }
  988. template <class R
  989. #if __cplusplus >= 201103L
  990. , class = typename enable_if<is_quat<R> >::type
  991. #endif
  992. >
  993. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  994. operator R() const
  995. {
  996. R r;
  997. assign(r,*this);
  998. return r;
  999. }
  1000. private:
  1001. rotx_quat_( rotx_quat_ const & );
  1002. rotx_quat_ & operator=( rotx_quat_ const & );
  1003. ~rotx_quat_();
  1004. };
  1005. template <int I>
  1006. struct
  1007. rotx_q_get
  1008. {
  1009. template <class T>
  1010. static
  1011. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  1012. T
  1013. get( T const & )
  1014. {
  1015. return scalar_traits<T>::value(0);
  1016. }
  1017. };
  1018. template <>
  1019. struct
  1020. rotx_q_get<1>
  1021. {
  1022. template <class T>
  1023. static
  1024. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  1025. T
  1026. get( T const & angle )
  1027. {
  1028. return sin(angle/2);
  1029. }
  1030. };
  1031. template <>
  1032. struct
  1033. rotx_q_get<0>
  1034. {
  1035. template <class T>
  1036. static
  1037. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  1038. T
  1039. get( T const & angle )
  1040. {
  1041. return cos(angle/2);
  1042. }
  1043. };
  1044. }
  1045. template <class Angle>
  1046. struct
  1047. quat_traits< qvm_detail::rotx_quat_<Angle> >
  1048. {
  1049. typedef qvm_detail::rotx_quat_<Angle> this_quaternion;
  1050. typedef Angle scalar_type;
  1051. template <int I>
  1052. static
  1053. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  1054. scalar_type
  1055. read_element( this_quaternion const & x )
  1056. {
  1057. BOOST_QVM_STATIC_ASSERT(I>=0);
  1058. BOOST_QVM_STATIC_ASSERT(I<4);
  1059. return qvm_detail::rotx_q_get<I>::get(reinterpret_cast<Angle const &>(x));
  1060. }
  1061. };
  1062. template <class Angle>
  1063. struct
  1064. deduce_quat< qvm_detail::rotx_quat_<Angle> >
  1065. {
  1066. typedef quat<Angle> type;
  1067. };
  1068. template <class Angle>
  1069. struct
  1070. deduce_quat2< qvm_detail::rotx_quat_<Angle>, qvm_detail::rotx_quat_<Angle> >
  1071. {
  1072. typedef quat<Angle> type;
  1073. };
  1074. template <class Angle>
  1075. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  1076. qvm_detail::rotx_quat_<Angle> const &
  1077. rotx_quat( Angle const & angle )
  1078. {
  1079. return reinterpret_cast<qvm_detail::rotx_quat_<Angle> const &>(angle);
  1080. }
  1081. template <class A,class Angle>
  1082. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  1083. typename enable_if_c<
  1084. is_quat<A>::value,
  1085. void>::type
  1086. set_rotx( A & a, Angle angle )
  1087. {
  1088. assign(a,rotx_quat(angle));
  1089. }
  1090. template <class A,class Angle>
  1091. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  1092. typename enable_if_c<
  1093. is_quat<A>::value,
  1094. void>::type
  1095. rotate_x( A & a, Angle angle )
  1096. {
  1097. a *= rotx_quat(angle);
  1098. }
  1099. ////////////////////////////////////////////////
  1100. namespace
  1101. qvm_detail
  1102. {
  1103. template <class T>
  1104. struct
  1105. roty_quat_
  1106. {
  1107. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  1108. roty_quat_()
  1109. {
  1110. }
  1111. template <class R
  1112. #if __cplusplus >= 201103L
  1113. , class = typename enable_if<is_quat<R> >::type
  1114. #endif
  1115. >
  1116. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  1117. operator R() const
  1118. {
  1119. R r;
  1120. assign(r,*this);
  1121. return r;
  1122. }
  1123. private:
  1124. roty_quat_( roty_quat_ const & );
  1125. roty_quat_ & operator=( roty_quat_ const & );
  1126. ~roty_quat_();
  1127. };
  1128. template <int I>
  1129. struct
  1130. roty_q_get
  1131. {
  1132. template <class T>
  1133. static
  1134. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  1135. T
  1136. get( T const & )
  1137. {
  1138. return scalar_traits<T>::value(0);
  1139. }
  1140. };
  1141. template <>
  1142. struct
  1143. roty_q_get<2>
  1144. {
  1145. template <class T>
  1146. static
  1147. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  1148. T
  1149. get( T const & angle )
  1150. {
  1151. return sin(angle/2);
  1152. }
  1153. };
  1154. template <>
  1155. struct
  1156. roty_q_get<0>
  1157. {
  1158. template <class T>
  1159. static
  1160. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  1161. T
  1162. get( T const & angle )
  1163. {
  1164. return cos(angle/2);
  1165. }
  1166. };
  1167. }
  1168. template <class Angle>
  1169. struct
  1170. quat_traits< qvm_detail::roty_quat_<Angle> >
  1171. {
  1172. typedef qvm_detail::roty_quat_<Angle> this_quaternion;
  1173. typedef Angle scalar_type;
  1174. template <int I>
  1175. static
  1176. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  1177. scalar_type
  1178. read_element( this_quaternion const & x )
  1179. {
  1180. BOOST_QVM_STATIC_ASSERT(I>=0);
  1181. BOOST_QVM_STATIC_ASSERT(I<4);
  1182. return qvm_detail::roty_q_get<I>::get(reinterpret_cast<Angle const &>(x));
  1183. }
  1184. };
  1185. template <class Angle>
  1186. struct
  1187. deduce_quat< qvm_detail::roty_quat_<Angle> >
  1188. {
  1189. typedef quat<Angle> type;
  1190. };
  1191. template <class Angle>
  1192. struct
  1193. deduce_quat2< qvm_detail::roty_quat_<Angle>, qvm_detail::roty_quat_<Angle> >
  1194. {
  1195. typedef quat<Angle> type;
  1196. };
  1197. template <class Angle>
  1198. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  1199. qvm_detail::roty_quat_<Angle> const &
  1200. roty_quat( Angle const & angle )
  1201. {
  1202. return reinterpret_cast<qvm_detail::roty_quat_<Angle> const &>(angle);
  1203. }
  1204. template <class A,class Angle>
  1205. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  1206. typename enable_if_c<
  1207. is_quat<A>::value,
  1208. void>::type
  1209. set_roty( A & a, Angle angle )
  1210. {
  1211. assign(a,roty_quat(angle));
  1212. }
  1213. template <class A,class Angle>
  1214. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  1215. typename enable_if_c<
  1216. is_quat<A>::value,
  1217. void>::type
  1218. rotate_y( A & a, Angle angle )
  1219. {
  1220. a *= roty_quat(angle);
  1221. }
  1222. ////////////////////////////////////////////////
  1223. namespace
  1224. qvm_detail
  1225. {
  1226. template <class T>
  1227. struct
  1228. rotz_quat_
  1229. {
  1230. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  1231. rotz_quat_()
  1232. {
  1233. }
  1234. template <class R
  1235. #if __cplusplus >= 201103L
  1236. , class = typename enable_if<is_quat<R> >::type
  1237. #endif
  1238. >
  1239. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  1240. operator R() const
  1241. {
  1242. R r;
  1243. assign(r,*this);
  1244. return r;
  1245. }
  1246. private:
  1247. rotz_quat_( rotz_quat_ const & );
  1248. rotz_quat_ & operator=( rotz_quat_ const & );
  1249. ~rotz_quat_();
  1250. };
  1251. template <int I>
  1252. struct
  1253. rotz_q_get
  1254. {
  1255. template <class T>
  1256. static
  1257. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  1258. T
  1259. get( T const & )
  1260. {
  1261. return scalar_traits<T>::value(0);
  1262. }
  1263. };
  1264. template <>
  1265. struct
  1266. rotz_q_get<3>
  1267. {
  1268. template <class T>
  1269. static
  1270. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  1271. T
  1272. get( T const & angle )
  1273. {
  1274. return sin(angle/2);
  1275. }
  1276. };
  1277. template <>
  1278. struct
  1279. rotz_q_get<0>
  1280. {
  1281. template <class T>
  1282. static
  1283. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  1284. T
  1285. get( T const & angle )
  1286. {
  1287. return cos(angle/2);
  1288. }
  1289. };
  1290. }
  1291. template <class Angle>
  1292. struct
  1293. quat_traits< qvm_detail::rotz_quat_<Angle> >
  1294. {
  1295. typedef qvm_detail::rotz_quat_<Angle> this_quaternion;
  1296. typedef Angle scalar_type;
  1297. template <int I>
  1298. static
  1299. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_CRITICAL
  1300. scalar_type
  1301. read_element( this_quaternion const & x )
  1302. {
  1303. BOOST_QVM_STATIC_ASSERT(I>=0);
  1304. BOOST_QVM_STATIC_ASSERT(I<4);
  1305. return qvm_detail::rotz_q_get<I>::get(reinterpret_cast<Angle const &>(x));
  1306. }
  1307. };
  1308. template <class Angle>
  1309. struct
  1310. deduce_quat< qvm_detail::rotz_quat_<Angle> >
  1311. {
  1312. typedef quat<Angle> type;
  1313. };
  1314. template <class Angle>
  1315. struct
  1316. deduce_quat2< qvm_detail::rotz_quat_<Angle>, qvm_detail::rotz_quat_<Angle> >
  1317. {
  1318. typedef quat<Angle> type;
  1319. };
  1320. template <class Angle>
  1321. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_TRIVIAL
  1322. qvm_detail::rotz_quat_<Angle> const &
  1323. rotz_quat( Angle const & angle )
  1324. {
  1325. return reinterpret_cast<qvm_detail::rotz_quat_<Angle> const &>(angle);
  1326. }
  1327. template <class A,class Angle>
  1328. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  1329. typename enable_if_c<
  1330. is_quat<A>::value,
  1331. void>::type
  1332. set_rotz( A & a, Angle angle )
  1333. {
  1334. assign(a,rotz_quat(angle));
  1335. }
  1336. template <class A,class Angle>
  1337. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  1338. typename enable_if_c<
  1339. is_quat<A>::value,
  1340. void>::type
  1341. rotate_z( A & a, Angle angle )
  1342. {
  1343. a *= rotz_quat(angle);
  1344. }
  1345. template <class A,class B>
  1346. BOOST_QVM_CONSTEXPR BOOST_QVM_INLINE_OPERATIONS
  1347. typename enable_if_c<
  1348. is_quat<A>::value && is_vec<B>::value && vec_traits<B>::dim==3,
  1349. typename quat_traits<A>::scalar_type>::type
  1350. axis_angle( A const & a, B & b )
  1351. {
  1352. typedef typename quat_traits<A>::scalar_type T;
  1353. T a0=quat_traits<A>::template read_element<0>(a);
  1354. T a1=quat_traits<A>::template read_element<1>(a);
  1355. T a2=quat_traits<A>::template read_element<2>(a);
  1356. T a3=quat_traits<A>::template read_element<3>(a);
  1357. if( a0>1 )
  1358. {
  1359. T const m2=a0*a0+a1*a1+a2*a2+a3*a3;
  1360. if( m2==scalar_traits<T>::value(0) )
  1361. BOOST_QVM_THROW_EXCEPTION(zero_magnitude_error());
  1362. T const s=sqrt(m2);
  1363. a0/=s;
  1364. a1/=s;
  1365. a2/=s;
  1366. a3/=s;
  1367. }
  1368. if( T s=sqrt(1-a0*a0) )
  1369. {
  1370. write_vec_element<0>(b, a1/s);
  1371. write_vec_element<1>(b, a2/s);
  1372. write_vec_element<2>(b, a3/s);
  1373. }
  1374. else
  1375. {
  1376. typedef typename vec_traits<B>::scalar_type U;
  1377. write_vec_element<0>(b, scalar_traits<U>::value(1));
  1378. write_vec_element<1>(b, scalar_traits<U>::value(0));
  1379. write_vec_element<2>(b, scalar_traits<U>::value(0));
  1380. }
  1381. return scalar_traits<T>::value(2) * qvm::acos(a0);
  1382. }
  1383. ////////////////////////////////////////////////
  1384. namespace
  1385. sfinae
  1386. {
  1387. using ::boost::qvm::assign;
  1388. using ::boost::qvm::cmp;
  1389. using ::boost::qvm::convert_to;
  1390. using ::boost::qvm::conjugate;
  1391. using ::boost::qvm::set_identity;
  1392. using ::boost::qvm::set_zero;
  1393. using ::boost::qvm::scalar_cast;
  1394. using ::boost::qvm::operator/=;
  1395. using ::boost::qvm::operator/;
  1396. using ::boost::qvm::dot;
  1397. using ::boost::qvm::operator==;
  1398. using ::boost::qvm::inverse;
  1399. using ::boost::qvm::mag_sqr;
  1400. using ::boost::qvm::mag;
  1401. using ::boost::qvm::slerp360;
  1402. using ::boost::qvm::slerp180;
  1403. using ::boost::qvm::slerp;
  1404. using ::boost::qvm::operator-=;
  1405. using ::boost::qvm::operator-;
  1406. using ::boost::qvm::operator*=;
  1407. using ::boost::qvm::operator*;
  1408. using ::boost::qvm::operator!=;
  1409. using ::boost::qvm::normalized;
  1410. using ::boost::qvm::normalize;
  1411. using ::boost::qvm::operator+=;
  1412. using ::boost::qvm::operator+;
  1413. using ::boost::qvm::qref;
  1414. using ::boost::qvm::rot_quat;
  1415. using ::boost::qvm::set_rot;
  1416. using ::boost::qvm::rotate;
  1417. using ::boost::qvm::rotx_quat;
  1418. using ::boost::qvm::set_rotx;
  1419. using ::boost::qvm::rotate_x;
  1420. using ::boost::qvm::roty_quat;
  1421. using ::boost::qvm::set_roty;
  1422. using ::boost::qvm::rotate_y;
  1423. using ::boost::qvm::rotz_quat;
  1424. using ::boost::qvm::set_rotz;
  1425. using ::boost::qvm::rotate_z;
  1426. }
  1427. } }
  1428. #endif