PageRenderTime 26ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/src/q2m.c

https://github.com/mattbornski/spice
C | 592 lines | 37 code | 201 blank | 354 comment | 4 complexity | e9b57ad636a28fa99f7f0413f3d857bb MD5 | raw file
  1. /* q2m.f -- translated by f2c (version 19980913).
  2. You must link the resulting object file with the libraries:
  3. -lf2c -lm (in that order)
  4. */
  5. #include "f2c.h"
  6. /* $Procedure Q2M ( Quaternion to matrix ) */
  7. /* Subroutine */ int q2m_(doublereal *q, doublereal *r__)
  8. {
  9. doublereal l2, q01, q02, q03, q12, q13, q23, sharpn, q1s, q2s, q3s;
  10. /* $ Abstract */
  11. /* Find the rotation matrix corresponding to a specified unit */
  12. /* quaternion. */
  13. /* $ Disclaimer */
  14. /* THIS SOFTWARE AND ANY RELATED MATERIALS WERE CREATED BY THE */
  15. /* CALIFORNIA INSTITUTE OF TECHNOLOGY (CALTECH) UNDER A U.S. */
  16. /* GOVERNMENT CONTRACT WITH THE NATIONAL AERONAUTICS AND SPACE */
  17. /* ADMINISTRATION (NASA). THE SOFTWARE IS TECHNOLOGY AND SOFTWARE */
  18. /* PUBLICLY AVAILABLE UNDER U.S. EXPORT LAWS AND IS PROVIDED "AS-IS" */
  19. /* TO THE RECIPIENT WITHOUT WARRANTY OF ANY KIND, INCLUDING ANY */
  20. /* WARRANTIES OF PERFORMANCE OR MERCHANTABILITY OR FITNESS FOR A */
  21. /* PARTICULAR USE OR PURPOSE (AS SET FORTH IN UNITED STATES UCC */
  22. /* SECTIONS 2312-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE */
  23. /* SOFTWARE AND RELATED MATERIALS, HOWEVER USED. */
  24. /* IN NO EVENT SHALL CALTECH, ITS JET PROPULSION LABORATORY, OR NASA */
  25. /* BE LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING, BUT NOT */
  26. /* LIMITED TO, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, */
  27. /* INCLUDING ECONOMIC DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, */
  28. /* REGARDLESS OF WHETHER CALTECH, JPL, OR NASA BE ADVISED, HAVE */
  29. /* REASON TO KNOW, OR, IN FACT, SHALL KNOW OF THE POSSIBILITY. */
  30. /* RECIPIENT BEARS ALL RISK RELATING TO QUALITY AND PERFORMANCE OF */
  31. /* THE SOFTWARE AND ANY RELATED MATERIALS, AND AGREES TO INDEMNIFY */
  32. /* CALTECH AND NASA FOR ALL THIRD-PARTY CLAIMS RESULTING FROM THE */
  33. /* ACTIONS OF RECIPIENT IN THE USE OF THE SOFTWARE. */
  34. /* $ Required_Reading */
  35. /* ROTATION */
  36. /* $ Keywords */
  37. /* MATH */
  38. /* MATRIX */
  39. /* ROTATION */
  40. /* $ Declarations */
  41. /* $ Brief_I/O */
  42. /* Variable I/O Description */
  43. /* -------- --- -------------------------------------------------- */
  44. /* Q I A unit quaternion. */
  45. /* R O A rotation matrix corresponding to Q. */
  46. /* $ Detailed_Input */
  47. /* Q is a unit-length SPICE-style quaternion. Q has the */
  48. /* property that */
  49. /* || Q || = 1 */
  50. /* See the discussion of quaternion styles in */
  51. /* Particulars below. */
  52. /* $ Detailed_Output */
  53. /* R is a 3 by 3 rotation matrix representing the same */
  54. /* rotation as does Q. See the discussion titled */
  55. /* "Associating SPICE Quaternions with Rotation */
  56. /* Matrices" in Particulars below. */
  57. /* $ Parameters */
  58. /* None. */
  59. /* $ Exceptions */
  60. /* Error free. */
  61. /* 1) If Q is not a unit quaternion, the output matrix M is */
  62. /* the rotation matrix that is the result of converting */
  63. /* normalized Q to a rotation matrix. */
  64. /* 2) If Q is the zero quaternion, the output matrix M is */
  65. /* the identity matrix. */
  66. /* $ Files */
  67. /* None. */
  68. /* $ Particulars */
  69. /* If a 4-dimensional vector Q satisfies the equality */
  70. /* || Q || = 1 */
  71. /* or equivalently */
  72. /* 2 2 2 2 */
  73. /* Q(0) + Q(1) + Q(2) + Q(3) = 1, */
  74. /* then we can always find a unit vector A and a scalar r such that */
  75. /* Q = ( cos(r/2), sin(r/2)A(1), sin(r/2)A(2), sin(r/2)A(3) ). */
  76. /* We can interpret A and r as the axis and rotation angle of a */
  77. /* rotation in 3-space. If we restrict r to the range [0, pi], */
  78. /* then r and A are uniquely determined, except if r = pi. In this */
  79. /* special case, A and -A are both valid rotation axes. */
  80. /* Every rotation is represented by a unique orthogonal matrix; this */
  81. /* routine returns that unique rotation matrix corresponding to Q. */
  82. /* The SPICELIB routine M2Q is a one-sided inverse of this routine: */
  83. /* given any rotation matrix R, the calls */
  84. /* CALL M2Q ( R, Q ) */
  85. /* CALL Q2M ( Q, R ) */
  86. /* leave R unchanged, except for round-off error. However, the */
  87. /* calls */
  88. /* CALL Q2M ( Q, R ) */
  89. /* CALL M2Q ( R, Q ) */
  90. /* might preserve Q or convert Q to -Q. */
  91. /* Quaternion Styles */
  92. /* ----------------- */
  93. /* There are different "styles" of quaternions used in */
  94. /* science and engineering applications. Quaternion styles */
  95. /* are characterized by */
  96. /* - The order of quaternion elements */
  97. /* - The quaternion multiplication formula */
  98. /* - The convention for associating quaternions */
  99. /* with rotation matrices */
  100. /* Two of the commonly used styles are */
  101. /* - "SPICE" */
  102. /* > Invented by Sir William Rowan Hamilton */
  103. /* > Frequently used in mathematics and physics textbooks */
  104. /* - "Engineering" */
  105. /* > Widely used in aerospace engineering applications */
  106. /* SPICELIB subroutine interfaces ALWAYS use SPICE quaternions. */
  107. /* Quaternions of any other style must be converted to SPICE */
  108. /* quaternions before they are passed to SPICELIB routines. */
  109. /* Relationship between SPICE and Engineering Quaternions */
  110. /* ------------------------------------------------------ */
  111. /* Let M be a rotation matrix such that for any vector V, */
  112. /* M*V */
  113. /* is the result of rotating V by theta radians in the */
  114. /* counterclockwise direction about unit rotation axis vector A. */
  115. /* Then the SPICE quaternions representing M are */
  116. /* (+/-) ( cos(theta/2), */
  117. /* sin(theta/2) A(1), */
  118. /* sin(theta/2) A(2), */
  119. /* sin(theta/2) A(3) ) */
  120. /* while the engineering quaternions representing M are */
  121. /* (+/-) ( -sin(theta/2) A(1), */
  122. /* -sin(theta/2) A(2), */
  123. /* -sin(theta/2) A(3), */
  124. /* cos(theta/2) ) */
  125. /* For both styles of quaternions, if a quaternion q represents */
  126. /* a rotation matrix M, then -q represents M as well. */
  127. /* Given an engineering quaternion */
  128. /* QENG = ( q0, q1, q2, q3 ) */
  129. /* the equivalent SPICE quaternion is */
  130. /* QSPICE = ( q3, -q0, -q1, -q2 ) */
  131. /* Associating SPICE Quaternions with Rotation Matrices */
  132. /* ---------------------------------------------------- */
  133. /* Let FROM and TO be two right-handed reference frames, for */
  134. /* example, an inertial frame and a spacecraft-fixed frame. Let the */
  135. /* symbols */
  136. /* V , V */
  137. /* FROM TO */
  138. /* denote, respectively, an arbitrary vector expressed relative to */
  139. /* the FROM and TO frames. Let M denote the transformation matrix */
  140. /* that transforms vectors from frame FROM to frame TO; then */
  141. /* V = M * V */
  142. /* TO FROM */
  143. /* where the expression on the right hand side represents left */
  144. /* multiplication of the vector by the matrix. */
  145. /* Then if the unit-length SPICE quaternion q represents M, where */
  146. /* q = (q0, q1, q2, q3) */
  147. /* the elements of M are derived from the elements of q as follows: */
  148. /* +- -+ */
  149. /* | 2 2 | */
  150. /* | 1 - 2*( q2 + q3 ) 2*(q1*q2 - q0*q3) 2*(q1*q3 + q0*q2) | */
  151. /* | | */
  152. /* | | */
  153. /* | 2 2 | */
  154. /* M = | 2*(q1*q2 + q0*q3) 1 - 2*( q1 + q3 ) 2*(q2*q3 - q0*q1) | */
  155. /* | | */
  156. /* | | */
  157. /* | 2 2 | */
  158. /* | 2*(q1*q3 - q0*q2) 2*(q2*q3 + q0*q1) 1 - 2*( q1 + q2 ) | */
  159. /* | | */
  160. /* +- -+ */
  161. /* Note that substituting the elements of -q for those of q in the */
  162. /* right hand side leaves each element of M unchanged; this shows */
  163. /* that if a quaternion q represents a matrix M, then so does the */
  164. /* quaternion -q. */
  165. /* To map the rotation matrix M to a unit quaternion, we start by */
  166. /* decomposing the rotation matrix as a sum of symmetric */
  167. /* and skew-symmetric parts: */
  168. /* 2 */
  169. /* M = [ I + (1-cos(theta)) OMEGA ] + [ sin(theta) OMEGA ] */
  170. /* symmetric skew-symmetric */
  171. /* OMEGA is a skew-symmetric matrix of the form */
  172. /* +- -+ */
  173. /* | 0 -n3 n2 | */
  174. /* | | */
  175. /* OMEGA = | n3 0 -n1 | */
  176. /* | | */
  177. /* | -n2 n1 0 | */
  178. /* +- -+ */
  179. /* The vector N of matrix entries (n1, n2, n3) is the rotation axis */
  180. /* of M and theta is M's rotation angle. Note that N and theta */
  181. /* are not unique. */
  182. /* Let */
  183. /* C = cos(theta/2) */
  184. /* S = sin(theta/2) */
  185. /* Then the unit quaternions Q corresponding to M are */
  186. /* Q = +/- ( C, S*n1, S*n2, S*n3 ) */
  187. /* The mappings between quaternions and the corresponding rotations */
  188. /* are carried out by the SPICELIB routines */
  189. /* Q2M {quaternion to matrix} */
  190. /* M2Q {matrix to quaternion} */
  191. /* M2Q always returns a quaternion with scalar part greater than */
  192. /* or equal to zero. */
  193. /* SPICE Quaternion Multiplication Formula */
  194. /* --------------------------------------- */
  195. /* Given a SPICE quaternion */
  196. /* Q = ( q0, q1, q2, q3 ) */
  197. /* corresponding to rotation axis A and angle theta as above, we can */
  198. /* represent Q using "scalar + vector" notation as follows: */
  199. /* s = q0 = cos(theta/2) */
  200. /* v = ( q1, q2, q3 ) = sin(theta/2) * A */
  201. /* Q = s + v */
  202. /* Let Q1 and Q2 be SPICE quaternions with respective scalar */
  203. /* and vector parts s1, s2 and v1, v2: */
  204. /* Q1 = s1 + v1 */
  205. /* Q2 = s2 + v2 */
  206. /* We represent the dot product of v1 and v2 by */
  207. /* <v1, v2> */
  208. /* and the cross product of v1 and v2 by */
  209. /* v1 x v2 */
  210. /* Then the SPICE quaternion product is */
  211. /* Q1*Q2 = s1*s2 - <v1,v2> + s1*v2 + s2*v1 + (v1 x v2) */
  212. /* If Q1 and Q2 represent the rotation matrices M1 and M2 */
  213. /* respectively, then the quaternion product */
  214. /* Q1*Q2 */
  215. /* represents the matrix product */
  216. /* M1*M2 */
  217. /* $ Examples */
  218. /* 1) A case amenable to checking by hand calculation: */
  219. /* To convert the quaternion */
  220. /* Q = ( sqrt(2)/2, 0, 0, -sqrt(2)/2 ) */
  221. /* to a rotation matrix, we can use the code fragment */
  222. /* Q(0) = DSQRT(2)/2.D0 */
  223. /* Q(1) = 0.D0 */
  224. /* Q(2) = 0.D0 */
  225. /* Q(3) = -DSQRT(2)/2.D0 */
  226. /* CALL Q2M ( Q, R ) */
  227. /* The matrix R will be set equal to */
  228. /* +- -+ */
  229. /* | 0 1 0 | */
  230. /* | | */
  231. /* | -1 0 0 |. */
  232. /* | | */
  233. /* | 0 0 1 | */
  234. /* +- -+ */
  235. /* Why? Well, Q represents a rotation by some angle r about */
  236. /* some axis vector A, where r and A satisfy */
  237. /* Q = */
  238. /* ( cos(r/2), sin(r/2)A(1), sin(r/2)A(2), sin(r/2)A(3) ). */
  239. /* In this example, */
  240. /* Q = ( sqrt(2)/2, 0, 0, -sqrt(2)/2 ), */
  241. /* so */
  242. /* cos(r/2) = sqrt(2)/2. */
  243. /* Assuming that r is in the interval [0, pi], we must have */
  244. /* r = pi/2, */
  245. /* so */
  246. /* sin(r/2) = sqrt(2)/2. */
  247. /* Since the second through fourth components of Q represent */
  248. /* sin(r/2) * A, */
  249. /* it follows that */
  250. /* A = ( 0, 0, -1 ). */
  251. /* So Q represents a transformation that rotates vectors by */
  252. /* pi/2 about the negative z-axis. This is equivalent to a */
  253. /* coordinate system rotation of pi/2 about the positive */
  254. /* z-axis; and we recognize R as the matrix */
  255. /* [ pi/2 ] . */
  256. /* 3 */
  257. /* 2) Finding a set of Euler angles that represent a rotation */
  258. /* specified by a quaternion: */
  259. /* Suppose our rotation R is represented by the quaternion */
  260. /* Q. To find angles TAU, ALPHA, DELTA such that */
  261. /* R = [ TAU ] [ pi/2 - DELTA ] [ ALPHA ] , */
  262. /* 3 2 3 */
  263. /* we can use the code fragment */
  264. /* CALL Q2M ( Q, R ) */
  265. /* CALL M2EUL ( R, 3, 2, 3, */
  266. /* . TAU, DELTA, ALPHA ) */
  267. /* DELTA = HALFPI() - DELTA */
  268. /* $ Restrictions */
  269. /* None. */
  270. /* $ Literature_References */
  271. /* [1] NAIF document 179.0, "Rotations and their Habits", by */
  272. /* W. L. Taber. */
  273. /* $ Author_and_Institution */
  274. /* N.J. Bachman (JPL) */
  275. /* W.L. Taber (JPL) */
  276. /* F.S. Turner (JPL) */
  277. /* $ Version */
  278. /* - SPICELIB Version 1.1.2, 26-FEB-2008 (NJB) */
  279. /* Updated header; added information about SPICE */
  280. /* quaternion conventions. */
  281. /* - SPICELIB Version 1.1.1, 13-JUN-2002 (FST) */
  282. /* Updated the Exceptions section to clarify exceptions that */
  283. /* are the result of changes made in the previous version of */
  284. /* the routine. */
  285. /* - SPICELIB Version 1.1.0, 04-MAR-1999 (WLT) */
  286. /* Added code to handle the case in which the input quaternion */
  287. /* is not of length 1. */
  288. /* - SPICELIB Version 1.0.1, 10-MAR-1992 (WLT) */
  289. /* Comment section for permuted index source lines was added */
  290. /* following the header. */
  291. /* - SPICELIB Version 1.0.0, 30-AUG-1990 (NJB) */
  292. /* -& */
  293. /* $ Index_Entries */
  294. /* quaternion to matrix */
  295. /* -& */
  296. /* Local variables */
  297. /* If a matrix R represents a rotation of r radians about the unit */
  298. /* vector n, we know that R can be represented as */
  299. /* 2 */
  300. /* I + sin(r) N + [ 1 - cos(r) ] N , */
  301. /* where N is the matrix that satisfies */
  302. /* Nv = n x v */
  303. /* for all vectors v, namely */
  304. /* +- -+ */
  305. /* | 0 -n n | */
  306. /* | 3 2 | */
  307. /* | | */
  308. /* N = | n 0 -n |. */
  309. /* | 3 1 | */
  310. /* | | */
  311. /* | -n n 0 | */
  312. /* | 2 1 | */
  313. /* +- -+ */
  314. /* Define S as */
  315. /* sin(r/2) N, */
  316. /* and let our input quaternion Q be */
  317. /* ( q , q , q , q ). */
  318. /* 0 1 2 3 */
  319. /* Using the facts that */
  320. /* 2 */
  321. /* 1 - cos(r) = 2 sin (r/2) */
  322. /* and */
  323. /* sin(r) = 2 cos(r/2) sin(r/2), */
  324. /* we can express R as */
  325. /* 2 */
  326. /* I + 2 cos(r/2) S + 2 S, */
  327. /* or */
  328. /* 2 */
  329. /* I + 2 q S + 2 S. */
  330. /* 0 */
  331. /* Since S is just */
  332. /* +- -+ */
  333. /* | 0 -q q | */
  334. /* | 3 2 | */
  335. /* | | */
  336. /* | q 0 -q |, */
  337. /* | 3 1 | */
  338. /* | | */
  339. /* | -q q 0 | */
  340. /* | 2 1 | */
  341. /* +- -+ */
  342. /* our expression for R comes out to */
  343. /* +- -+ */
  344. /* | 2 2 | */
  345. /* | 1 - 2 ( q + q ) 2( q q - q q ) 2 ( q q + q q ) | */
  346. /* | 2 3 1 2 0 3 1 3 0 2 | */
  347. /* | | */
  348. /* | 2 2 | */
  349. /* | 2( q q + q q ) 1 - 2 ( q + q ) 2 ( q q - q q ) |. */
  350. /* | 1 2 0 3 1 3 2 3 0 1 | */
  351. /* | | */
  352. /* | 2 2 | */
  353. /* | 2( q q - q q ) 2 ( q q + q q ) 1 - 2 ( q + q ) | */
  354. /* | 1 3 0 2 2 3 0 1 1 2 | */
  355. /* +- -+ */
  356. /* For efficiency, we avoid duplicating calculations where possible. */
  357. q01 = q[0] * q[1];
  358. q02 = q[0] * q[2];
  359. q03 = q[0] * q[3];
  360. q12 = q[1] * q[2];
  361. q13 = q[1] * q[3];
  362. q23 = q[2] * q[3];
  363. q1s = q[1] * q[1];
  364. q2s = q[2] * q[2];
  365. q3s = q[3] * q[3];
  366. /* We sharpen the computation by effectively converting Q to */
  367. /* a unit quaternion if it isn't one already. */
  368. l2 = q[0] * q[0] + q1s + q2s + q3s;
  369. if (l2 != 1. && l2 != 0.) {
  370. sharpn = 1. / l2;
  371. q01 *= sharpn;
  372. q02 *= sharpn;
  373. q03 *= sharpn;
  374. q12 *= sharpn;
  375. q13 *= sharpn;
  376. q23 *= sharpn;
  377. q1s *= sharpn;
  378. q2s *= sharpn;
  379. q3s *= sharpn;
  380. }
  381. r__[0] = 1. - (q2s + q3s) * 2.;
  382. r__[1] = (q12 + q03) * 2.;
  383. r__[2] = (q13 - q02) * 2.;
  384. r__[3] = (q12 - q03) * 2.;
  385. r__[4] = 1. - (q1s + q3s) * 2.;
  386. r__[5] = (q23 + q01) * 2.;
  387. r__[6] = (q13 + q02) * 2.;
  388. r__[7] = (q23 - q01) * 2.;
  389. r__[8] = 1. - (q1s + q2s) * 2.;
  390. return 0;
  391. } /* q2m_ */