PageRenderTime 32ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/brlcad/tags/rel-7-10-2/src/libbn/anim.c

https://bitbucket.org/vrrm/brl-cad-copy-for-fast-history-browsing-in-git
C | 1023 lines | 641 code | 108 blank | 274 comment | 70 complexity | 8a631062f8fa09c41b64ec058622ecc9 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. /* A N I M . C
  2. * BRL-CAD
  3. *
  4. * Copyright (c) 1993-2007 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 anim */
  21. /** @{ */
  22. /** @file anim.c
  23. * @brief
  24. * Routines useful in animation programs.
  25. *
  26. * @author
  27. * Carl J. Nuzman
  28. *
  29. * @par Source -
  30. * The U. S. Army Research Laboratory
  31. *@n Aberdeen Proving Ground, Maryland 21005-5068 USA
  32. *
  33. *
  34. *
  35. *
  36. ***********************************************************************
  37. *
  38. * @par This file includes the following routines:
  39. * @li anim_v_permute() apply camera animation permutation
  40. * @li anim_v_unpermute() undo camera animation permutation
  41. * @li anim_tran() transpose matrix in place
  42. * @li anim_mat2zyx() extract angles from rotation matrix
  43. * @li anim_mat2ypr() extract yaw,pitch,roll from rotation matrix
  44. * @li anim_mat2quat() extract quaternion from rotation matrix
  45. * @li anim_ypr2mat() create rotation matrix from ypr, etc.
  46. * @li anim_ypr2vmat()
  47. * @li anim_y_p_r2mat()
  48. * @li anim_dy_p_r2mat()
  49. * @li anim_dy_p_r2vmat()
  50. * @li anim_x_y_z2mat()
  51. * @li anim_dx_y_z2mat()
  52. * @li anim_z_y_x2mat()
  53. * @li anim_dz_y_x2mat()
  54. * @li anim_quat2mat()
  55. * @li anim_dir2mat() create rotation matrix from direction
  56. * @li anim_dirn2mat() create rot matrix from dir and normal
  57. * @li anim_steer_mat() automatic steering
  58. * @li anim_add_trans() add pre- and post- translation to matrix
  59. * @li anim_rotatez() rotate vector about z-axis
  60. * @li anim_mat_print() print matrix with optional semi-colon
  61. * @li anim_view_rev() reverse view matrix
  62. */
  63. #include "common.h"
  64. #include <stdio.h>
  65. #include <math.h>
  66. #include "machine.h"
  67. #include "bu.h"
  68. #include "vmath.h"
  69. #include "bn.h"
  70. #include "anim.h"
  71. #ifndef M_PI
  72. #define M_PI 3.14159265358979323846
  73. #endif
  74. #define NORMAL 0
  75. #define ERROR1 1
  76. #define ERROR2 2
  77. /**
  78. * Orientation conventions:
  79. * The default object orientation is facing the positive x-axis, with
  80. * the positive y-axis to the object's left and the positive z-axis above
  81. * the object.
  82. * The default view orientation for rt and mged is facing the negative z-axis,
  83. * with the negative x-axis leading to the left and the positive y-axis
  84. * going upwards.
  85. */
  86. /**
  87. * ANIM_V_PERMUTE
  88. * @brief Pre-multiply a rotation matrix by a matrix
  89. * which maps the z-axis to the negative x-axis, the y-axis to the
  90. * z-axis and the x-axis to the negative y-axis.
  91. *
  92. * This has the effect of twisting an object in the default view orientation
  93. * into the default object orientation before applying the matrix.
  94. * Given a matrix designed to operate on an object, yield a matrix which
  95. * operates on the view.
  96. */
  97. void anim_v_permute(mat_t m)
  98. {
  99. int i;
  100. fastf_t store;
  101. for (i=0; i<9; i+=4){
  102. store = m[i];
  103. m[i] = -m[i+1];
  104. m[i+1] = m[i+2];
  105. m[i+2] = -store;
  106. }
  107. }
  108. /**
  109. * ANIM_V_UNPERMUTE
  110. * @brief Undo the mapping done by anim_v_permute().
  111. *
  112. * This has the effect of twisting an object in the default object
  113. * orientation into the default view orientation before applying the
  114. * matrix.
  115. * Given a matrix designed to operate on the view, yield a matrix which
  116. * operates on an object.
  117. */
  118. void anim_v_unpermute(mat_t m)
  119. {
  120. int i;
  121. fastf_t store;
  122. for (i=0; i<9; i+=4){
  123. store = m[i+2];
  124. m[i+2] = m[i+1];
  125. m[i+1] = -m[i];
  126. m[i] = -store;
  127. }
  128. }
  129. /** @brief Transpose matrix in place */
  130. void anim_tran(mat_t m)
  131. {
  132. int i;
  133. fastf_t store;
  134. #if 1
  135. /* The sun4's complain about no automatic aggregate initialization,
  136. * so we'll do it another way. :-(
  137. */
  138. int src[6];
  139. int dst[6];
  140. src[0] = 1;
  141. src[1] = 2;
  142. src[2] = 3;
  143. src[3] = 6;
  144. src[4] = 7;
  145. src[5] = 11;
  146. dst[0] = 4;
  147. dst[1] = 8;
  148. dst[2] = 12;
  149. dst[3] = 9;
  150. dst[4] = 13;
  151. dst[5] = 14;
  152. #else
  153. int src[] = { 1, 2, 3, 6, 7, 11 };
  154. int dst[] = { 4, 8, 12, 9, 13, 14};
  155. #endif
  156. for (i=0; i<6; i++) {
  157. store = m[dst[i]];
  158. m[dst[i]] = m[src[i]];
  159. m[src[i]] = store;
  160. }
  161. }
  162. /***************************************
  163. *ANIM_MAT2* - Conversions from matrices
  164. ***************************************/
  165. /** ANIM_MAT2ZYX
  166. * @brief
  167. * Convert the rotational part of a 4x4 transformation matrix
  168. * to zyx form, that is to say, rotations carried out in the order z, y,
  169. * and then x. The angles are stored in radians as a vector in the order
  170. * x,y,z. A return value of ERROR1 means that arbitrary assumptions were
  171. * necessary. ERROR2 means that the conversion failed.
  172. */
  173. int anim_mat2zyx(const mat_t viewrot, vect_t angle)
  174. {
  175. int i, return_value, id_x, id_z;
  176. fastf_t sin_x, sin_z, cos_x, cos_z, big_x, big_z;
  177. static fastf_t previous[3];
  178. if ((viewrot[1]==0.0) && (viewrot[0]==0.0)){
  179. return_value = ERROR1;
  180. angle[0] = 0.0;
  181. angle[2] = atan2(viewrot[4],viewrot[5]);
  182. /*bu_log("Warning: x arbitrarily set to 0.0; z set to %f.\n",angle[2]);*/
  183. }
  184. else {
  185. return_value = NORMAL;
  186. angle[2] = atan2(-viewrot[1],viewrot[0]);
  187. angle[0] = atan2(-viewrot[6],viewrot[10]);
  188. }
  189. sin_x = sin(angle[0]);
  190. sin_z = sin(angle[2]);
  191. cos_x = cos(angle[0]);
  192. cos_z = cos(angle[2]);
  193. /* in principle, we can use the sin_x or cos_x with sin_z or cos_z to
  194. * figure out angle[1], as long as they are non-zero. To avoid
  195. * ill-conditioning effects, we choose the two that are greatest in
  196. * absolute value
  197. */
  198. id_z = (fabs(sin_z) > fabs(cos_z)) ? 1 : 0;
  199. big_z = id_z ? sin_z : cos_z;
  200. id_x = (fabs(sin_x) > fabs(cos_x)) ? 1 : 0;
  201. big_x = id_x ? sin_x : cos_x;
  202. if (fabs(big_x*big_z) < VDIVIDE_TOL){ /* this should be impossible*/
  203. /* unable to calculate pitch*/
  204. return(ERROR2);
  205. }
  206. else if ( id_x && (!id_z) )
  207. angle[1]=atan2( (viewrot[4] - cos_x*sin_z)/(sin_x*cos_z), -viewrot[6]/sin_x);
  208. else if ( (!id_x) && (!id_z) )
  209. angle[1]=atan2( (-viewrot[8] + sin_x*sin_z)/(cos_x*cos_z), viewrot[0]/cos_z);
  210. else if ( id_x && id_z )
  211. angle[1]=atan2( (-viewrot[5] + cos_x*cos_z)/(sin_x*sin_z), -viewrot[1]/sin_z);
  212. else if ( (!id_x) && id_z )
  213. angle[1]=atan2( (viewrot[9] - sin_x*cos_z)/(cos_x*sin_z), viewrot[10]/cos_x);
  214. /* assume the smallest possible arc-length from frame to frame */
  215. for (i=0; i<3; i++) {
  216. while ((angle[i] - previous[i]) > M_PI)
  217. angle[i] -= (2.0*M_PI);
  218. while ((previous[i] - angle[i]) > M_PI)
  219. angle[i] += (2.0*M_PI);
  220. previous[i] = angle[i];
  221. }
  222. return(return_value);
  223. }
  224. /** ANIM_MAT2YPR
  225. *@brief
  226. * Convert the rotational part of a 4x4 transformation matrix
  227. * to yaw-pitch-roll form, that is to say, +roll degrees about the x-axis,
  228. * -pitch degrees about the y-axis, and +yaw degrees about the
  229. * z-axis. The angles are stored in radians as a vector in the order y,p,r.
  230. * A return of ERROR1 means that arbitrary assumptions were necessary.
  231. * ERROR2 means that the conversion failed.
  232. */
  233. int anim_mat2ypr(mat_t viewrot, vect_t angle)
  234. {
  235. int i, return_value, id_y, id_r;
  236. fastf_t sin_y, sin_r, cos_y, cos_r, big_y, big_r;
  237. static fastf_t prev_angle[3];
  238. if ((viewrot[9]==0.0) && (viewrot[10]==0.0)){
  239. return_value = ERROR1;
  240. angle[2] = 0.0;
  241. angle[0] = atan2(-viewrot[1],viewrot[5]);
  242. /*bu_log("Warning: roll arbitrarily set to 0.0; yaw set to %f radians.\n",angle[0]);*/
  243. }
  244. else {
  245. return_value = NORMAL;
  246. angle[0] = atan2(viewrot[4],viewrot[0]);
  247. angle[2] = atan2(viewrot[9],viewrot[10]);
  248. }
  249. sin_y = sin(angle[0]);
  250. sin_r = sin(angle[2]);
  251. cos_y = cos(angle[0]);
  252. cos_r = cos(angle[2]);
  253. /* in principle, we can use sin_y or cos_y with sin_r or cos_r to
  254. * figure out angle[1], as long as they are non-zero. To avoid
  255. * ill-conditioning effects, we choose the two that are greatest in
  256. * absolute value
  257. */
  258. id_y = (fabs(sin_y) > fabs(cos_y)) ? 1 : 0;
  259. big_y = id_y ? sin_y : cos_y;
  260. id_r = (fabs(sin_r) > fabs(cos_r)) ? 1 : 0;
  261. big_r = id_r ? sin_r : cos_r;
  262. if (fabs(big_y*big_r) < VDIVIDE_TOL){ /* this should not happen */
  263. /* unable to calculate pitch*/
  264. return(ERROR2);
  265. }
  266. else if ( (!id_y) && id_r )
  267. angle[1] = atan2( -(viewrot[1]+sin_y*cos_r)/(cos_y*sin_r),viewrot[9]/sin_r);
  268. else if ( id_y && (!id_r) )
  269. angle[1] = atan2( -(viewrot[6]+cos_y*sin_r)/(sin_y*cos_r),viewrot[10]/cos_r);
  270. else if ( id_y && id_r )
  271. angle[1] = atan2( -(viewrot[5]-cos_y*cos_r)/(sin_y*sin_r),viewrot[4]/sin_y);
  272. else if ( (!id_y) && (!id_r) )
  273. angle[1] = atan2( -(viewrot[2]-sin_y*sin_r)/(cos_y*cos_r),viewrot[0]/cos_y);
  274. /* assume the smallest possible arc-length from frame to frame */
  275. for (i=0; i<3; i++) {
  276. while ((angle[i] - prev_angle[i]) > M_PI)
  277. angle[i] -= (2.0*M_PI);
  278. while ((prev_angle[i] - angle[i]) > M_PI)
  279. angle[i] += (2.0*M_PI);
  280. prev_angle[i] = angle[i];
  281. }
  282. return(return_value);
  283. }
  284. /** ANIM_MAT2QUAT
  285. * @brief
  286. * This interprets the rotational part of a 4x4 transformation
  287. * matrix in terms of unit quaternions. The result is stored as a vector in
  288. * the order x,y,z,w.
  289. * The algorithm is from Ken Shoemake, Animating Rotation with Quaternion
  290. * Curves, 1985 SIGGraph Conference Proceeding, p.245.
  291. */
  292. int anim_mat2quat(quat_t quat, const mat_t viewrot)
  293. {
  294. int i;
  295. fastf_t qdiff[4], square, mag1, mag2;
  296. static fastf_t prev_quat[4];
  297. square = 0.25 * (1 + viewrot[0] + viewrot[5] + viewrot[10]);
  298. if ( square != 0.0 ) {
  299. quat[W] = sqrt(square);
  300. quat[X] = 0.25 * (viewrot[9] - viewrot[6])/ quat[W];
  301. quat[Y] = 0.25 * (viewrot[2] - viewrot[8])/ quat[W];
  302. quat[Z] = 0.25 * (viewrot[4] - viewrot[1])/ quat[W];
  303. }
  304. else {
  305. quat[W] = 0.0;
  306. square = -0.5 * (viewrot[5] + viewrot[10]);
  307. if (square != 0.0 ) {
  308. quat[X] = sqrt(square);
  309. quat[Y] = 0.5 * viewrot[4] / quat[X];
  310. quat[Z] = 0.5 * viewrot[8] / quat[X];
  311. }
  312. else {
  313. quat[X] = 0.0;
  314. square = 0.5 * (1 - viewrot[10]);
  315. if (square != 0.0){
  316. quat[Y] = sqrt(square);
  317. quat[Z] = 0.5 * viewrot[9]/ quat[Y];
  318. }
  319. else {
  320. quat[Y] = 0.0;
  321. quat[Z] = 1.0;
  322. }
  323. }
  324. }
  325. /* quaternions on opposite sides of a four-dimensional sphere
  326. are equivalent. Take the quaternion closest to the previous
  327. one */
  328. for (i=0; i<4; i++)
  329. qdiff[i] = prev_quat[i] - quat[i];
  330. mag1 = QMAGSQ(qdiff);
  331. for (i=0; i<4; i++)
  332. qdiff[i] = prev_quat[i] + quat[i];
  333. mag2 = QMAGSQ(qdiff);
  334. for (i=0; i<4; i++) {
  335. if (mag1 > mag2) /* inverse of quat would be closer */
  336. quat[i] = -quat[i];
  337. prev_quat[i] = quat[i];
  338. }
  339. return(1);
  340. }
  341. /***************************************
  342. *ANIM_*2MAT - Conversions to matrices
  343. ***************************************/
  344. /** ANIM_YPR2MAT
  345. * @brief Create a premultiplication rotation matrix to turn the front
  346. * of an object (its x-axis) to the given yaw, pitch, and roll,
  347. * which is stored in radians in the vector a.
  348. */
  349. void anim_ypr2mat(mat_t m, const vect_t a)
  350. {
  351. fastf_t cos_y,cos_p,cos_r,sin_y,sin_p,sin_r;
  352. cos_y = cos(a[0]);
  353. cos_p = cos(a[1]);
  354. cos_r = cos(a[2]);
  355. sin_y = sin(a[0]);
  356. sin_p = sin(a[1]);
  357. sin_r = sin(a[2]);
  358. m[0] = cos_y*cos_p;
  359. m[1] = -cos_y*sin_p*sin_r-sin_y*cos_r;
  360. m[2] = -cos_y*sin_p*cos_r+sin_y*sin_r;
  361. m[3] = 0;
  362. m[4] = sin_y*cos_p;
  363. m[5] = -sin_y*sin_p*sin_r+cos_y*cos_r;
  364. m[6] = -sin_y*sin_p*cos_r-cos_y*sin_r;
  365. m[7] = 0;
  366. m[8]= sin_p;
  367. m[9] = cos_p*sin_r;
  368. m[10] = cos_p*cos_r;
  369. m[11] = 0.0;
  370. m[12] = 0.0;
  371. m[13] = 0.0;
  372. m[14] = 0.0;
  373. m[15] = 1.0;
  374. }
  375. /** ANIM_YPR2VMAT
  376. * @brief Create a post-multiplication rotation matrix ,which could
  377. * be used to move the virtual camera to the given yaw, pitch,
  378. * and roll, which are stored in radians in the given vector a. The
  379. * following are equivalent sets of commands:
  380. * ypr2vmat(matrix,a);
  381. * or
  382. * ypr2mat(matrix,a);
  383. * v_permute(matrix);
  384. * transpose(matrix;
  385. */
  386. void anim_ypr2vmat(mat_t m, const vect_t a)
  387. {
  388. fastf_t cos_y,cos_p,cos_r,sin_y,sin_p,sin_r;
  389. cos_y = cos(a[0]);
  390. cos_p = cos(a[1]);
  391. cos_r = cos(a[2]);
  392. sin_y = sin(a[0]);
  393. sin_p = sin(a[1]);
  394. sin_r = sin(a[2]);
  395. m[0] = -cos_y*sin_p*sin_r-sin_y*cos_r;
  396. m[1] = -sin_y*sin_p*sin_r+cos_y*cos_r;
  397. m[2] = cos_p*sin_r;
  398. m[3] = 0;
  399. m[4] = -cos_y*sin_p*cos_r+sin_y*sin_r;
  400. m[5] = -sin_y*sin_p*cos_r-cos_y*sin_r;
  401. m[6] = cos_p*cos_r;
  402. m[7] = 0;
  403. m[8] = cos_y*cos_p;
  404. m[9] = sin_y*cos_p;
  405. m[10] = sin_p;
  406. m[11] = 0.0;
  407. m[12] = 0.0;
  408. m[13] = 0.0;
  409. m[14] = 0.0;
  410. m[15] = 1.0;
  411. }
  412. /** ANIM_Y_P_R2MAT
  413. * @brief
  414. * Make matrix to rotate an object to the given yaw,
  415. * pitch, and roll. (Specified in radians.)
  416. */
  417. void anim_y_p_r2mat(mat_t m, double y, double p, double r)
  418. {
  419. fastf_t cos_y = cos(y);
  420. fastf_t sin_y = sin(y);
  421. fastf_t cos_p = cos(p);
  422. fastf_t sin_p = sin(p);
  423. fastf_t cos_r = cos(r);
  424. fastf_t sin_r = sin(r);
  425. m[0] = cos_y*cos_p;
  426. m[1] = -cos_y*sin_p*sin_r-sin_y*cos_r;
  427. m[2] = -cos_y*sin_p*cos_r+sin_y*sin_r;
  428. m[4] = sin_y*cos_p;
  429. m[5] = -sin_y*sin_p*sin_r+cos_y*cos_r;
  430. m[6] = -sin_y*sin_p*cos_r-cos_y*sin_r;
  431. m[8]= sin_p;
  432. m[9] = cos_p*sin_r;
  433. m[10] = cos_p*cos_r;
  434. m[3]=m[7]=m[11]=m[12]=m[13]=m[14]=0;
  435. m[15]=1;
  436. }
  437. /** ANIM_DY_P_R2MAT
  438. * @brief Make matrix to rotate an object to the given yaw,
  439. * pitch, and roll. (Specified in degrees.)
  440. */
  441. void anim_dy_p_r2mat(mat_t m, double y, double p, double r)
  442. {
  443. fastf_t radian_yaw = y*(M_PI*0.0055555555556);
  444. fastf_t radian_pitch = p*(M_PI*0.0055555555556);
  445. fastf_t radian_roll = r*(M_PI*0.0055555555556);
  446. fastf_t cos_y = cos(radian_yaw);
  447. fastf_t sin_y = sin(radian_yaw);
  448. fastf_t cos_p = cos(radian_pitch);
  449. fastf_t sin_p = sin(radian_pitch);
  450. fastf_t cos_r = cos(radian_roll);
  451. fastf_t sin_r = sin(radian_roll);
  452. m[0] = cos_y*cos_p;
  453. m[1] = -cos_y*sin_p*sin_r-sin_y*cos_r;
  454. m[2] = -cos_y*sin_p*cos_r+sin_y*sin_r;
  455. m[4] = sin_y*cos_p;
  456. m[5] = -sin_y*sin_p*sin_r+cos_y*cos_r;
  457. m[6] = -sin_y*sin_p*cos_r-cos_y*sin_r;
  458. m[8]= sin_p;
  459. m[9] = cos_p*sin_r;
  460. m[10] = cos_p*cos_r;
  461. m[3]=m[7]=m[11]=m[12]=m[13]=m[14]=0;
  462. m[15]=1;
  463. }
  464. /** ANIM_DY_P_R2VMAT
  465. * @brief Make a view rotation matrix, given desired yaw, pitch
  466. * and roll. (Note that the matrix is a permutation of the object rotation
  467. * matrix).
  468. */
  469. void anim_dy_p_r2vmat(mat_t m, double yaw, double pch, double rll)
  470. {
  471. float ryaw = yaw*(M_PI*0.0055555555556);
  472. float rpch = pch*(M_PI*0.0055555555556);
  473. float rrll = rll*(M_PI*0.0055555555556);
  474. float cos_y = cos(ryaw);
  475. float sin_y = sin(ryaw);
  476. float cos_p = cos(rpch);
  477. float sin_p = sin(rpch);
  478. float cos_r = cos(rrll);
  479. float sin_r = sin(rrll);
  480. m[0] = -cos_y*sin_p*sin_r-sin_y*cos_r;
  481. m[1] = -sin_y*sin_p*sin_r+cos_y*cos_r;
  482. m[2] = cos_p*sin_r;
  483. m[4] = -cos_y*sin_p*cos_r+sin_y*sin_r;
  484. m[5] = -sin_y*sin_p*cos_r-cos_y*sin_r;
  485. m[6] = cos_p*cos_r;
  486. m[8] = cos_y*cos_p;
  487. m[9] = sin_y*cos_p;
  488. m[10]= sin_p;
  489. m[3]=m[7]=m[11]=0;
  490. m[12]=m[13]=m[14]=0;
  491. m[15]=1;
  492. }
  493. /** ANIM_X_Y_Z2MAT
  494. * @brief Make a rotation matrix corresponding to a rotation of
  495. * "x" radians about the x-axis, "y" radians about the y-axis, and
  496. * then "z" radians about the z-axis.
  497. */
  498. void anim_x_y_z2mat(mat_t m, double x, double y, double z)
  499. {
  500. fastf_t cosx = cos(x);
  501. fastf_t sinx = sin(x);
  502. fastf_t cosy = cos(y);
  503. fastf_t siny = sin(y);
  504. fastf_t cosz = cos(z);
  505. fastf_t sinz = sin(z);
  506. m[0] = cosz*cosy;
  507. m[1] = cosz*siny*sinx-sinz*cosx;
  508. m[2] = cosz*siny*cosx+sinz*sinx;
  509. m[4] = sinz*cosy;
  510. m[5] = sinz*siny*sinx+cosz*cosx;
  511. m[6] = sinz*siny*cosx-cosz*sinx;
  512. m[8] = -siny;
  513. m[9] = cosy*sinx;
  514. m[10] = cosy*cosx;
  515. m[3]=m[7]=m[11]=m[12]=m[13]=m[14]=0;
  516. m[15]=1;
  517. }
  518. /** ANIM_DX_Y_Z2MAT
  519. * @brief Make a rotation matrix corresponding to a rotation of
  520. * "x" degrees about the x-axis, "y" degrees about the y-axis, and
  521. * then "z" degrees about the z-axis.
  522. */
  523. void anim_dx_y_z2mat(mat_t m, double x, double y, double z)
  524. {
  525. fastf_t cosx,cosy,cosz,sinx,siny,sinz;
  526. x *= (M_PI*0.0055555555556);
  527. y *= (M_PI*0.0055555555556);
  528. z *= (M_PI*0.0055555555556);
  529. cosx = cos(x);
  530. sinx = sin(x);
  531. cosy = cos(y);
  532. siny = sin(y);
  533. cosz = cos(z);
  534. sinz = sin(z);
  535. m[0] = cosz*cosy;
  536. m[1] = cosz*siny*sinx-sinz*cosx;
  537. m[2] = cosz*siny*cosx+sinz*sinx;
  538. m[4] = sinz*cosy;
  539. m[5] = sinz*siny*sinx+cosz*cosx;
  540. m[6] = sinz*siny*cosx-cosz*sinx;
  541. m[8] = -siny;
  542. m[9] = cosy*sinx;
  543. m[10] = cosy*cosx;
  544. m[3]=m[7]=m[11]=m[12]=m[13]=m[14]=0.0;
  545. m[15]=1.0;
  546. }
  547. /* ANIM_ZYX2MAT @brief Make a rotation matrix corresponding to a rotation of
  548. * "z" radians about the z-axis, "y" radians about the y-axis, and
  549. * then "x" radians about the x-axis.
  550. */
  551. void anim_zyx2mat(mat_t m, const vect_t a)
  552. {
  553. fastf_t cosX,cosY,cosZ,sinX,sinY,sinZ;
  554. cosX = cos(a[0]);
  555. cosY = cos(a[1]);
  556. cosZ = cos(a[2]);
  557. sinX = sin(a[0]);
  558. sinY = sin(a[1]);
  559. sinZ = sin(a[2]);
  560. m[0] = cosY*cosZ;
  561. m[1] = -cosY*sinZ;
  562. m[2] = sinY;
  563. m[3] = 0;
  564. m[4] = cosX*sinZ + sinX*sinY*cosZ;
  565. m[5] = cosX*cosZ - sinX*sinY*sinZ;
  566. m[6] = -sinX*cosY;
  567. m[7] = 0;
  568. m[8] = sinX*sinZ - cosX*sinY*cosZ;
  569. m[9] = sinX*cosZ + cosX*sinY*sinZ;
  570. m[10] = cosX*cosY;
  571. m[11] = 0.0;
  572. m[12] = 0.0;
  573. m[13] = 0.0;
  574. m[14] = 0.0;
  575. m[15] = 1.0;
  576. }
  577. /** ANIM_Z_Y_X2MAT @brief Make a rotation matrix corresponding to a rotation of
  578. * "z" radians about the z-axis, "y" radians about the y-axis, and
  579. * then "x" radians about the x-axis.
  580. */
  581. void anim_z_y_x2mat(mat_t m, double x, double y, double z)
  582. {
  583. fastf_t cosx = cos(x);
  584. fastf_t sinx = sin(x);
  585. fastf_t cosy = cos(y);
  586. fastf_t siny = sin(y);
  587. fastf_t cosz = cos(z);
  588. fastf_t sinz = sin(z);
  589. m[0] = cosy*cosz;
  590. m[1] = -cosy*sinz;
  591. m[2] = siny;
  592. m[4] = cosx*sinz + sinx*siny*cosz;
  593. m[5] = cosx*cosz - sinx*siny*sinz;
  594. m[6] = -sinx*cosy;
  595. m[8] = sinx*sinz - cosx*siny*cosz;
  596. m[9] = sinx*cosz + cosx*siny*sinz;
  597. m[10]= cosx*cosy;
  598. m[3]=m[7]=m[11]=m[12]=m[13]=m[14]=0.0;
  599. m[15]=1.0;
  600. }
  601. /** ANIM_DZ_Y_X2MAT
  602. * @brief
  603. * Make a rotation matrix corresponding to a rotation of
  604. * "z" degrees about the z-axis, "y" degrees about the y-axis, and
  605. * then "x" degrees about the x-axis.
  606. */
  607. void anim_dz_y_x2mat(mat_t m, double x, double y, double z)
  608. {
  609. fastf_t cosx,cosy,cosz,sinx,siny,sinz;
  610. x *= (M_PI*0.0055555555556);
  611. y *= (M_PI*0.0055555555556);
  612. z *= (M_PI*0.0055555555556);
  613. cosx = cos(x);
  614. sinx = sin(x);
  615. cosy = cos(y);
  616. siny = sin(y);
  617. cosz = cos(z);
  618. sinz = sin(z);
  619. m[0] = cosy*cosz;
  620. m[1] = -cosy*sinz;
  621. m[2] = siny;
  622. m[4] = cosx*sinz + sinx*siny*cosz;
  623. m[5] = cosx*cosz - sinx*siny*sinz;
  624. m[6] = -sinx*cosy;
  625. m[8] = sinx*sinz - cosx*siny*cosz;
  626. m[9] = sinx*cosz + cosx*siny*sinz;
  627. m[10]= cosx*cosy;
  628. m[3]=m[7]=m[11]=m[12]=m[13]=m[14]=0;
  629. m[15]=1;
  630. }
  631. /* ANIM_QUAT2MAT
  632. * @brief
  633. * Make 4x4 matrix from the given quaternion
  634. * Note: these quaternions are the conjugates of the quaternions
  635. * used in the librt/qmath.c quat_quat2mat()
  636. */
  637. void anim_quat2mat(mat_t m, const quat_t qq)
  638. {
  639. fastf_t two_q[4];
  640. quat_t q;
  641. QMOVE(q, qq);
  642. QUNITIZE(q);
  643. VADD2N(two_q,q,q,4);
  644. m[0] = 1.0 - two_q[Y]*q[Y] - two_q[Z]*q[Z];
  645. m[1] = two_q[X]*q[Y] - two_q[W]*q[Z];
  646. m[2] = two_q[X]*q[Z] + two_q[W]*q[Y];
  647. m[3] = 0.0;
  648. m[4] = two_q[X]*q[Y] + two_q[W]*q[Z];
  649. m[5] = 1.0 - two_q[X]*q[X] - two_q[Z]*q[Z];
  650. m[6] = two_q[Y]*q[Z] - two_q[W]*q[X];
  651. m[7] = 0.0;
  652. m[8] = two_q[X]*q[Z] - two_q[W]*q[Y];
  653. m[9] = two_q[Y]*q[Z] + two_q[W]*q[X];
  654. m[10] = 1.0 - two_q[X]*q[X] - two_q[Y]*q[Y];
  655. m[11] = 0.0;
  656. m[12] = 0.0;
  657. m[13] = 0.0;
  658. m[14] = 0.0;
  659. m[15] = 1.0;
  660. }
  661. /* ANIM_DIR2MAT
  662. * @brief
  663. * make a matrix which turns a vehicle from the x-axis to
  664. * point in the desired direction, staying "right-side up" (ie the y-axis
  665. * never has a z-component). A second direction vector is consulted when
  666. * the given direction is vertical. This is intended to represent the
  667. * the direction from a previous frame.
  668. */
  669. void anim_dir2mat(mat_t m, const vect_t d, const vect_t d2b)
  670. {
  671. fastf_t hypotenuse, sign;
  672. vect_t d2;
  673. VMOVE( d2, d2b );
  674. sign = 1.0;
  675. hypotenuse = sqrt(d[0]*d[0]+d[1]*d[1]);
  676. if (hypotenuse < VDIVIDE_TOL){ /* vertical direction - use d2 to
  677. * determine roll */
  678. hypotenuse = sqrt(d2[0]*d2[0]+d2[1]*d2[1]);
  679. if (hypotenuse < VDIVIDE_TOL){ /* use x-axis as default*/
  680. VSET(d2,1,0,0);
  681. hypotenuse = 1;
  682. }
  683. if (d[2] < 0)
  684. sign = -1.0;
  685. m[1] = -d2[1]/hypotenuse;
  686. m[5] = d2[0]/hypotenuse;
  687. m[2] = -sign * d2[0]/hypotenuse;
  688. m[6] = -sign * d2[1]/hypotenuse;
  689. m[8] = sign;
  690. m[0]=m[4]=m[9]=m[10]=0.0;
  691. }
  692. else { /* normal - no roll*/
  693. m[0] = d[0];
  694. m[1] = -d[1]/hypotenuse;
  695. m[2] = -d[0]*d[2]/hypotenuse;
  696. m[4] = d[1];
  697. m[5] = d[0]/hypotenuse;
  698. m[6] = -d[1]*d[2]/hypotenuse;
  699. m[8] = d[2];
  700. m[9] = 0.0;
  701. m[10] = hypotenuse;
  702. }
  703. m[3]=m[7]=m[11]=0.0;
  704. m[12]=m[13]=m[14]=0.0;
  705. m[15]=1.0;
  706. }
  707. /* ANIM_DIRN2MAT
  708. * @brief
  709. * make a matrix which turns a vehicle from the x-axis to
  710. * point in the desired direction, staying "right-side up". In cases where
  711. * the direction is vertical, the second vector is consulted. The second
  712. * vector defines a normal to the the vertical plane into which the vehicle's
  713. * x and z axes should be put. A good choice to put here is the direction
  714. * of the vehicle's y-axis in the previous frame.
  715. */
  716. void anim_dirn2mat(mat_t m, const vect_t dx2, const vect_t dn)
  717. {
  718. vect_t temp;
  719. fastf_t hyp, sign,inv,mag;
  720. vect_t dx;
  721. VMOVE( dx, dx2 );
  722. sign = 1.0;
  723. mag = MAGNITUDE(dx);
  724. if (mag < VDIVIDE_TOL) {
  725. bu_log("anim_dirn2mat: Need non-zero vector");
  726. return;
  727. }
  728. inv = 1.0/mag;
  729. dx[0] *= inv;
  730. dx[1] *= inv;
  731. dx[2] *= inv;
  732. hyp = sqrt(dx[0]*dx[0]+dx[1]*dx[1]);
  733. if (hyp < VDIVIDE_TOL) { /* vertical - special handling */
  734. sign = (dx[2] < 0) ? -1.0 : 1.0;
  735. VSET(temp, dn[0], dn[1], 0.0);
  736. mag = MAGNITUDE(temp);
  737. if (mag < VDIVIDE_TOL) {
  738. /* use default */
  739. VSET(temp, 0.0, 1.0, 0.0);
  740. mag = 1.0;
  741. } else {
  742. inv = 1.0/mag;
  743. temp[0] *= inv;
  744. temp[1] *= inv;
  745. }
  746. m[0] = 0.0;
  747. m[4] = 0.0;
  748. m[8] = sign;
  749. m[1] = temp[0];
  750. m[5] = temp[1];
  751. m[9] = 0.0;
  752. m[2] = -sign*temp[1];
  753. m[6] = sign*temp[0];
  754. m[10] = 0.0;
  755. m[3]=m[7]=m[11]=0.0;
  756. m[12]=m[13]=m[14]=0.0;
  757. m[15]=1.0;
  758. return;
  759. }
  760. /*else normal*/
  761. m[0] = dx[0];
  762. m[1] = -dx[1]/hyp;
  763. m[2] = -dx[0]*dx[2]/hyp;
  764. m[4] = dx[1];
  765. m[5] = dx[0]/hyp;
  766. m[6] = -dx[1]*dx[2]/hyp;
  767. m[8] = dx[2];
  768. m[9] = 0.0;
  769. m[10] = hyp;
  770. m[3]=m[7]=m[11]=0.0;
  771. m[12]=m[13]=m[14]=0.0;
  772. m[15]=1.0;
  773. }
  774. #define ASM_EMPTY 0
  775. #define ASM_FIRST 1
  776. #define ASM_FULL 2
  777. /*ANIM_STEER_MAT
  778. * @brief
  779. * given the next frame's position, remember the value of
  780. the previous frame's position and calculate a matrix which points the x-axis
  781. in the direction defined by those two positions. Return new matrix, and the
  782. remembered value of the current position, as arguments; return 1 as the
  783. normal value, and 0 when there is not yet information to remember.
  784. */
  785. int anim_steer_mat(mat_t mat, vect_t point, int end)
  786. {
  787. static vect_t p1, p2, p3;
  788. vect_t dir;
  789. static vect_t norm;
  790. static int state = ASM_EMPTY;
  791. VMOVE(p1,p2);
  792. VMOVE(p2,p3);
  793. VMOVE(p3,point);
  794. switch(state) {
  795. case ASM_EMPTY:
  796. if (end) {
  797. state = ASM_EMPTY;
  798. } else {
  799. state = ASM_FIRST;
  800. /* "don't print yet */
  801. }
  802. return 0;
  803. case ASM_FIRST:
  804. if (end) {
  805. /* only one point specified, use default direction*/
  806. VSET(dir,1.0,0.0,0.0);
  807. VSET(norm,0.0,1.0,0.0);
  808. state = ASM_EMPTY;
  809. } else {
  810. VSUBUNIT(dir,p3,p2);
  811. VSET(norm, 0.0, 1.0, 0.0);
  812. state = ASM_FULL;
  813. }
  814. break;
  815. case ASM_FULL:
  816. if (end) {
  817. VSUBUNIT(dir,p2,p1);
  818. state = ASM_EMPTY;
  819. } else {
  820. VSUBUNIT(dir,p3,p1);
  821. state = ASM_FULL;
  822. }
  823. }
  824. /* go for it */
  825. anim_dirn2mat(mat,dir,norm); /* create basic rotation matrix */
  826. VSET(norm, mat[1], mat[5], 0.0); /* save for next time */
  827. VMOVE(point,p2); /* for main's purposes, the current point is p2 */
  828. return(1); /* return signal go ahead and print */
  829. }
  830. /***************************************
  831. * Other animation routines
  832. ***************************************/
  833. /* ANIM_ADD_TRANS
  834. * @brief
  835. * Add pre- and post- translation to a rotation matrix.
  836. * The resulting matrix has the effect of performing the first
  837. * translation, followed by the rotation, followed by the second translation.
  838. */
  839. void anim_add_trans(mat_t m, const vect_t post, const vect_t pre)
  840. {
  841. int i;
  842. for (i=0; i<3; i++)
  843. m[3+i*4] += m[i*4]*pre[0] + m[1+i*4]*pre[1]+m[2+i*4]*pre[2] + post[i];
  844. }
  845. /* ANIM_ROTATEZ
  846. * @brief
  847. * Rotate the vector "d" through "a" radians about the z-axis.
  848. */
  849. void anim_rotatez(fastf_t a, vect_t d)
  850. {
  851. fastf_t temp[3];
  852. fastf_t cos_y = cos(a);
  853. fastf_t sin_y = sin(a);
  854. temp[0] = d[0]*cos_y - d[1]*sin_y;
  855. temp[1] = d[0]*sin_y + d[1]*cos_y;
  856. d[0]=temp[0];
  857. d[1]=temp[1];
  858. }
  859. /* ANIM_MAT_PRINT
  860. * @brief
  861. * print out 4X4 matrix, with optional colon
  862. */
  863. void anim_mat_print(FILE *fp, const mat_t m, int s_colon)
  864. {
  865. bu_flog( fp,"%.10g %.10g %.10g %.10g\n", m[0], m[1], m[2], m[3]);
  866. bu_flog( fp,"%.10g %.10g %.10g %.10g\n", m[4], m[5], m[6], m[7]);
  867. bu_flog( fp,"%.10g %.10g %.10g %.10g\n", m[8], m[9], m[10], m[11]);
  868. bu_flog( fp,"%.10g %.10g %.10g %.10g", m[12], m[13], m[14], m[15]);
  869. if (s_colon)
  870. bu_flog( fp,";");
  871. bu_flog( fp,"\n");
  872. }
  873. /* ANIM_MAT_PRINTF
  874. * @brief
  875. * print out 4X4 matrix
  876. * formstr must be less than twenty chars
  877. */
  878. void anim_mat_printf(
  879. FILE *fp,
  880. const mat_t m,
  881. const char *formstr,
  882. const char *linestr,
  883. const char *endstr)
  884. {
  885. char mystr[80];
  886. sprintf(mystr,"%s%s%s%s%%s",formstr,formstr,formstr,formstr);
  887. bu_flog( fp,mystr, m[0], m[1], m[2], m[3], linestr);
  888. bu_flog( fp,mystr, m[4], m[5], m[6], m[7], linestr);
  889. bu_flog( fp,mystr, m[8], m[9], m[10], m[11], linestr);
  890. bu_flog( fp,mystr, m[12], m[13], m[14], m[15], endstr);
  891. }
  892. /* ANIM_VIEW_REV
  893. * @brief
  894. * Reverse the direction of a view matrix, keeping it
  895. * right-side up
  896. */
  897. void anim_view_rev(mat_t m)
  898. {
  899. m[0] = -m[0];
  900. m[1] = -m[1];
  901. m[4] = -m[4];
  902. m[5] = -m[5];
  903. m[8] = -m[8];
  904. m[9] = -m[9];
  905. }
  906. /** @} */
  907. /*
  908. * Local Variables:
  909. * mode: C
  910. * tab-width: 8
  911. * c-basic-offset: 4
  912. * indent-tabs-mode: t
  913. * End:
  914. * ex: shiftwidth=4 tabstop=8
  915. */