PageRenderTime 27ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/brlcad/branches/STABLE/src/libbn/qmath.c

https://bitbucket.org/vrrm/brl-cad-copy-for-fast-history-browsing-in-git
C | 390 lines | 197 code | 34 blank | 159 comment | 15 complexity | 69e5351d18478987da50b857b55805dd MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, LGPL-2.1, Apache-2.0, AGPL-3.0, LGPL-3.0, GPL-3.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, 0BSD, BSD-3-Clause
  1. /* Q M A T H . C
  2. * BRL-CAD
  3. *
  4. * Copyright (c) 2004-2012 United States Government as represented by
  5. * the U.S. Army Research Laboratory.
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public License
  9. * version 2.1 as published by the Free Software Foundation.
  10. *
  11. * This library is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this file; see the file named COPYING for more
  18. * information.
  19. */
  20. /** @addtogroup mat */
  21. /** @{ */
  22. /** @file libbn/qmath.c
  23. *
  24. * @brief
  25. * Quaternion math routines.
  26. *
  27. * Unit Quaternions:
  28. * Q = [ r, a ] where r = cos(theta/2) = rotation amount
  29. * |a| = sin(theta/2) = rotation axis
  30. *
  31. * If a = 0 we have the reals; if one coord is zero we have
  32. * complex numbers (2D rotations).
  33. *
  34. * [r, a][s, b] = [rs - a.b, rb + sa + axb]
  35. *
  36. * -1
  37. * [r, a] = (r - a) / (r^2 + a.a)
  38. *
  39. * Powers of quaternions yield incremental rotations,
  40. * e.g. Q^3 is rotated three times as far as Q.
  41. *
  42. * Some operations on quaternions:
  43. * -1
  44. * [0, P'] = Q [0, P]Q Rotate a point P by quaternion Q
  45. * -1 a
  46. * slerp(Q, R, a) = Q(Q R) Spherical linear interp: 0 < a < 1
  47. *
  48. * bisect(P, Q) = (P + Q) / |P + Q| Great circle bisector
  49. *
  50. * Additions inspired by "Quaternion Calculus For Animation" by Ken Shoemake,
  51. * SIGGRAPH '89 course notes for "Math for SIGGRAPH", May 1989.
  52. *
  53. */
  54. #include "common.h"
  55. #include <stdio.h> /* DEBUG need stderr for now... */
  56. #include <math.h>
  57. #include "bu.h"
  58. #include "vmath.h"
  59. #include "bn.h"
  60. /**
  61. * Q U A T _ M A T 2 Q U A T
  62. *@brief
  63. * Convert Matrix to Quaternion.
  64. */
  65. void
  66. quat_mat2quat(register fastf_t *quat, register const fastf_t *mat)
  67. {
  68. fastf_t tr;
  69. fastf_t s;
  70. #define XX 0
  71. #define YY 5
  72. #define ZZ 10
  73. #define MMM(a, b) mat[4*(a)+(b)]
  74. tr = mat[XX] + mat[YY] + mat[ZZ];
  75. if ( tr > 0.0 ) {
  76. s = sqrt( tr + 1.0 );
  77. quat[W] = s * 0.5;
  78. s = 0.5 / s;
  79. quat[X] = ( mat[6] - mat[9] ) * s;
  80. quat[Y] = ( mat[8] - mat[2] ) * s;
  81. quat[Z] = ( mat[1] - mat[4] ) * s;
  82. return;
  83. }
  84. /* Find dominant element of primary diagonal */
  85. if ( mat[YY] > mat[XX] ) {
  86. if ( mat[ZZ] > mat[YY] ) {
  87. s = sqrt( MMM(Z, Z) - (MMM(X, X)+MMM(Y, Y)) + 1.0 );
  88. quat[Z] = s * 0.5;
  89. s = 0.5 / s;
  90. quat[W] = (MMM(X, Y) - MMM(Y, X)) * s;
  91. quat[X] = (MMM(Z, X) + MMM(X, Z)) * s;
  92. quat[Y] = (MMM(Z, Y) + MMM(Y, Z)) * s;
  93. } else {
  94. s = sqrt( MMM(Y, Y) - (MMM(Z, Z)+MMM(X, X)) + 1.0 );
  95. quat[Y] = s * 0.5;
  96. s = 0.5 / s;
  97. quat[W] = (MMM(Z, X) - MMM(X, Z)) * s;
  98. quat[Z] = (MMM(Y, Z) + MMM(Z, Y)) * s;
  99. quat[X] = (MMM(Y, X) + MMM(X, Y)) * s;
  100. }
  101. } else {
  102. if ( mat[ZZ] > mat[XX] ) {
  103. s = sqrt( MMM(Z, Z) - (MMM(X, X)+MMM(Y, Y)) + 1.0 );
  104. quat[Z] = s * 0.5;
  105. s = 0.5 / s;
  106. quat[W] = (MMM(X, Y) - MMM(Y, X)) * s;
  107. quat[X] = (MMM(Z, X) + MMM(X, Z)) * s;
  108. quat[Y] = (MMM(Z, Y) + MMM(Y, Z)) * s;
  109. } else {
  110. s = sqrt( MMM(X, X) - (MMM(Y, Y)+MMM(Z, Z)) + 1.0 );
  111. quat[X] = s * 0.5;
  112. s = 0.5 / s;
  113. quat[W] = (MMM(Y, Z) - MMM(Z, Y)) * s;
  114. quat[Y] = (MMM(X, Y) + MMM(Y, X)) * s;
  115. quat[Z] = (MMM(X, Z) + MMM(Z, X)) * s;
  116. }
  117. }
  118. #undef MMM
  119. }
  120. /**
  121. * Q U A T _ Q U A T 2 M A T
  122. *@brief
  123. * Convert Quaternion to Matrix.
  124. *
  125. * NB: This only works for UNIT quaternions. We may get imaginary results
  126. * otherwise. We should normalize first (still yields same rotation).
  127. */
  128. void
  129. quat_quat2mat(register fastf_t *mat, register const fastf_t *quat)
  130. {
  131. quat_t q;
  132. QMOVE( q, quat ); /* private copy */
  133. QUNITIZE( q );
  134. mat[0] = 1.0 - 2.0*q[Y]*q[Y] - 2.0*q[Z]*q[Z];
  135. mat[1] = 2.0*q[X]*q[Y] + 2.0*q[W]*q[Z];
  136. mat[2] = 2.0*q[X]*q[Z] - 2.0*q[W]*q[Y];
  137. mat[3] = 0.0;
  138. mat[4] = 2.0*q[X]*q[Y] - 2.0*q[W]*q[Z];
  139. mat[5] = 1.0 - 2.0*q[X]*q[X] - 2.0*q[Z]*q[Z];
  140. mat[6] = 2.0*q[Y]*q[Z] + 2.0*q[W]*q[X];
  141. mat[7] = 0.0;
  142. mat[8] = 2.0*q[X]*q[Z] + 2.0*q[W]*q[Y];
  143. mat[9] = 2.0*q[Y]*q[Z] - 2.0*q[W]*q[X];
  144. mat[10] = 1.0 - 2.0*q[X]*q[X] - 2.0*q[Y]*q[Y];
  145. mat[11] = 0.0;
  146. mat[12] = 0.0;
  147. mat[13] = 0.0;
  148. mat[14] = 0.0;
  149. mat[15] = 1.0;
  150. }
  151. /**
  152. * Q U A T _ D I S T A N C E
  153. *@brief
  154. * Gives the euclidean distance between two quaternions.
  155. */
  156. double
  157. quat_distance(const fastf_t *q1, const fastf_t *q2)
  158. {
  159. quat_t qtemp;
  160. QSUB2( qtemp, q1, q2 );
  161. return QMAGNITUDE( qtemp );
  162. }
  163. /**
  164. * Q U A T _ D O U B L E
  165. *@brief
  166. * Gives the quaternion point representing twice the rotation
  167. * from q1 to q2.
  168. * Needed for patching Bezier curves together.
  169. * A rather poor name admittedly.
  170. */
  171. void
  172. quat_double(fastf_t *qout, const fastf_t *q1, const fastf_t *q2)
  173. {
  174. quat_t qtemp;
  175. double scale;
  176. scale = 2.0 * QDOT( q1, q2 );
  177. QSCALE( qtemp, q2, scale );
  178. QSUB2( qout, qtemp, q1 );
  179. QUNITIZE( qout );
  180. }
  181. /**
  182. * Q U A T _ B I S E C T
  183. *@brief
  184. * Gives the bisector of quaternions q1 and q2.
  185. * (Could be done with quat_slerp and factor 0.5)
  186. * [I believe they must be unit quaternions this to work]
  187. */
  188. void
  189. quat_bisect(fastf_t *qout, const fastf_t *q1, const fastf_t *q2)
  190. {
  191. QADD2( qout, q1, q2 );
  192. QUNITIZE( qout );
  193. }
  194. /**
  195. * Q U A T _ S L E R P
  196. *@brief
  197. * Do Spherical Linear Interpolation between two unit quaternions
  198. * by the given factor.
  199. *
  200. * As f goes from 0 to 1, qout goes from q1 to q2.
  201. * Code based on code by Ken Shoemake
  202. */
  203. void
  204. quat_slerp(fastf_t *qout, const fastf_t *q1, const fastf_t *q2, double f)
  205. {
  206. double omega;
  207. double cos_omega;
  208. double invsin;
  209. register double s1, s2;
  210. cos_omega = QDOT( q1, q2 );
  211. if ( (1.0 + cos_omega) > 1.0e-5 ) {
  212. /* cos_omega > -0.99999 */
  213. if ( (1.0 - cos_omega) > 1.0e-5 ) {
  214. /* usual case */
  215. omega = acos(cos_omega); /* XXX atan2? */
  216. invsin = 1.0 / sin(omega);
  217. s1 = sin( (1.0-f)*omega ) * invsin;
  218. s2 = sin( f*omega ) * invsin;
  219. } else {
  220. /*
  221. * cos_omega > 0.99999
  222. * The ends are very close to each other,
  223. * use linear interpolation, to avoid divide-by-zero
  224. */
  225. s1 = 1.0 - f;
  226. s2 = f;
  227. }
  228. QBLEND2( qout, s1, q1, s2, q2 );
  229. } else {
  230. /*
  231. * cos_omega == -1, omega = M_PI.
  232. * The ends are nearly opposite, 180 degrees (M_PI) apart.
  233. */
  234. /* (I have no idea what permuting the elements accomplishes,
  235. * perhaps it creates a perpendicular? */
  236. qout[X] = -q1[Y];
  237. qout[Y] = q1[X];
  238. qout[Z] = -q1[W];
  239. s1 = sin( (0.5-f) * M_PI );
  240. s2 = sin( f * M_PI );
  241. VBLEND2( qout, s1, q1, s2, qout );
  242. qout[W] = q1[Z];
  243. }
  244. }
  245. /**
  246. * Q U A T _ S B E R P
  247. *@brief
  248. * Spherical Bezier Interpolate between four quaternions by amount f.
  249. * These are intended to be used as start and stop quaternions along
  250. * with two control quaternions chosen to match spline segments with
  251. * first order continuity.
  252. *
  253. * Uses the method of successive bisection.
  254. */
  255. void
  256. quat_sberp(fastf_t *qout, const fastf_t *q1, const fastf_t *qa, const fastf_t *qb, const fastf_t *q2, double f)
  257. {
  258. quat_t p1, p2, p3, p4, p5;
  259. /* Interp down the three segments */
  260. quat_slerp( p1, q1, qa, f );
  261. quat_slerp( p2, qa, qb, f );
  262. quat_slerp( p3, qb, q2, f );
  263. /* Interp down the resulting two */
  264. quat_slerp( p4, p1, p2, f );
  265. quat_slerp( p5, p2, p3, f );
  266. /* Interp this segment for final quaternion */
  267. quat_slerp( qout, p4, p5, f );
  268. }
  269. /**
  270. * Q U A T _ M A K E _ N E A R E S T
  271. *@brief
  272. * Set the quaternion q1 to the quaternion which yields the
  273. * smallest rotation from q2 (of the two versions of q1 which
  274. * produce the same orientation).
  275. *
  276. * Note that smallest euclidian distance implies smallest great
  277. * circle distance as well (since surface is convex).
  278. */
  279. void
  280. quat_make_nearest(fastf_t *q1, const fastf_t *q2)
  281. {
  282. quat_t qtemp;
  283. double d1, d2;
  284. QSCALE( qtemp, q1, -1.0 );
  285. d1 = quat_distance( q1, q2 );
  286. d2 = quat_distance( qtemp, q2 );
  287. /* Choose smallest distance */
  288. if ( d2 < d1 ) {
  289. QMOVE( q1, qtemp );
  290. }
  291. }
  292. /**
  293. * Q U A T _ P R I N T
  294. */
  295. /* DEBUG ROUTINE */
  296. void
  297. quat_print(const char *title, const fastf_t *quat)
  298. {
  299. int i;
  300. vect_t axis;
  301. fprintf( stderr, "QUATERNION: %s\n", title );
  302. for ( i = 0; i < 4; i++ )
  303. fprintf( stderr, "%8f ", quat[i] );
  304. fprintf( stderr, "\n" );
  305. fprintf( stderr, "rot_angle = %8f deg", RAD2DEG * 2.0 * acos( quat[W] ) );
  306. VMOVE( axis, quat );
  307. VUNITIZE( axis );
  308. fprintf( stderr, ", Axis = (%f, %f, %f)\n",
  309. axis[X], axis[Y], axis[Z] );
  310. }
  311. /**
  312. * Q U A T _ E X P
  313. *@brief
  314. * Exponentiate a quaternion, assuming that the scalar part is 0.
  315. * Code by Ken Shoemake.
  316. */
  317. void
  318. quat_exp(fastf_t *out, const fastf_t *in)
  319. {
  320. fastf_t theta;
  321. fastf_t scale;
  322. if ( (theta = MAGNITUDE( in )) > VDIVIDE_TOL )
  323. scale = sin(theta)/theta;
  324. else
  325. scale = 1.0;
  326. VSCALE( out, in, scale );
  327. out[W] = cos(theta);
  328. }
  329. /**
  330. * Q U A T _ L O G
  331. *@brief
  332. * Take the natural logarithm of a unit quaternion.
  333. * Code by Ken Shoemake.
  334. */
  335. void
  336. quat_log(fastf_t *out, const fastf_t *in)
  337. {
  338. fastf_t theta;
  339. fastf_t scale;
  340. if ( (scale = MAGNITUDE(in)) > VDIVIDE_TOL ) {
  341. theta = atan2( scale, in[W] );
  342. scale = theta/scale;
  343. }
  344. VSCALE( out, in, scale );
  345. out[W] = 0.0;
  346. }
  347. /** @} */
  348. /*
  349. * Local Variables:
  350. * mode: C
  351. * tab-width: 8
  352. * indent-tabs-mode: t
  353. * c-file-style: "stroustrup"
  354. * End:
  355. * ex: shiftwidth=4 tabstop=8
  356. */