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

/brlcad/tags/rel-7-14-4/src/libbn/anim.c

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