quat_operations.hpp 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572
  1. #ifndef BOOST_QVM_QUAT_OPERATIONS
  2. #define BOOST_QVM_QUAT_OPERATIONS
  3. // Copyright 2008-2024 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); (void)i;
  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