quaternion.hpp 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252
  1. // boost quaternion.hpp header file
  2. // (C) Copyright Hubert Holin 2001.
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. // See http://www.boost.org for updates, documentation, and revision history.
  7. #ifndef BOOST_QUATERNION_HPP
  8. #define BOOST_QUATERNION_HPP
  9. #include <boost/config.hpp> // for BOOST_NO_STD_LOCALE
  10. #include <boost/math_fwd.hpp>
  11. #include <boost/detail/workaround.hpp>
  12. #include <boost/type_traits/is_convertible.hpp>
  13. #include <boost/utility/enable_if.hpp>
  14. #ifndef BOOST_NO_STD_LOCALE
  15. # include <locale> // for the "<<" operator
  16. #endif /* BOOST_NO_STD_LOCALE */
  17. #include <complex>
  18. #include <iosfwd> // for the "<<" and ">>" operators
  19. #include <sstream> // for the "<<" operator
  20. #include <boost/math/special_functions/sinc.hpp> // for the Sinus cardinal
  21. #include <boost/math/special_functions/sinhc.hpp> // for the Hyperbolic Sinus cardinal
  22. #include <boost/math/tools/cxx03_warn.hpp>
  23. #include <type_traits>
  24. namespace boost
  25. {
  26. namespace math
  27. {
  28. namespace detail {
  29. #if !defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_SFINAE_EXPR)
  30. template <class T>
  31. struct is_trivial_arithmetic_type_imp
  32. {
  33. typedef std::integral_constant<bool,
  34. noexcept(std::declval<T&>() += std::declval<T>())
  35. && noexcept(std::declval<T&>() -= std::declval<T>())
  36. && noexcept(std::declval<T&>() *= std::declval<T>())
  37. && noexcept(std::declval<T&>() /= std::declval<T>())
  38. > type;
  39. };
  40. template <class T>
  41. struct is_trivial_arithmetic_type : public is_trivial_arithmetic_type_imp<T>::type {};
  42. #else
  43. template <class T>
  44. struct is_trivial_arithmetic_type : public std::is_trivial<T>::value {};
  45. #endif
  46. }
  47. #ifndef BOOST_NO_CXX14_CONSTEXPR
  48. namespace constexpr_detail
  49. {
  50. template <class T>
  51. constexpr void swap(T& a, T& b)
  52. {
  53. T t(a);
  54. a = b;
  55. b = t;
  56. }
  57. }
  58. #endif
  59. template<typename T>
  60. class quaternion
  61. {
  62. public:
  63. typedef T value_type;
  64. // constructor for H seen as R^4
  65. // (also default constructor)
  66. BOOST_CONSTEXPR explicit quaternion( T const & requested_a = T(),
  67. T const & requested_b = T(),
  68. T const & requested_c = T(),
  69. T const & requested_d = T())
  70. : a(requested_a),
  71. b(requested_b),
  72. c(requested_c),
  73. d(requested_d)
  74. {
  75. // nothing to do!
  76. }
  77. // constructor for H seen as C^2
  78. BOOST_CONSTEXPR explicit quaternion( ::std::complex<T> const & z0,
  79. ::std::complex<T> const & z1 = ::std::complex<T>())
  80. : a(z0.real()),
  81. b(z0.imag()),
  82. c(z1.real()),
  83. d(z1.imag())
  84. {
  85. // nothing to do!
  86. }
  87. // UNtemplated copy constructor
  88. BOOST_CONSTEXPR quaternion(quaternion const & a_recopier)
  89. : a(a_recopier.R_component_1()),
  90. b(a_recopier.R_component_2()),
  91. c(a_recopier.R_component_3()),
  92. d(a_recopier.R_component_4()) {}
  93. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  94. BOOST_CONSTEXPR quaternion(quaternion && a_recopier)
  95. : a(std::move(a_recopier.R_component_1())),
  96. b(std::move(a_recopier.R_component_2())),
  97. c(std::move(a_recopier.R_component_3())),
  98. d(std::move(a_recopier.R_component_4())) {}
  99. #endif
  100. // templated copy constructor
  101. template<typename X>
  102. BOOST_CONSTEXPR explicit quaternion(quaternion<X> const & a_recopier)
  103. : a(static_cast<T>(a_recopier.R_component_1())),
  104. b(static_cast<T>(a_recopier.R_component_2())),
  105. c(static_cast<T>(a_recopier.R_component_3())),
  106. d(static_cast<T>(a_recopier.R_component_4()))
  107. {
  108. // nothing to do!
  109. }
  110. // destructor
  111. // (this is taken care of by the compiler itself)
  112. // accessors
  113. //
  114. // Note: Like complex number, quaternions do have a meaningful notion of "real part",
  115. // but unlike them there is no meaningful notion of "imaginary part".
  116. // Instead there is an "unreal part" which itself is a quaternion, and usually
  117. // nothing simpler (as opposed to the complex number case).
  118. // However, for practicality, there are accessors for the other components
  119. // (these are necessary for the templated copy constructor, for instance).
  120. BOOST_CONSTEXPR T real() const
  121. {
  122. return(a);
  123. }
  124. BOOST_CONSTEXPR quaternion<T> unreal() const
  125. {
  126. return(quaternion<T>(static_cast<T>(0), b, c, d));
  127. }
  128. BOOST_CONSTEXPR T R_component_1() const
  129. {
  130. return(a);
  131. }
  132. BOOST_CONSTEXPR T R_component_2() const
  133. {
  134. return(b);
  135. }
  136. BOOST_CONSTEXPR T R_component_3() const
  137. {
  138. return(c);
  139. }
  140. BOOST_CONSTEXPR T R_component_4() const
  141. {
  142. return(d);
  143. }
  144. BOOST_CONSTEXPR ::std::complex<T> C_component_1() const
  145. {
  146. return(::std::complex<T>(a, b));
  147. }
  148. BOOST_CONSTEXPR ::std::complex<T> C_component_2() const
  149. {
  150. return(::std::complex<T>(c, d));
  151. }
  152. BOOST_CXX14_CONSTEXPR void swap(quaternion& o)
  153. {
  154. #ifndef BOOST_NO_CXX14_CONSTEXPR
  155. using constexpr_detail::swap;
  156. #else
  157. using std::swap;
  158. #endif
  159. swap(a, o.a);
  160. swap(b, o.b);
  161. swap(c, o.c);
  162. swap(d, o.d);
  163. }
  164. // assignment operators
  165. template<typename X>
  166. BOOST_CXX14_CONSTEXPR quaternion<T> & operator = (quaternion<X> const & a_affecter)
  167. {
  168. a = static_cast<T>(a_affecter.R_component_1());
  169. b = static_cast<T>(a_affecter.R_component_2());
  170. c = static_cast<T>(a_affecter.R_component_3());
  171. d = static_cast<T>(a_affecter.R_component_4());
  172. return(*this);
  173. }
  174. BOOST_CXX14_CONSTEXPR quaternion<T> & operator = (quaternion<T> const & a_affecter)
  175. {
  176. a = a_affecter.a;
  177. b = a_affecter.b;
  178. c = a_affecter.c;
  179. d = a_affecter.d;
  180. return(*this);
  181. }
  182. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  183. BOOST_CXX14_CONSTEXPR quaternion<T> & operator = (quaternion<T> && a_affecter)
  184. {
  185. a = std::move(a_affecter.a);
  186. b = std::move(a_affecter.b);
  187. c = std::move(a_affecter.c);
  188. d = std::move(a_affecter.d);
  189. return(*this);
  190. }
  191. #endif
  192. BOOST_CXX14_CONSTEXPR quaternion<T> & operator = (T const & a_affecter)
  193. {
  194. a = a_affecter;
  195. b = c = d = static_cast<T>(0);
  196. return(*this);
  197. }
  198. BOOST_CXX14_CONSTEXPR quaternion<T> & operator = (::std::complex<T> const & a_affecter)
  199. {
  200. a = a_affecter.real();
  201. b = a_affecter.imag();
  202. c = d = static_cast<T>(0);
  203. return(*this);
  204. }
  205. // other assignment-related operators
  206. //
  207. // NOTE: Quaternion multiplication is *NOT* commutative;
  208. // symbolically, "q *= rhs;" means "q = q * rhs;"
  209. // and "q /= rhs;" means "q = q * inverse_of(rhs);"
  210. //
  211. // Note2: Each operator comes in 2 forms - one for the simple case where
  212. // type T throws no exceptions, and one exception-safe version
  213. // for the case where it might.
  214. private:
  215. BOOST_CXX14_CONSTEXPR quaternion<T> & do_add(T const & rhs, const std::true_type&)
  216. {
  217. a += rhs;
  218. return *this;
  219. }
  220. BOOST_CXX14_CONSTEXPR quaternion<T> & do_add(T const & rhs, const std::false_type&)
  221. {
  222. quaternion<T> result(a + rhs, b, c, d); // exception guard
  223. swap(result);
  224. return *this;
  225. }
  226. BOOST_CXX14_CONSTEXPR quaternion<T> & do_add(std::complex<T> const & rhs, const std::true_type&)
  227. {
  228. a += std::real(rhs);
  229. b += std::imag(rhs);
  230. return *this;
  231. }
  232. BOOST_CXX14_CONSTEXPR quaternion<T> & do_add(std::complex<T> const & rhs, const std::false_type&)
  233. {
  234. quaternion<T> result(a + std::real(rhs), b + std::imag(rhs), c, d); // exception guard
  235. swap(result);
  236. return *this;
  237. }
  238. template <class X>
  239. BOOST_CXX14_CONSTEXPR quaternion<T> & do_add(quaternion<X> const & rhs, const std::true_type&)
  240. {
  241. a += rhs.R_component_1();
  242. b += rhs.R_component_2();
  243. c += rhs.R_component_3();
  244. d += rhs.R_component_4();
  245. return *this;
  246. }
  247. template <class X>
  248. BOOST_CXX14_CONSTEXPR quaternion<T> & do_add(quaternion<X> const & rhs, const std::false_type&)
  249. {
  250. quaternion<T> result(a + rhs.R_component_1(), b + rhs.R_component_2(), c + rhs.R_component_3(), d + rhs.R_component_4()); // exception guard
  251. swap(result);
  252. return *this;
  253. }
  254. BOOST_CXX14_CONSTEXPR quaternion<T> & do_subtract(T const & rhs, const std::true_type&)
  255. {
  256. a -= rhs;
  257. return *this;
  258. }
  259. BOOST_CXX14_CONSTEXPR quaternion<T> & do_subtract(T const & rhs, const std::false_type&)
  260. {
  261. quaternion<T> result(a - rhs, b, c, d); // exception guard
  262. swap(result);
  263. return *this;
  264. }
  265. BOOST_CXX14_CONSTEXPR quaternion<T> & do_subtract(std::complex<T> const & rhs, const std::true_type&)
  266. {
  267. a -= std::real(rhs);
  268. b -= std::imag(rhs);
  269. return *this;
  270. }
  271. BOOST_CXX14_CONSTEXPR quaternion<T> & do_subtract(std::complex<T> const & rhs, const std::false_type&)
  272. {
  273. quaternion<T> result(a - std::real(rhs), b - std::imag(rhs), c, d); // exception guard
  274. swap(result);
  275. return *this;
  276. }
  277. template <class X>
  278. BOOST_CXX14_CONSTEXPR quaternion<T> & do_subtract(quaternion<X> const & rhs, const std::true_type&)
  279. {
  280. a -= rhs.R_component_1();
  281. b -= rhs.R_component_2();
  282. c -= rhs.R_component_3();
  283. d -= rhs.R_component_4();
  284. return *this;
  285. }
  286. template <class X>
  287. BOOST_CXX14_CONSTEXPR quaternion<T> & do_subtract(quaternion<X> const & rhs, const std::false_type&)
  288. {
  289. quaternion<T> result(a - rhs.R_component_1(), b - rhs.R_component_2(), c - rhs.R_component_3(), d - rhs.R_component_4()); // exception guard
  290. swap(result);
  291. return *this;
  292. }
  293. BOOST_CXX14_CONSTEXPR quaternion<T> & do_multiply(T const & rhs, const std::true_type&)
  294. {
  295. a *= rhs;
  296. b *= rhs;
  297. c *= rhs;
  298. d *= rhs;
  299. return *this;
  300. }
  301. BOOST_CXX14_CONSTEXPR quaternion<T> & do_multiply(T const & rhs, const std::false_type&)
  302. {
  303. quaternion<T> result(a * rhs, b * rhs, c * rhs, d * rhs); // exception guard
  304. swap(result);
  305. return *this;
  306. }
  307. BOOST_CXX14_CONSTEXPR quaternion<T> & do_divide(T const & rhs, const std::true_type&)
  308. {
  309. a /= rhs;
  310. b /= rhs;
  311. c /= rhs;
  312. d /= rhs;
  313. return *this;
  314. }
  315. BOOST_CXX14_CONSTEXPR quaternion<T> & do_divide(T const & rhs, const std::false_type&)
  316. {
  317. quaternion<T> result(a / rhs, b / rhs, c / rhs, d / rhs); // exception guard
  318. swap(result);
  319. return *this;
  320. }
  321. public:
  322. BOOST_CXX14_CONSTEXPR quaternion<T> & operator += (T const & rhs) { return do_add(rhs, detail::is_trivial_arithmetic_type<T>()); }
  323. BOOST_CXX14_CONSTEXPR quaternion<T> & operator += (::std::complex<T> const & rhs) { return do_add(rhs, detail::is_trivial_arithmetic_type<T>()); }
  324. template<typename X> BOOST_CXX14_CONSTEXPR quaternion<T> & operator += (quaternion<X> const & rhs) { return do_add(rhs, detail::is_trivial_arithmetic_type<T>()); }
  325. BOOST_CXX14_CONSTEXPR quaternion<T> & operator -= (T const & rhs) { return do_subtract(rhs, detail::is_trivial_arithmetic_type<T>()); }
  326. BOOST_CXX14_CONSTEXPR quaternion<T> & operator -= (::std::complex<T> const & rhs) { return do_subtract(rhs, detail::is_trivial_arithmetic_type<T>()); }
  327. template<typename X> BOOST_CXX14_CONSTEXPR quaternion<T> & operator -= (quaternion<X> const & rhs) { return do_subtract(rhs, detail::is_trivial_arithmetic_type<T>()); }
  328. BOOST_CXX14_CONSTEXPR quaternion<T> & operator *= (T const & rhs) { return do_multiply(rhs, detail::is_trivial_arithmetic_type<T>()); }
  329. BOOST_CXX14_CONSTEXPR quaternion<T> & operator *= (::std::complex<T> const & rhs)
  330. {
  331. T ar = rhs.real();
  332. T br = rhs.imag();
  333. quaternion<T> result(a*ar - b*br, a*br + b*ar, c*ar + d*br, -c*br+d*ar);
  334. swap(result);
  335. return(*this);
  336. }
  337. template<typename X>
  338. BOOST_CXX14_CONSTEXPR quaternion<T> & operator *= (quaternion<X> const & rhs)
  339. {
  340. T ar = static_cast<T>(rhs.R_component_1());
  341. T br = static_cast<T>(rhs.R_component_2());
  342. T cr = static_cast<T>(rhs.R_component_3());
  343. T dr = static_cast<T>(rhs.R_component_4());
  344. quaternion<T> result(a*ar - b*br - c*cr - d*dr, a*br + b*ar + c*dr - d*cr, a*cr - b*dr + c*ar + d*br, a*dr + b*cr - c*br + d*ar);
  345. swap(result);
  346. return(*this);
  347. }
  348. BOOST_CXX14_CONSTEXPR quaternion<T> & operator /= (T const & rhs) { return do_divide(rhs, detail::is_trivial_arithmetic_type<T>()); }
  349. BOOST_CXX14_CONSTEXPR quaternion<T> & operator /= (::std::complex<T> const & rhs)
  350. {
  351. T ar = rhs.real();
  352. T br = rhs.imag();
  353. T denominator = ar*ar+br*br;
  354. quaternion<T> result((+a*ar + b*br) / denominator, (-a*br + b*ar) / denominator, (+c*ar - d*br) / denominator, (+c*br + d*ar) / denominator);
  355. swap(result);
  356. return(*this);
  357. }
  358. template<typename X>
  359. BOOST_CXX14_CONSTEXPR quaternion<T> & operator /= (quaternion<X> const & rhs)
  360. {
  361. T ar = static_cast<T>(rhs.R_component_1());
  362. T br = static_cast<T>(rhs.R_component_2());
  363. T cr = static_cast<T>(rhs.R_component_3());
  364. T dr = static_cast<T>(rhs.R_component_4());
  365. T denominator = ar*ar+br*br+cr*cr+dr*dr;
  366. quaternion<T> result((+a*ar+b*br+c*cr+d*dr)/denominator, (-a*br+b*ar-c*dr+d*cr)/denominator, (-a*cr+b*dr+c*ar-d*br)/denominator, (-a*dr-b*cr+c*br+d*ar)/denominator);
  367. swap(result);
  368. return(*this);
  369. }
  370. private:
  371. T a, b, c, d;
  372. };
  373. // swap:
  374. template <class T>
  375. BOOST_CXX14_CONSTEXPR void swap(quaternion<T>& a, quaternion<T>& b) { a.swap(b); }
  376. // operator+
  377. template <class T1, class T2>
  378. inline BOOST_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  379. operator + (const quaternion<T1>& a, const T2& b)
  380. {
  381. return quaternion<T1>(static_cast<T1>(a.R_component_1() + b), a.R_component_2(), a.R_component_3(), a.R_component_4());
  382. }
  383. template <class T1, class T2>
  384. inline BOOST_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  385. operator + (const T1& a, const quaternion<T2>& b)
  386. {
  387. return quaternion<T2>(static_cast<T2>(b.R_component_1() + a), b.R_component_2(), b.R_component_3(), b.R_component_4());
  388. }
  389. template <class T1, class T2>
  390. inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  391. operator + (const quaternion<T1>& a, const std::complex<T2>& b)
  392. {
  393. return quaternion<T1>(a.R_component_1() + std::real(b), a.R_component_2() + std::imag(b), a.R_component_3(), a.R_component_4());
  394. }
  395. template <class T1, class T2>
  396. inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  397. operator + (const std::complex<T1>& a, const quaternion<T2>& b)
  398. {
  399. return quaternion<T1>(b.R_component_1() + std::real(a), b.R_component_2() + std::imag(a), b.R_component_3(), b.R_component_4());
  400. }
  401. template <class T>
  402. inline BOOST_CONSTEXPR quaternion<T> operator + (const quaternion<T>& a, const quaternion<T>& b)
  403. {
  404. return quaternion<T>(a.R_component_1() + b.R_component_1(), a.R_component_2() + b.R_component_2(), a.R_component_3() + b.R_component_3(), a.R_component_4() + b.R_component_4());
  405. }
  406. // operator-
  407. template <class T1, class T2>
  408. inline BOOST_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  409. operator - (const quaternion<T1>& a, const T2& b)
  410. {
  411. return quaternion<T1>(static_cast<T1>(a.R_component_1() - b), a.R_component_2(), a.R_component_3(), a.R_component_4());
  412. }
  413. template <class T1, class T2>
  414. inline BOOST_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  415. operator - (const T1& a, const quaternion<T2>& b)
  416. {
  417. return quaternion<T2>(static_cast<T2>(a - b.R_component_1()), -b.R_component_2(), -b.R_component_3(), -b.R_component_4());
  418. }
  419. template <class T1, class T2>
  420. inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  421. operator - (const quaternion<T1>& a, const std::complex<T2>& b)
  422. {
  423. return quaternion<T1>(a.R_component_1() - std::real(b), a.R_component_2() - std::imag(b), a.R_component_3(), a.R_component_4());
  424. }
  425. template <class T1, class T2>
  426. inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  427. operator - (const std::complex<T1>& a, const quaternion<T2>& b)
  428. {
  429. return quaternion<T1>(std::real(a) - b.R_component_1(), std::imag(a) - b.R_component_2(), -b.R_component_3(), -b.R_component_4());
  430. }
  431. template <class T>
  432. inline BOOST_CONSTEXPR quaternion<T> operator - (const quaternion<T>& a, const quaternion<T>& b)
  433. {
  434. return quaternion<T>(a.R_component_1() - b.R_component_1(), a.R_component_2() - b.R_component_2(), a.R_component_3() - b.R_component_3(), a.R_component_4() - b.R_component_4());
  435. }
  436. // operator*
  437. template <class T1, class T2>
  438. inline BOOST_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  439. operator * (const quaternion<T1>& a, const T2& b)
  440. {
  441. return quaternion<T1>(static_cast<T1>(a.R_component_1() * b), a.R_component_2() * b, a.R_component_3() * b, a.R_component_4() * b);
  442. }
  443. template <class T1, class T2>
  444. inline BOOST_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  445. operator * (const T1& a, const quaternion<T2>& b)
  446. {
  447. return quaternion<T2>(static_cast<T2>(a * b.R_component_1()), a * b.R_component_2(), a * b.R_component_3(), a * b.R_component_4());
  448. }
  449. template <class T1, class T2>
  450. inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  451. operator * (const quaternion<T1>& a, const std::complex<T2>& b)
  452. {
  453. quaternion<T1> result(a);
  454. result *= b;
  455. return result;
  456. }
  457. template <class T1, class T2>
  458. inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  459. operator * (const std::complex<T1>& a, const quaternion<T2>& b)
  460. {
  461. quaternion<T1> result(a);
  462. result *= b;
  463. return result;
  464. }
  465. template <class T>
  466. inline BOOST_CXX14_CONSTEXPR quaternion<T> operator * (const quaternion<T>& a, const quaternion<T>& b)
  467. {
  468. quaternion<T> result(a);
  469. result *= b;
  470. return result;
  471. }
  472. // operator/
  473. template <class T1, class T2>
  474. inline BOOST_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  475. operator / (const quaternion<T1>& a, const T2& b)
  476. {
  477. return quaternion<T1>(a.R_component_1() / b, a.R_component_2() / b, a.R_component_3() / b, a.R_component_4() / b);
  478. }
  479. template <class T1, class T2>
  480. inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  481. operator / (const T1& a, const quaternion<T2>& b)
  482. {
  483. quaternion<T2> result(a);
  484. result /= b;
  485. return result;
  486. }
  487. template <class T1, class T2>
  488. inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T2, T1>::value, quaternion<T1> >::type
  489. operator / (const quaternion<T1>& a, const std::complex<T2>& b)
  490. {
  491. quaternion<T1> result(a);
  492. result /= b;
  493. return result;
  494. }
  495. template <class T1, class T2>
  496. inline BOOST_CXX14_CONSTEXPR typename std::enable_if<std::is_convertible<T1, T2>::value, quaternion<T2> >::type
  497. operator / (const std::complex<T1>& a, const quaternion<T2>& b)
  498. {
  499. quaternion<T2> result(a);
  500. result /= b;
  501. return result;
  502. }
  503. template <class T>
  504. inline BOOST_CXX14_CONSTEXPR quaternion<T> operator / (const quaternion<T>& a, const quaternion<T>& b)
  505. {
  506. quaternion<T> result(a);
  507. result /= b;
  508. return result;
  509. }
  510. template<typename T>
  511. inline BOOST_CONSTEXPR const quaternion<T>& operator + (quaternion<T> const & q)
  512. {
  513. return q;
  514. }
  515. template<typename T>
  516. inline BOOST_CONSTEXPR quaternion<T> operator - (quaternion<T> const & q)
  517. {
  518. return(quaternion<T>(-q.R_component_1(),-q.R_component_2(),-q.R_component_3(),-q.R_component_4()));
  519. }
  520. template<typename R, typename T>
  521. inline BOOST_CONSTEXPR typename std::enable_if<std::is_convertible<R, T>::value, bool>::type operator == (R const & lhs, quaternion<T> const & rhs)
  522. {
  523. return (
  524. (rhs.R_component_1() == lhs)&&
  525. (rhs.R_component_2() == static_cast<T>(0))&&
  526. (rhs.R_component_3() == static_cast<T>(0))&&
  527. (rhs.R_component_4() == static_cast<T>(0))
  528. );
  529. }
  530. template<typename T, typename R>
  531. inline BOOST_CONSTEXPR typename std::enable_if<std::is_convertible<R, T>::value, bool>::type operator == (quaternion<T> const & lhs, R const & rhs)
  532. {
  533. return rhs == lhs;
  534. }
  535. template<typename T>
  536. inline BOOST_CONSTEXPR bool operator == (::std::complex<T> const & lhs, quaternion<T> const & rhs)
  537. {
  538. return (
  539. (rhs.R_component_1() == lhs.real())&&
  540. (rhs.R_component_2() == lhs.imag())&&
  541. (rhs.R_component_3() == static_cast<T>(0))&&
  542. (rhs.R_component_4() == static_cast<T>(0))
  543. );
  544. }
  545. template<typename T>
  546. inline BOOST_CONSTEXPR bool operator == (quaternion<T> const & lhs, ::std::complex<T> const & rhs)
  547. {
  548. return rhs == lhs;
  549. }
  550. template<typename T>
  551. inline BOOST_CONSTEXPR bool operator == (quaternion<T> const & lhs, quaternion<T> const & rhs)
  552. {
  553. return (
  554. (rhs.R_component_1() == lhs.R_component_1())&&
  555. (rhs.R_component_2() == lhs.R_component_2())&&
  556. (rhs.R_component_3() == lhs.R_component_3())&&
  557. (rhs.R_component_4() == lhs.R_component_4())
  558. );
  559. }
  560. template<typename R, typename T> inline BOOST_CONSTEXPR bool operator != (R const & lhs, quaternion<T> const & rhs) { return !(lhs == rhs); }
  561. template<typename T, typename R> inline BOOST_CONSTEXPR bool operator != (quaternion<T> const & lhs, R const & rhs) { return !(lhs == rhs); }
  562. template<typename T> inline BOOST_CONSTEXPR bool operator != (::std::complex<T> const & lhs, quaternion<T> const & rhs) { return !(lhs == rhs); }
  563. template<typename T> inline BOOST_CONSTEXPR bool operator != (quaternion<T> const & lhs, ::std::complex<T> const & rhs) { return !(lhs == rhs); }
  564. template<typename T> inline BOOST_CONSTEXPR bool operator != (quaternion<T> const & lhs, quaternion<T> const & rhs) { return !(lhs == rhs); }
  565. // Note: we allow the following formats, with a, b, c, and d reals
  566. // a
  567. // (a), (a,b), (a,b,c), (a,b,c,d)
  568. // (a,(c)), (a,(c,d)), ((a)), ((a),c), ((a),(c)), ((a),(c,d)), ((a,b)), ((a,b),c), ((a,b),(c)), ((a,b),(c,d))
  569. template<typename T, typename charT, class traits>
  570. ::std::basic_istream<charT,traits> & operator >> ( ::std::basic_istream<charT,traits> & is,
  571. quaternion<T> & q)
  572. {
  573. #ifdef BOOST_NO_STD_LOCALE
  574. #else
  575. const ::std::ctype<charT> & ct = ::std::use_facet< ::std::ctype<charT> >(is.getloc());
  576. #endif /* BOOST_NO_STD_LOCALE */
  577. T a = T();
  578. T b = T();
  579. T c = T();
  580. T d = T();
  581. ::std::complex<T> u = ::std::complex<T>();
  582. ::std::complex<T> v = ::std::complex<T>();
  583. charT ch = charT();
  584. char cc;
  585. is >> ch; // get the first lexeme
  586. if (!is.good()) goto finish;
  587. #ifdef BOOST_NO_STD_LOCALE
  588. cc = ch;
  589. #else
  590. cc = ct.narrow(ch, char());
  591. #endif /* BOOST_NO_STD_LOCALE */
  592. if (cc == '(') // read "(", possible: (a), (a,b), (a,b,c), (a,b,c,d), (a,(c)), (a,(c,d)), ((a)), ((a),c), ((a),(c)), ((a),(c,d)), ((a,b)), ((a,b),c), ((a,b),(c)), ((a,b,),(c,d,))
  593. {
  594. is >> ch; // get the second lexeme
  595. if (!is.good()) goto finish;
  596. #ifdef BOOST_NO_STD_LOCALE
  597. cc = ch;
  598. #else
  599. cc = ct.narrow(ch, char());
  600. #endif /* BOOST_NO_STD_LOCALE */
  601. if (cc == '(') // read "((", possible: ((a)), ((a),c), ((a),(c)), ((a),(c,d)), ((a,b)), ((a,b),c), ((a,b),(c)), ((a,b,),(c,d,))
  602. {
  603. is.putback(ch);
  604. is >> u; // we extract the first and second components
  605. a = u.real();
  606. b = u.imag();
  607. if (!is.good()) goto finish;
  608. is >> ch; // get the next lexeme
  609. if (!is.good()) goto finish;
  610. #ifdef BOOST_NO_STD_LOCALE
  611. cc = ch;
  612. #else
  613. cc = ct.narrow(ch, char());
  614. #endif /* BOOST_NO_STD_LOCALE */
  615. if (cc == ')') // format: ((a)) or ((a,b))
  616. {
  617. q = quaternion<T>(a,b);
  618. }
  619. else if (cc == ',') // read "((a)," or "((a,b),", possible: ((a),c), ((a),(c)), ((a),(c,d)), ((a,b),c), ((a,b),(c)), ((a,b,),(c,d,))
  620. {
  621. is >> v; // we extract the third and fourth components
  622. c = v.real();
  623. d = v.imag();
  624. if (!is.good()) goto finish;
  625. is >> ch; // get the last lexeme
  626. if (!is.good()) goto finish;
  627. #ifdef BOOST_NO_STD_LOCALE
  628. cc = ch;
  629. #else
  630. cc = ct.narrow(ch, char());
  631. #endif /* BOOST_NO_STD_LOCALE */
  632. if (cc == ')') // format: ((a),c), ((a),(c)), ((a),(c,d)), ((a,b),c), ((a,b),(c)) or ((a,b,),(c,d,))
  633. {
  634. q = quaternion<T>(a,b,c,d);
  635. }
  636. else // error
  637. {
  638. is.setstate(::std::ios_base::failbit);
  639. }
  640. }
  641. else // error
  642. {
  643. is.setstate(::std::ios_base::failbit);
  644. }
  645. }
  646. else // read "(a", possible: (a), (a,b), (a,b,c), (a,b,c,d), (a,(c)), (a,(c,d))
  647. {
  648. is.putback(ch);
  649. is >> a; // we extract the first component
  650. if (!is.good()) goto finish;
  651. is >> ch; // get the third lexeme
  652. if (!is.good()) goto finish;
  653. #ifdef BOOST_NO_STD_LOCALE
  654. cc = ch;
  655. #else
  656. cc = ct.narrow(ch, char());
  657. #endif /* BOOST_NO_STD_LOCALE */
  658. if (cc == ')') // format: (a)
  659. {
  660. q = quaternion<T>(a);
  661. }
  662. else if (cc == ',') // read "(a,", possible: (a,b), (a,b,c), (a,b,c,d), (a,(c)), (a,(c,d))
  663. {
  664. is >> ch; // get the fourth lexeme
  665. if (!is.good()) goto finish;
  666. #ifdef BOOST_NO_STD_LOCALE
  667. cc = ch;
  668. #else
  669. cc = ct.narrow(ch, char());
  670. #endif /* BOOST_NO_STD_LOCALE */
  671. if (cc == '(') // read "(a,(", possible: (a,(c)), (a,(c,d))
  672. {
  673. is.putback(ch);
  674. is >> v; // we extract the third and fourth component
  675. c = v.real();
  676. d = v.imag();
  677. if (!is.good()) goto finish;
  678. is >> ch; // get the ninth lexeme
  679. if (!is.good()) goto finish;
  680. #ifdef BOOST_NO_STD_LOCALE
  681. cc = ch;
  682. #else
  683. cc = ct.narrow(ch, char());
  684. #endif /* BOOST_NO_STD_LOCALE */
  685. if (cc == ')') // format: (a,(c)) or (a,(c,d))
  686. {
  687. q = quaternion<T>(a,b,c,d);
  688. }
  689. else // error
  690. {
  691. is.setstate(::std::ios_base::failbit);
  692. }
  693. }
  694. else // read "(a,b", possible: (a,b), (a,b,c), (a,b,c,d)
  695. {
  696. is.putback(ch);
  697. is >> b; // we extract the second component
  698. if (!is.good()) goto finish;
  699. is >> ch; // get the fifth lexeme
  700. if (!is.good()) goto finish;
  701. #ifdef BOOST_NO_STD_LOCALE
  702. cc = ch;
  703. #else
  704. cc = ct.narrow(ch, char());
  705. #endif /* BOOST_NO_STD_LOCALE */
  706. if (cc == ')') // format: (a,b)
  707. {
  708. q = quaternion<T>(a,b);
  709. }
  710. else if (cc == ',') // read "(a,b,", possible: (a,b,c), (a,b,c,d)
  711. {
  712. is >> c; // we extract the third component
  713. if (!is.good()) goto finish;
  714. is >> ch; // get the seventh lexeme
  715. if (!is.good()) goto finish;
  716. #ifdef BOOST_NO_STD_LOCALE
  717. cc = ch;
  718. #else
  719. cc = ct.narrow(ch, char());
  720. #endif /* BOOST_NO_STD_LOCALE */
  721. if (cc == ')') // format: (a,b,c)
  722. {
  723. q = quaternion<T>(a,b,c);
  724. }
  725. else if (cc == ',') // read "(a,b,c,", possible: (a,b,c,d)
  726. {
  727. is >> d; // we extract the fourth component
  728. if (!is.good()) goto finish;
  729. is >> ch; // get the ninth lexeme
  730. if (!is.good()) goto finish;
  731. #ifdef BOOST_NO_STD_LOCALE
  732. cc = ch;
  733. #else
  734. cc = ct.narrow(ch, char());
  735. #endif /* BOOST_NO_STD_LOCALE */
  736. if (cc == ')') // format: (a,b,c,d)
  737. {
  738. q = quaternion<T>(a,b,c,d);
  739. }
  740. else // error
  741. {
  742. is.setstate(::std::ios_base::failbit);
  743. }
  744. }
  745. else // error
  746. {
  747. is.setstate(::std::ios_base::failbit);
  748. }
  749. }
  750. else // error
  751. {
  752. is.setstate(::std::ios_base::failbit);
  753. }
  754. }
  755. }
  756. else // error
  757. {
  758. is.setstate(::std::ios_base::failbit);
  759. }
  760. }
  761. }
  762. else // format: a
  763. {
  764. is.putback(ch);
  765. is >> a; // we extract the first component
  766. if (!is.good()) goto finish;
  767. q = quaternion<T>(a);
  768. }
  769. finish:
  770. return(is);
  771. }
  772. template<typename T, typename charT, class traits>
  773. ::std::basic_ostream<charT,traits> & operator << ( ::std::basic_ostream<charT,traits> & os,
  774. quaternion<T> const & q)
  775. {
  776. ::std::basic_ostringstream<charT,traits> s;
  777. s.flags(os.flags());
  778. #ifdef BOOST_NO_STD_LOCALE
  779. #else
  780. s.imbue(os.getloc());
  781. #endif /* BOOST_NO_STD_LOCALE */
  782. s.precision(os.precision());
  783. s << '(' << q.R_component_1() << ','
  784. << q.R_component_2() << ','
  785. << q.R_component_3() << ','
  786. << q.R_component_4() << ')';
  787. return os << s.str();
  788. }
  789. // values
  790. template<typename T>
  791. inline BOOST_CONSTEXPR T real(quaternion<T> const & q)
  792. {
  793. return(q.real());
  794. }
  795. template<typename T>
  796. inline BOOST_CONSTEXPR quaternion<T> unreal(quaternion<T> const & q)
  797. {
  798. return(q.unreal());
  799. }
  800. template<typename T>
  801. inline T sup(quaternion<T> const & q)
  802. {
  803. using ::std::abs;
  804. return (std::max)((std::max)(abs(q.R_component_1()), abs(q.R_component_2())), (std::max)(abs(q.R_component_3()), abs(q.R_component_4())));
  805. }
  806. template<typename T>
  807. inline T l1(quaternion<T> const & q)
  808. {
  809. using ::std::abs;
  810. return abs(q.R_component_1()) + abs(q.R_component_2()) + abs(q.R_component_3()) + abs(q.R_component_4());
  811. }
  812. template<typename T>
  813. inline T abs(quaternion<T> const & q)
  814. {
  815. using ::std::abs;
  816. using ::std::sqrt;
  817. T maxim = sup(q); // overflow protection
  818. if (maxim == static_cast<T>(0))
  819. {
  820. return(maxim);
  821. }
  822. else
  823. {
  824. T mixam = static_cast<T>(1)/maxim; // prefer multiplications over divisions
  825. T a = q.R_component_1() * mixam;
  826. T b = q.R_component_2() * mixam;
  827. T c = q.R_component_3() * mixam;
  828. T d = q.R_component_4() * mixam;
  829. a *= a;
  830. b *= b;
  831. c *= c;
  832. d *= d;
  833. return(maxim * sqrt(a + b + c + d));
  834. }
  835. //return(sqrt(norm(q)));
  836. }
  837. // Note: This is the Cayley norm, not the Euclidean norm...
  838. template<typename T>
  839. inline BOOST_CXX14_CONSTEXPR T norm(quaternion<T>const & q)
  840. {
  841. return(real(q*conj(q)));
  842. }
  843. template<typename T>
  844. inline BOOST_CONSTEXPR quaternion<T> conj(quaternion<T> const & q)
  845. {
  846. return(quaternion<T>( +q.R_component_1(),
  847. -q.R_component_2(),
  848. -q.R_component_3(),
  849. -q.R_component_4()));
  850. }
  851. template<typename T>
  852. inline quaternion<T> spherical( T const & rho,
  853. T const & theta,
  854. T const & phi1,
  855. T const & phi2)
  856. {
  857. using ::std::cos;
  858. using ::std::sin;
  859. //T a = cos(theta)*cos(phi1)*cos(phi2);
  860. //T b = sin(theta)*cos(phi1)*cos(phi2);
  861. //T c = sin(phi1)*cos(phi2);
  862. //T d = sin(phi2);
  863. T courrant = static_cast<T>(1);
  864. T d = sin(phi2);
  865. courrant *= cos(phi2);
  866. T c = sin(phi1)*courrant;
  867. courrant *= cos(phi1);
  868. T b = sin(theta)*courrant;
  869. T a = cos(theta)*courrant;
  870. return(rho*quaternion<T>(a,b,c,d));
  871. }
  872. template<typename T>
  873. inline quaternion<T> semipolar( T const & rho,
  874. T const & alpha,
  875. T const & theta1,
  876. T const & theta2)
  877. {
  878. using ::std::cos;
  879. using ::std::sin;
  880. T a = cos(alpha)*cos(theta1);
  881. T b = cos(alpha)*sin(theta1);
  882. T c = sin(alpha)*cos(theta2);
  883. T d = sin(alpha)*sin(theta2);
  884. return(rho*quaternion<T>(a,b,c,d));
  885. }
  886. template<typename T>
  887. inline quaternion<T> multipolar( T const & rho1,
  888. T const & theta1,
  889. T const & rho2,
  890. T const & theta2)
  891. {
  892. using ::std::cos;
  893. using ::std::sin;
  894. T a = rho1*cos(theta1);
  895. T b = rho1*sin(theta1);
  896. T c = rho2*cos(theta2);
  897. T d = rho2*sin(theta2);
  898. return(quaternion<T>(a,b,c,d));
  899. }
  900. template<typename T>
  901. inline quaternion<T> cylindrospherical( T const & t,
  902. T const & radius,
  903. T const & longitude,
  904. T const & latitude)
  905. {
  906. using ::std::cos;
  907. using ::std::sin;
  908. T b = radius*cos(longitude)*cos(latitude);
  909. T c = radius*sin(longitude)*cos(latitude);
  910. T d = radius*sin(latitude);
  911. return(quaternion<T>(t,b,c,d));
  912. }
  913. template<typename T>
  914. inline quaternion<T> cylindrical(T const & r,
  915. T const & angle,
  916. T const & h1,
  917. T const & h2)
  918. {
  919. using ::std::cos;
  920. using ::std::sin;
  921. T a = r*cos(angle);
  922. T b = r*sin(angle);
  923. return(quaternion<T>(a,b,h1,h2));
  924. }
  925. // transcendentals
  926. // (please see the documentation)
  927. template<typename T>
  928. inline quaternion<T> exp(quaternion<T> const & q)
  929. {
  930. using ::std::exp;
  931. using ::std::cos;
  932. using ::boost::math::sinc_pi;
  933. T u = exp(real(q));
  934. T z = abs(unreal(q));
  935. T w = sinc_pi(z);
  936. return(u*quaternion<T>(cos(z),
  937. w*q.R_component_2(), w*q.R_component_3(),
  938. w*q.R_component_4()));
  939. }
  940. template<typename T>
  941. inline quaternion<T> cos(quaternion<T> const & q)
  942. {
  943. using ::std::sin;
  944. using ::std::cos;
  945. using ::std::cosh;
  946. using ::boost::math::sinhc_pi;
  947. T z = abs(unreal(q));
  948. T w = -sin(q.real())*sinhc_pi(z);
  949. return(quaternion<T>(cos(q.real())*cosh(z),
  950. w*q.R_component_2(), w*q.R_component_3(),
  951. w*q.R_component_4()));
  952. }
  953. template<typename T>
  954. inline quaternion<T> sin(quaternion<T> const & q)
  955. {
  956. using ::std::sin;
  957. using ::std::cos;
  958. using ::std::cosh;
  959. using ::boost::math::sinhc_pi;
  960. T z = abs(unreal(q));
  961. T w = +cos(q.real())*sinhc_pi(z);
  962. return(quaternion<T>(sin(q.real())*cosh(z),
  963. w*q.R_component_2(), w*q.R_component_3(),
  964. w*q.R_component_4()));
  965. }
  966. template<typename T>
  967. inline quaternion<T> tan(quaternion<T> const & q)
  968. {
  969. return(sin(q)/cos(q));
  970. }
  971. template<typename T>
  972. inline quaternion<T> cosh(quaternion<T> const & q)
  973. {
  974. return((exp(+q)+exp(-q))/static_cast<T>(2));
  975. }
  976. template<typename T>
  977. inline quaternion<T> sinh(quaternion<T> const & q)
  978. {
  979. return((exp(+q)-exp(-q))/static_cast<T>(2));
  980. }
  981. template<typename T>
  982. inline quaternion<T> tanh(quaternion<T> const & q)
  983. {
  984. return(sinh(q)/cosh(q));
  985. }
  986. template<typename T>
  987. quaternion<T> pow(quaternion<T> const & q,
  988. int n)
  989. {
  990. if (n > 1)
  991. {
  992. int m = n>>1;
  993. quaternion<T> result = pow(q, m);
  994. result *= result;
  995. if (n != (m<<1))
  996. {
  997. result *= q; // n odd
  998. }
  999. return(result);
  1000. }
  1001. else if (n == 1)
  1002. {
  1003. return(q);
  1004. }
  1005. else if (n == 0)
  1006. {
  1007. return(quaternion<T>(static_cast<T>(1)));
  1008. }
  1009. else /* n < 0 */
  1010. {
  1011. return(pow(quaternion<T>(static_cast<T>(1))/q,-n));
  1012. }
  1013. }
  1014. }
  1015. }
  1016. #endif /* BOOST_QUATERNION_HPP */