PageRenderTime 27ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/brlcad/tags/rel-6-1-DP/libbn/qmath.c

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