PageRenderTime 189ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

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

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