HSO3.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /********************************************************************************************/
  2. /* */
  3. /* HSO3.hpp header file */
  4. /* */
  5. /* This file is not currently part of the Boost library. It is simply an example of the use */
  6. /* quaternions can be put to. Hopefully it will be useful too. */
  7. /* */
  8. /* This file provides tools to convert between quaternions and R^3 rotation matrices. */
  9. /* */
  10. /********************************************************************************************/
  11. // (C) Copyright Hubert Holin 2001.
  12. // Distributed under the Boost Software License, Version 1.0. (See
  13. // accompanying file LICENSE_1_0.txt or copy at
  14. // http://www.boost.org/LICENSE_1_0.txt)
  15. #ifndef TEST_HSO3_HPP
  16. #define TEST_HSO3_HPP
  17. #include <algorithm>
  18. #if defined(__GNUC__) && (__GNUC__ < 3)
  19. #include <boost/limits.hpp>
  20. #else
  21. #include <limits>
  22. #endif
  23. #include <stdexcept>
  24. #include <string>
  25. #include <boost/math/quaternion.hpp>
  26. #if defined(__GNUC__) && (__GNUC__ < 3)
  27. // gcc 2.x ignores function scope using declarations, put them here instead:
  28. using namespace ::std;
  29. using namespace ::boost::math;
  30. #endif
  31. template<typename TYPE_FLOAT>
  32. struct R3_matrix
  33. {
  34. TYPE_FLOAT a11, a12, a13;
  35. TYPE_FLOAT a21, a22, a23;
  36. TYPE_FLOAT a31, a32, a33;
  37. };
  38. // Note: the input quaternion need not be of norm 1 for the following function
  39. template<typename TYPE_FLOAT>
  40. R3_matrix<TYPE_FLOAT> quaternion_to_R3_rotation(::boost::math::quaternion<TYPE_FLOAT> const & q)
  41. {
  42. using ::std::numeric_limits;
  43. TYPE_FLOAT a = q.R_component_1();
  44. TYPE_FLOAT b = q.R_component_2();
  45. TYPE_FLOAT c = q.R_component_3();
  46. TYPE_FLOAT d = q.R_component_4();
  47. TYPE_FLOAT aa = a*a;
  48. TYPE_FLOAT ab = a*b;
  49. TYPE_FLOAT ac = a*c;
  50. TYPE_FLOAT ad = a*d;
  51. TYPE_FLOAT bb = b*b;
  52. TYPE_FLOAT bc = b*c;
  53. TYPE_FLOAT bd = b*d;
  54. TYPE_FLOAT cc = c*c;
  55. TYPE_FLOAT cd = c*d;
  56. TYPE_FLOAT dd = d*d;
  57. TYPE_FLOAT norme_carre = aa+bb+cc+dd;
  58. if (norme_carre <= numeric_limits<TYPE_FLOAT>::epsilon())
  59. {
  60. ::std::string error_reporting("Argument to quaternion_to_R3_rotation is too small!");
  61. ::std::underflow_error bad_argument(error_reporting);
  62. throw(bad_argument);
  63. }
  64. R3_matrix<TYPE_FLOAT> out_matrix;
  65. out_matrix.a11 = (aa+bb-cc-dd)/norme_carre;
  66. out_matrix.a12 = 2*(-ad+bc)/norme_carre;
  67. out_matrix.a13 = 2*(ac+bd)/norme_carre;
  68. out_matrix.a21 = 2*(ad+bc)/norme_carre;
  69. out_matrix.a22 = (aa-bb+cc-dd)/norme_carre;
  70. out_matrix.a23 = 2*(-ab+cd)/norme_carre;
  71. out_matrix.a31 = 2*(-ac+bd)/norme_carre;
  72. out_matrix.a32 = 2*(ab+cd)/norme_carre;
  73. out_matrix.a33 = (aa-bb-cc+dd)/norme_carre;
  74. return(out_matrix);
  75. }
  76. template<typename TYPE_FLOAT>
  77. void find_invariant_vector( R3_matrix<TYPE_FLOAT> const & rot,
  78. TYPE_FLOAT & x,
  79. TYPE_FLOAT & y,
  80. TYPE_FLOAT & z)
  81. {
  82. using ::std::sqrt;
  83. using ::std::numeric_limits;
  84. TYPE_FLOAT b11 = rot.a11 - static_cast<TYPE_FLOAT>(1);
  85. TYPE_FLOAT b12 = rot.a12;
  86. TYPE_FLOAT b13 = rot.a13;
  87. TYPE_FLOAT b21 = rot.a21;
  88. TYPE_FLOAT b22 = rot.a22 - static_cast<TYPE_FLOAT>(1);
  89. TYPE_FLOAT b23 = rot.a23;
  90. TYPE_FLOAT b31 = rot.a31;
  91. TYPE_FLOAT b32 = rot.a32;
  92. TYPE_FLOAT b33 = rot.a33 - static_cast<TYPE_FLOAT>(1);
  93. TYPE_FLOAT minors[9] =
  94. {
  95. b11*b22-b12*b21,
  96. b11*b23-b13*b21,
  97. b12*b23-b13*b22,
  98. b11*b32-b12*b31,
  99. b11*b33-b13*b31,
  100. b12*b33-b13*b32,
  101. b21*b32-b22*b31,
  102. b21*b33-b23*b31,
  103. b22*b33-b23*b32
  104. };
  105. TYPE_FLOAT * where = ::std::max_element(minors, minors+9);
  106. TYPE_FLOAT det = *where;
  107. if (det <= numeric_limits<TYPE_FLOAT>::epsilon())
  108. {
  109. ::std::string error_reporting("Underflow error in find_invariant_vector!");
  110. ::std::underflow_error processing_error(error_reporting);
  111. throw(processing_error);
  112. }
  113. switch (where-minors)
  114. {
  115. case 0:
  116. z = static_cast<TYPE_FLOAT>(1);
  117. x = (-b13*b22+b12*b23)/det;
  118. y = (-b11*b23+b13*b21)/det;
  119. break;
  120. case 1:
  121. y = static_cast<TYPE_FLOAT>(1);
  122. x = (-b12*b23+b13*b22)/det;
  123. z = (-b11*b22+b12*b21)/det;
  124. break;
  125. case 2:
  126. x = static_cast<TYPE_FLOAT>(1);
  127. y = (-b11*b23+b13*b21)/det;
  128. z = (-b12*b21+b11*b22)/det;
  129. break;
  130. case 3:
  131. z = static_cast<TYPE_FLOAT>(1);
  132. x = (-b13*b32+b12*b33)/det;
  133. y = (-b11*b33+b13*b31)/det;
  134. break;
  135. case 4:
  136. y = static_cast<TYPE_FLOAT>(1);
  137. x = (-b12*b33+b13*b32)/det;
  138. z = (-b11*b32+b12*b31)/det;
  139. break;
  140. case 5:
  141. x = static_cast<TYPE_FLOAT>(1);
  142. y = (-b11*b33+b13*b31)/det;
  143. z = (-b12*b31+b11*b32)/det;
  144. break;
  145. case 6:
  146. z = static_cast<TYPE_FLOAT>(1);
  147. x = (-b23*b32+b22*b33)/det;
  148. y = (-b21*b33+b23*b31)/det;
  149. break;
  150. case 7:
  151. y = static_cast<TYPE_FLOAT>(1);
  152. x = (-b22*b33+b23*b32)/det;
  153. z = (-b21*b32+b22*b31)/det;
  154. break;
  155. case 8:
  156. x = static_cast<TYPE_FLOAT>(1);
  157. y = (-b21*b33+b23*b31)/det;
  158. z = (-b22*b31+b21*b32)/det;
  159. break;
  160. default:
  161. ::std::string error_reporting("Impossible condition in find_invariant_vector");
  162. ::std::logic_error processing_error(error_reporting);
  163. throw(processing_error);
  164. break;
  165. }
  166. TYPE_FLOAT vecnorm = sqrt(x*x+y*y+z*z);
  167. if (vecnorm <= numeric_limits<TYPE_FLOAT>::epsilon())
  168. {
  169. ::std::string error_reporting("Overflow error in find_invariant_vector!");
  170. ::std::overflow_error processing_error(error_reporting);
  171. throw(processing_error);
  172. }
  173. x /= vecnorm;
  174. y /= vecnorm;
  175. z /= vecnorm;
  176. }
  177. template<typename TYPE_FLOAT>
  178. void find_orthogonal_vector( TYPE_FLOAT x,
  179. TYPE_FLOAT y,
  180. TYPE_FLOAT z,
  181. TYPE_FLOAT & u,
  182. TYPE_FLOAT & v,
  183. TYPE_FLOAT & w)
  184. {
  185. using ::std::abs;
  186. using ::std::sqrt;
  187. using ::std::numeric_limits;
  188. TYPE_FLOAT vecnormsqr = x*x+y*y+z*z;
  189. if (vecnormsqr <= numeric_limits<TYPE_FLOAT>::epsilon())
  190. {
  191. ::std::string error_reporting("Underflow error in find_orthogonal_vector!");
  192. ::std::underflow_error processing_error(error_reporting);
  193. throw(processing_error);
  194. }
  195. TYPE_FLOAT lambda;
  196. TYPE_FLOAT components[3] =
  197. {
  198. abs(x),
  199. abs(y),
  200. abs(z)
  201. };
  202. TYPE_FLOAT * where = ::std::min_element(components, components+3);
  203. switch (where-components)
  204. {
  205. case 0:
  206. if (*where <= numeric_limits<TYPE_FLOAT>::epsilon())
  207. {
  208. v =
  209. w = static_cast<TYPE_FLOAT>(0);
  210. u = static_cast<TYPE_FLOAT>(1);
  211. }
  212. else
  213. {
  214. lambda = -x/vecnormsqr;
  215. u = static_cast<TYPE_FLOAT>(1) + lambda*x;
  216. v = lambda*y;
  217. w = lambda*z;
  218. }
  219. break;
  220. case 1:
  221. if (*where <= numeric_limits<TYPE_FLOAT>::epsilon())
  222. {
  223. u =
  224. w = static_cast<TYPE_FLOAT>(0);
  225. v = static_cast<TYPE_FLOAT>(1);
  226. }
  227. else
  228. {
  229. lambda = -y/vecnormsqr;
  230. u = lambda*x;
  231. v = static_cast<TYPE_FLOAT>(1) + lambda*y;
  232. w = lambda*z;
  233. }
  234. break;
  235. case 2:
  236. if (*where <= numeric_limits<TYPE_FLOAT>::epsilon())
  237. {
  238. u =
  239. v = static_cast<TYPE_FLOAT>(0);
  240. w = static_cast<TYPE_FLOAT>(1);
  241. }
  242. else
  243. {
  244. lambda = -z/vecnormsqr;
  245. u = lambda*x;
  246. v = lambda*y;
  247. w = static_cast<TYPE_FLOAT>(1) + lambda*z;
  248. }
  249. break;
  250. default:
  251. ::std::string error_reporting("Impossible condition in find_invariant_vector");
  252. ::std::logic_error processing_error(error_reporting);
  253. throw(processing_error);
  254. break;
  255. }
  256. TYPE_FLOAT vecnorm = sqrt(u*u+v*v+w*w);
  257. if (vecnorm <= numeric_limits<TYPE_FLOAT>::epsilon())
  258. {
  259. ::std::string error_reporting("Underflow error in find_orthogonal_vector!");
  260. ::std::underflow_error processing_error(error_reporting);
  261. throw(processing_error);
  262. }
  263. u /= vecnorm;
  264. v /= vecnorm;
  265. w /= vecnorm;
  266. }
  267. // Note: we want [[v, v, w], [r, s, t], [x, y, z]] to be a direct orthogonal basis
  268. // of R^3. It might not be orthonormal, however, and we do not check if the
  269. // two input vectors are colinear or not.
  270. template<typename TYPE_FLOAT>
  271. void find_vector_for_BOD(TYPE_FLOAT x,
  272. TYPE_FLOAT y,
  273. TYPE_FLOAT z,
  274. TYPE_FLOAT u,
  275. TYPE_FLOAT v,
  276. TYPE_FLOAT w,
  277. TYPE_FLOAT & r,
  278. TYPE_FLOAT & s,
  279. TYPE_FLOAT & t)
  280. {
  281. r = +y*w-z*v;
  282. s = -x*w+z*u;
  283. t = +x*v-y*u;
  284. }
  285. template<typename TYPE_FLOAT>
  286. inline bool is_R3_rotation_matrix(R3_matrix<TYPE_FLOAT> const & mat)
  287. {
  288. using ::std::abs;
  289. using ::std::numeric_limits;
  290. return (
  291. !(
  292. (abs(mat.a11*mat.a11+mat.a21*mat.a21+mat.a31*mat.a31 - static_cast<TYPE_FLOAT>(1)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())||
  293. (abs(mat.a11*mat.a12+mat.a21*mat.a22+mat.a31*mat.a32 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())||
  294. (abs(mat.a11*mat.a13+mat.a21*mat.a23+mat.a31*mat.a33 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())||
  295. //(abs(mat.a11*mat.a12+mat.a21*mat.a22+mat.a31*mat.a32 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())||
  296. (abs(mat.a12*mat.a12+mat.a22*mat.a22+mat.a32*mat.a32 - static_cast<TYPE_FLOAT>(1)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())||
  297. (abs(mat.a12*mat.a13+mat.a22*mat.a23+mat.a32*mat.a33 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())||
  298. //(abs(mat.a11*mat.a13+mat.a21*mat.a23+mat.a31*mat.a33 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())||
  299. //(abs(mat.a12*mat.a13+mat.a22*mat.a23+mat.a32*mat.a33 - static_cast<TYPE_FLOAT>(0)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())||
  300. (abs(mat.a13*mat.a13+mat.a23*mat.a23+mat.a33*mat.a33 - static_cast<TYPE_FLOAT>(1)) > static_cast<TYPE_FLOAT>(10)*numeric_limits<TYPE_FLOAT>::epsilon())
  301. )
  302. );
  303. }
  304. template<typename TYPE_FLOAT>
  305. ::boost::math::quaternion<TYPE_FLOAT> R3_rotation_to_quaternion( R3_matrix<TYPE_FLOAT> const & rot,
  306. ::boost::math::quaternion<TYPE_FLOAT> const * hint = 0)
  307. {
  308. using ::boost::math::abs;
  309. using ::std::abs;
  310. using ::std::sqrt;
  311. using ::std::numeric_limits;
  312. if (!is_R3_rotation_matrix(rot))
  313. {
  314. ::std::string error_reporting("Argument to R3_rotation_to_quaternion is not an R^3 rotation matrix!");
  315. ::std::range_error bad_argument(error_reporting);
  316. throw(bad_argument);
  317. }
  318. ::boost::math::quaternion<TYPE_FLOAT> q;
  319. if (
  320. (abs(rot.a11 - static_cast<TYPE_FLOAT>(1)) <= numeric_limits<TYPE_FLOAT>::epsilon())&&
  321. (abs(rot.a22 - static_cast<TYPE_FLOAT>(1)) <= numeric_limits<TYPE_FLOAT>::epsilon())&&
  322. (abs(rot.a33 - static_cast<TYPE_FLOAT>(1)) <= numeric_limits<TYPE_FLOAT>::epsilon())
  323. )
  324. {
  325. q = ::boost::math::quaternion<TYPE_FLOAT>(1);
  326. }
  327. else
  328. {
  329. TYPE_FLOAT cos_theta = (rot.a11+rot.a22+rot.a33-static_cast<TYPE_FLOAT>(1))/static_cast<TYPE_FLOAT>(2);
  330. TYPE_FLOAT stuff = (cos_theta+static_cast<TYPE_FLOAT>(1))/static_cast<TYPE_FLOAT>(2);
  331. TYPE_FLOAT cos_theta_sur_2 = sqrt(stuff);
  332. TYPE_FLOAT sin_theta_sur_2 = sqrt(1-stuff);
  333. TYPE_FLOAT x;
  334. TYPE_FLOAT y;
  335. TYPE_FLOAT z;
  336. find_invariant_vector(rot, x, y, z);
  337. TYPE_FLOAT u;
  338. TYPE_FLOAT v;
  339. TYPE_FLOAT w;
  340. find_orthogonal_vector(x, y, z, u, v, w);
  341. TYPE_FLOAT r;
  342. TYPE_FLOAT s;
  343. TYPE_FLOAT t;
  344. find_vector_for_BOD(x, y, z, u, v, w, r, s, t);
  345. TYPE_FLOAT ru = rot.a11*u+rot.a12*v+rot.a13*w;
  346. TYPE_FLOAT rv = rot.a21*u+rot.a22*v+rot.a23*w;
  347. TYPE_FLOAT rw = rot.a31*u+rot.a32*v+rot.a33*w;
  348. TYPE_FLOAT angle_sign_determinator = r*ru+s*rv+t*rw;
  349. if (angle_sign_determinator > +numeric_limits<TYPE_FLOAT>::epsilon())
  350. {
  351. q = ::boost::math::quaternion<TYPE_FLOAT>(cos_theta_sur_2, +x*sin_theta_sur_2, +y*sin_theta_sur_2, +z*sin_theta_sur_2);
  352. }
  353. else if (angle_sign_determinator < -numeric_limits<TYPE_FLOAT>::epsilon())
  354. {
  355. q = ::boost::math::quaternion<TYPE_FLOAT>(cos_theta_sur_2, -x*sin_theta_sur_2, -y*sin_theta_sur_2, -z*sin_theta_sur_2);
  356. }
  357. else
  358. {
  359. TYPE_FLOAT desambiguator = u*ru+v*rv+w*rw;
  360. if (desambiguator >= static_cast<TYPE_FLOAT>(1))
  361. {
  362. q = ::boost::math::quaternion<TYPE_FLOAT>(0, +x, +y, +z);
  363. }
  364. else
  365. {
  366. q = ::boost::math::quaternion<TYPE_FLOAT>(0, -x, -y, -z);
  367. }
  368. }
  369. }
  370. if ((hint != 0) && (abs(*hint+q) < abs(*hint-q)))
  371. {
  372. return(-q);
  373. }
  374. return(q);
  375. }
  376. #endif /* TEST_HSO3_HPP */