compose_matrix_src.cxx 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726
  1. // Filename: compose_matrix_src.cxx
  2. // Created by: drose (27Jan99)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
  8. //
  9. // All use of this software is subject to the terms of the Panda 3d
  10. // Software license. You should have received a copy of this license
  11. // along with this source code; you will also find a current copy of
  12. // the license at http://www.panda3d.org/license.txt .
  13. //
  14. // To contact the maintainers of this program write to
  15. // [email protected] .
  16. //
  17. ////////////////////////////////////////////////////////////////////
  18. ////////////////////////////////////////////////////////////////////
  19. // Function: compose_matrix
  20. // Description: Computes the 3x3 matrix from scale and rotation.
  21. ////////////////////////////////////////////////////////////////////
  22. void
  23. compose_matrix(FLOATNAME(LMatrix3) &mat,
  24. const FLOATNAME(LVecBase3) &scale,
  25. const FLOATNAME(LVecBase3) &hpr,
  26. CoordinateSystem cs) {
  27. // temp_hpr_fix blocks use the correct way. need to keep other way
  28. // as default until legacy tools are fixed to work with correct way
  29. if (temp_hpr_fix) {
  30. mat.scale_multiply(scale,
  31. FLOATNAME(LMatrix3)::rotate_mat_normaxis(hpr[2], FLOATNAME(LVector3)::forward(cs), cs) *
  32. FLOATNAME(LMatrix3)::rotate_mat_normaxis(hpr[1], FLOATNAME(LVector3)::right(cs), cs) *
  33. FLOATNAME(LMatrix3)::rotate_mat_normaxis(hpr[0], FLOATNAME(LVector3)::up(cs), cs));
  34. } else {
  35. mat.scale_multiply(scale,
  36. FLOATNAME(LMatrix3)::rotate_mat_normaxis(hpr[1], FLOATNAME(LVector3)::right(cs), cs) *
  37. FLOATNAME(LMatrix3)::rotate_mat_normaxis(hpr[0], FLOATNAME(LVector3)::up(cs), cs) *
  38. FLOATNAME(LMatrix3)::rotate_mat_normaxis(hpr[2], FLOATNAME(LVector3)::back(cs), cs));
  39. }
  40. }
  41. ////////////////////////////////////////////////////////////////////
  42. // Function: unwind_yup_rotation
  43. // Description: Extracts the rotation about the x, y, and z axes from
  44. // the given hpr & scale matrix. Adjusts the matrix
  45. // to eliminate the rotation.
  46. //
  47. // This function assumes the matrix is stored in a
  48. // right-handed Y-up coordinate system.
  49. ////////////////////////////////////////////////////////////////////
  50. static void
  51. unwind_yup_rotation(FLOATNAME(LMatrix3) &mat, FLOATNAME(LVecBase3) &hpr) {
  52. typedef FLOATNAME(LMatrix3) Matrix;
  53. if (temp_hpr_fix) {
  54. // Extract the axes from the matrix.
  55. FLOATNAME(LVector3) x, y, z;
  56. mat.get_row(x,0);
  57. mat.get_row(y,1);
  58. mat.get_row(z,2);
  59. // Project Z into the XZ plane.
  60. FLOATNAME(LVector2) xz(z[0], z[2]);
  61. xz = normalize(xz);
  62. // Compute the rotation about the +Y (up) axis. This is yaw, or
  63. // "heading".
  64. FLOATTYPE heading = rad_2_deg(((FLOATTYPE)atan2(xz[0], xz[1])));
  65. // Unwind the heading, and continue.
  66. Matrix rot_y;
  67. rot_y = Matrix::rotate_mat_normaxis(-heading, FLOATNAME(LVector3)(0.0f, 1.0f, 0.0f),
  68. CS_yup_right);
  69. x = x * rot_y;
  70. y = y * rot_y;
  71. z = z * rot_y;
  72. // Project the rotated Z into the YZ plane.
  73. FLOATNAME(LVector2) yz(z[1], z[2]);
  74. yz = normalize(yz);
  75. // Compute the rotation about the +X (right) axis. This is pitch.
  76. FLOATTYPE pitch = rad_2_deg((FLOATTYPE)(-atan2(yz[0], yz[1])));
  77. // Unwind the pitch.
  78. Matrix rot_x;
  79. rot_x = Matrix::rotate_mat_normaxis(-pitch, FLOATNAME(LVector3)(1.0f, 0.0f, 0.0f),
  80. CS_yup_right);
  81. x = x * rot_x;
  82. y = y * rot_x;
  83. z = z * rot_x;
  84. // Project the rotated X onto the XY plane.
  85. FLOATNAME(LVector2) xy(x[0], x[1]);
  86. xy = normalize(xy);
  87. // Compute the rotation about the +Z (back) axis. This is roll.
  88. FLOATTYPE roll = -rad_2_deg(((FLOATTYPE)atan2(xy[1], xy[0])));
  89. // Unwind the roll from the axes, and continue.
  90. Matrix rot_z;
  91. rot_z = Matrix::rotate_mat_normaxis(roll, FLOATNAME(LVector3)(0.0f, 0.0f, 1.0f),
  92. CS_yup_right);
  93. x = x * rot_z;
  94. y = y * rot_z;
  95. z = z * rot_z;
  96. // Reset the matrix to reflect the unwinding.
  97. mat.set_row(0, x);
  98. mat.set_row(1, y);
  99. mat.set_row(2, z);
  100. // Return the three rotation components.
  101. hpr[0] = heading;
  102. hpr[1] = pitch;
  103. hpr[2] = roll;
  104. } else {
  105. // Extract the axes from the matrix.
  106. FLOATNAME(LVector3) x, y, z;
  107. mat.get_row(x,0);
  108. mat.get_row(y,1);
  109. mat.get_row(z,2);
  110. // Project X onto the XY plane.
  111. FLOATNAME(LVector2) xy(x[0], x[1]);
  112. xy = normalize(xy);
  113. // Compute the rotation about the +Z (back) axis. This is roll.
  114. FLOATTYPE roll = rad_2_deg(((FLOATTYPE)atan2(xy[1], xy[0])));
  115. // Unwind the roll from the axes, and continue.
  116. Matrix rot_z;
  117. rot_z = Matrix::rotate_mat_normaxis(-roll, FLOATNAME(LVector3)(0.0f, 0.0f, 1.0f),
  118. CS_yup_right);
  119. x = x * rot_z;
  120. y = y * rot_z;
  121. z = z * rot_z;
  122. // Project the rotated X into the XZ plane.
  123. FLOATNAME(LVector2) xz(x[0], x[2]);
  124. xz = normalize(xz);
  125. // Compute the rotation about the +Y (up) axis. This is yaw, or
  126. // "heading".
  127. FLOATTYPE heading = rad_2_deg(((FLOATTYPE)-atan2(xz[1], xz[0])));
  128. // Unwind the heading, and continue.
  129. Matrix rot_y;
  130. rot_y = Matrix::rotate_mat_normaxis(-heading, FLOATNAME(LVector3)(0.0f, 1.0f, 0.0f),
  131. CS_yup_right);
  132. x = x * rot_y;
  133. y = y * rot_y;
  134. z = z * rot_y;
  135. // Project the rotated Z into the YZ plane.
  136. FLOATNAME(LVector2) yz(z[1], z[2]);
  137. yz = normalize(yz);
  138. // Compute the rotation about the +X (right) axis. This is pitch.
  139. FLOATTYPE pitch = rad_2_deg(((FLOATTYPE)-atan2(yz[0], yz[1])));
  140. // Unwind the pitch.
  141. Matrix rot_x;
  142. rot_x = Matrix::rotate_mat_normaxis(-pitch, FLOATNAME(LVector3)(1.0f, 0.0f, 0.0f),
  143. CS_yup_right);
  144. x = x * rot_x;
  145. y = y * rot_x;
  146. z = z * rot_x;
  147. // Reset the matrix to reflect the unwinding.
  148. mat.set_row(0, x);
  149. mat.set_row(1, y);
  150. mat.set_row(2, z);
  151. // Return the three rotation components.
  152. hpr[0] = heading;
  153. hpr[1] = pitch;
  154. hpr[2] = roll;
  155. }
  156. }
  157. ////////////////////////////////////////////////////////////////////
  158. // Function: unwind_yup_rotation
  159. // Description: Extracts the rotation about the x, y, and z axes from
  160. // the given hpr & scale matrix, given the indicated
  161. // roll amount as a hint. Adjusts the matrix to
  162. // eliminate the rotation.
  163. //
  164. // This function assumes the matrix is stored in a
  165. // right-handed Y-up coordinate system.
  166. ////////////////////////////////////////////////////////////////////
  167. static void
  168. unwind_yup_rotation(FLOATNAME(LMatrix3) &mat, FLOATNAME(LVecBase3) &hpr,
  169. FLOATTYPE roll) {
  170. if (temp_hpr_fix) {
  171. unwind_yup_rotation(mat, hpr);
  172. return;
  173. }
  174. typedef FLOATNAME(LMatrix3) Matrix;
  175. // Extract the axes from the matrix.
  176. FLOATNAME(LVector3) x, y, z;
  177. mat.get_row(x,0);
  178. mat.get_row(y,1);
  179. mat.get_row(z,2);
  180. // Unwind the roll from the axes, and continue.
  181. Matrix rot_z;
  182. rot_z = Matrix::rotate_mat_normaxis(-roll, FLOATNAME(LVector3)(0.0f, 0.0f, 1.0f),
  183. CS_yup_right);
  184. x = x * rot_z;
  185. y = y * rot_z;
  186. z = z * rot_z;
  187. // Project the rotated X into the XZ plane.
  188. FLOATNAME(LVector2) xz(x[0], x[2]);
  189. xz = normalize(xz);
  190. // Compute the rotation about the +Y (up) axis. This is yaw, or
  191. // "heading".
  192. FLOATTYPE heading = rad_2_deg(((FLOATTYPE)-atan2(xz[1], xz[0])));
  193. // Unwind the heading, and continue.
  194. Matrix rot_y;
  195. rot_y = Matrix::rotate_mat_normaxis(-heading, FLOATNAME(LVector3)(0.0f, 1.0f, 0.0f),
  196. CS_yup_right);
  197. x = x * rot_y;
  198. y = y * rot_y;
  199. z = z * rot_y;
  200. // Project the rotated Z into the YZ plane.
  201. FLOATNAME(LVector2) yz(z[1], z[2]);
  202. yz = normalize(yz);
  203. // Compute the rotation about the +X (right) axis. This is pitch.
  204. FLOATTYPE pitch = rad_2_deg(((FLOATTYPE)-atan2(yz[0], yz[1])));
  205. // Unwind the pitch.
  206. Matrix rot_x;
  207. rot_x = Matrix::rotate_mat_normaxis(-pitch, FLOATNAME(LVector3)(1.0f, 0.0f, 0.0f),
  208. CS_yup_right);
  209. x = x * rot_x;
  210. y = y * rot_x;
  211. z = z * rot_x;
  212. // Reset the matrix to reflect the unwinding.
  213. mat.set_row(0, x);
  214. mat.set_row(1, y);
  215. mat.set_row(2, z);
  216. // Return the three rotation components.
  217. hpr[0] = heading;
  218. hpr[1] = pitch;
  219. hpr[2] = roll;
  220. }
  221. ////////////////////////////////////////////////////////////////////
  222. // Function: unwind_zup_rotation
  223. // Description: Extracts the rotation about the x, y, and z axes from
  224. // the given hpr & scale matrix. Adjusts the matrix
  225. // to eliminate the rotation.
  226. //
  227. // This function assumes the matrix is stored in a
  228. // right-handed Z-up coordinate system.
  229. ////////////////////////////////////////////////////////////////////
  230. static void
  231. unwind_zup_rotation(FLOATNAME(LMatrix3) &mat, FLOATNAME(LVecBase3) &hpr) {
  232. if (temp_hpr_fix) {
  233. typedef FLOATNAME(LMatrix3) Matrix;
  234. // Extract the axes from the matrix.
  235. FLOATNAME(LVector3) x, y, z;
  236. mat.get_row(x,0);
  237. mat.get_row(y,1);
  238. mat.get_row(z,2);
  239. // Project Y into the XY plane.
  240. FLOATNAME(LVector2) xy(y[0], y[1]);
  241. xy = normalize(xy);
  242. // Compute the rotation about the +Z (up) axis. This is yaw, or
  243. // "heading".
  244. FLOATTYPE heading = -rad_2_deg(((FLOATTYPE)atan2(xy[0], xy[1])));
  245. // Unwind the heading, and continue.
  246. Matrix rot_z;
  247. rot_z = Matrix::rotate_mat_normaxis(-heading, FLOATNAME(LVector3)(0.0f, 0.0f, 1.0f),
  248. CS_zup_right);
  249. x = x * rot_z;
  250. y = y * rot_z;
  251. z = z * rot_z;
  252. // Project the rotated Y into the YZ plane.
  253. FLOATNAME(LVector2) yz(y[1], y[2]);
  254. yz = normalize(yz);
  255. // Compute the rotation about the +X (right) axis. This is pitch.
  256. FLOATTYPE pitch = rad_2_deg(((FLOATTYPE)atan2(yz[1], yz[0])));
  257. // Unwind the pitch.
  258. Matrix rot_x;
  259. rot_x = Matrix::rotate_mat_normaxis(-pitch, FLOATNAME(LVector3)(1.0f, 0.0f, 0.0f),
  260. CS_zup_right);
  261. x = x * rot_x;
  262. y = y * rot_x;
  263. z = z * rot_x;
  264. // Project X into the XZ plane.
  265. FLOATNAME(LVector2) xz(x[0], x[2]);
  266. xz = normalize(xz);
  267. // Compute the rotation about the -Y (back) axis. This is roll.
  268. FLOATTYPE roll = -rad_2_deg(((FLOATTYPE)atan2(xz[1], xz[0])));
  269. // Unwind the roll from the axes, and continue.
  270. Matrix rot_y;
  271. rot_y = Matrix::rotate_mat_normaxis(-roll, FLOATNAME(LVector3)(0.0f, 1.0f, 0.0f),
  272. CS_zup_right);
  273. x = x * rot_y;
  274. y = y * rot_y;
  275. z = z * rot_y;
  276. // Reset the matrix to reflect the unwinding.
  277. mat.set_row(0, x);
  278. mat.set_row(1, y);
  279. mat.set_row(2, z);
  280. // Return the three rotation components.
  281. hpr[0] = heading;
  282. hpr[1] = pitch;
  283. hpr[2] = roll;
  284. } else {
  285. typedef FLOATNAME(LMatrix3) Matrix;
  286. // Extract the axes from the matrix.
  287. FLOATNAME(LVector3) x, y, z;
  288. mat.get_row(x,0);
  289. mat.get_row(y,1);
  290. mat.get_row(z,2);
  291. // Project X into the XZ plane.
  292. FLOATNAME(LVector2) xz(x[0], x[2]);
  293. xz = normalize(xz);
  294. // Compute the rotation about the -Y (back) axis. This is roll.
  295. FLOATTYPE roll = rad_2_deg(((FLOATTYPE)atan2(xz[1], xz[0])));
  296. if (y[1] < 0.0f) {
  297. if (roll < 0.0f) {
  298. roll += 180.0;
  299. } else {
  300. roll -= 180.0;
  301. }
  302. }
  303. // Unwind the roll from the axes, and continue.
  304. Matrix rot_y;
  305. rot_y = Matrix::rotate_mat_normaxis(roll, FLOATNAME(LVector3)(0.0f, 1.0f, 0.0f),
  306. CS_zup_right);
  307. x = x * rot_y;
  308. y = y * rot_y;
  309. z = z * rot_y;
  310. // Project the rotated X into the XY plane.
  311. FLOATNAME(LVector2) xy(x[0], x[1]);
  312. xy = normalize(xy);
  313. // Compute the rotation about the +Z (up) axis. This is yaw, or
  314. // "heading".
  315. FLOATTYPE heading = rad_2_deg(((FLOATTYPE)atan2(xy[1], xy[0])));
  316. // Unwind the heading, and continue.
  317. Matrix rot_z;
  318. rot_z = Matrix::rotate_mat_normaxis(-heading, FLOATNAME(LVector3)(0.0f, 0.0f, 1.0f),
  319. CS_zup_right);
  320. x = x * rot_z;
  321. y = y * rot_z;
  322. z = z * rot_z;
  323. // Project the rotated Y into the YZ plane.
  324. FLOATNAME(LVector2) yz(y[1], y[2]);
  325. yz = normalize(yz);
  326. // Compute the rotation about the +X (right) axis. This is pitch.
  327. FLOATTYPE pitch = rad_2_deg(((FLOATTYPE)atan2(yz[1], yz[0])));
  328. // Unwind the pitch.
  329. Matrix rot_x;
  330. rot_x = Matrix::rotate_mat_normaxis(-pitch, FLOATNAME(LVector3)(1.0f, 0.0f, 0.0f),
  331. CS_zup_right);
  332. x = x * rot_x;
  333. y = y * rot_x;
  334. z = z * rot_x;
  335. // Reset the matrix to reflect the unwinding.
  336. mat.set_row(0, x);
  337. mat.set_row(1, y);
  338. mat.set_row(2, z);
  339. // Return the three rotation components.
  340. hpr[0] = heading;
  341. hpr[1] = pitch;
  342. hpr[2] = roll;
  343. }
  344. }
  345. ////////////////////////////////////////////////////////////////////
  346. // Function: unwind_zup_rotation
  347. // Description: Extracts the rotation about the x, y, and z axes from
  348. // the given hpr & scale matrix, given the indicated
  349. // roll amount as a hint. Adjusts the matrix to
  350. // eliminate the rotation.
  351. //
  352. // This function assumes the matrix is stored in a
  353. // right-handed Z-up coordinate system.
  354. ////////////////////////////////////////////////////////////////////
  355. static void
  356. unwind_zup_rotation(FLOATNAME(LMatrix3) &mat, FLOATNAME(LVecBase3) &hpr,
  357. FLOATTYPE roll) {
  358. if (temp_hpr_fix) {
  359. unwind_zup_rotation(mat, hpr);
  360. return;
  361. }
  362. typedef FLOATNAME(LMatrix3) Matrix;
  363. // Extract the axes from the matrix.
  364. FLOATNAME(LVector3) x, y, z;
  365. mat.get_row(x,0);
  366. mat.get_row(y,1);
  367. mat.get_row(z,2);
  368. // Unwind the roll from the axes, and continue.
  369. Matrix rot_y;
  370. rot_y = Matrix::rotate_mat_normaxis(roll, FLOATNAME(LVector3)(0.0f, 1.0f, 0.0f),
  371. CS_zup_right);
  372. x = x * rot_y;
  373. y = y * rot_y;
  374. z = z * rot_y;
  375. // Project the rotated X into the XY plane.
  376. FLOATNAME(LVector2) xy(x[0], x[1]);
  377. xy = normalize(xy);
  378. // Compute the rotation about the +Z (up) axis. This is yaw, or
  379. // "heading".
  380. FLOATTYPE heading = rad_2_deg(((FLOATTYPE)atan2(xy[1], xy[0])));
  381. // Unwind the heading, and continue.
  382. Matrix rot_z;
  383. rot_z = Matrix::rotate_mat_normaxis(-heading, FLOATNAME(LVector3)(0.0f, 0.0f, 1.0f),
  384. CS_zup_right);
  385. x = x * rot_z;
  386. y = y * rot_z;
  387. z = z * rot_z;
  388. // Project the rotated Y into the YZ plane.
  389. FLOATNAME(LVector2) yz(y[1], y[2]);
  390. yz = normalize(yz);
  391. // Compute the rotation about the +X (right) axis. This is pitch.
  392. FLOATTYPE pitch = rad_2_deg(((FLOATTYPE)atan2(yz[1], yz[0])));
  393. // Unwind the pitch.
  394. Matrix rot_x;
  395. rot_x = Matrix::rotate_mat_normaxis(-pitch, FLOATNAME(LVector3)(1.0f, 0.0f, 0.0f),
  396. CS_zup_right);
  397. x = x * rot_x;
  398. y = y * rot_x;
  399. z = z * rot_x;
  400. // Reset the matrix to reflect the unwinding.
  401. mat.set_row(0, x);
  402. mat.set_row(1, y);
  403. mat.set_row(2, z);
  404. // Return the three rotation components.
  405. hpr[0] = heading;
  406. hpr[1] = pitch;
  407. hpr[2] = roll;
  408. }
  409. ////////////////////////////////////////////////////////////////////
  410. // Function: decompose_matrix
  411. // Description: Extracts out the components of a 3x3 rotation matrix.
  412. // Returns true if the scale and hpr completely describe
  413. // the matrix, or false if there is also a shear
  414. // component or if the matrix is not affine.
  415. ////////////////////////////////////////////////////////////////////
  416. bool
  417. decompose_matrix(const FLOATNAME(LMatrix3) &mat,
  418. FLOATNAME(LVecBase3) &scale,
  419. FLOATNAME(LVecBase3) &hpr,
  420. CoordinateSystem cs) {
  421. if (cs == CS_default) {
  422. cs = default_coordinate_system;
  423. }
  424. if (linmath_cat.is_debug()) {
  425. linmath_cat.debug()
  426. << "decomposing " << mat << " via cs " << cs << "\n";
  427. }
  428. // Extract the rotation and scale, according to the coordinate
  429. // system of choice.
  430. bool is_left_handed;
  431. FLOATNAME(LMatrix3) new_mat(mat);
  432. switch (cs) {
  433. case CS_zup_right:
  434. {
  435. unwind_zup_rotation(new_mat, hpr);
  436. is_left_handed = false;
  437. }
  438. break;
  439. case CS_yup_right:
  440. {
  441. unwind_yup_rotation(new_mat, hpr);
  442. is_left_handed = false;
  443. }
  444. break;
  445. case CS_zup_left:
  446. {
  447. new_mat._m.m._02 = -new_mat._m.m._02;
  448. new_mat._m.m._12 = -new_mat._m.m._12;
  449. new_mat._m.m._20 = -new_mat._m.m._20;
  450. new_mat._m.m._21 = -new_mat._m.m._21;
  451. /*
  452. FLOATNAME(LMatrix3) lm(mat(0, 0), mat(0, 1), -mat(0, 2),
  453. mat(1, 0), mat(1, 1), -mat(1, 2),
  454. -mat(2, 0), -mat(2, 1), mat(2, 2));
  455. */
  456. unwind_zup_rotation(new_mat, hpr);
  457. hpr[0] = -hpr[0];
  458. hpr[2] = -hpr[2];
  459. is_left_handed = true;
  460. }
  461. break;
  462. case CS_yup_left:
  463. {
  464. new_mat._m.m._02 = -new_mat._m.m._02;
  465. new_mat._m.m._12 = -new_mat._m.m._12;
  466. new_mat._m.m._20 = -new_mat._m.m._20;
  467. new_mat._m.m._21 = -new_mat._m.m._21;
  468. /*
  469. FLOATNAME(LMatrix3) lm(mat(0, 0), mat(0, 1), -mat(0, 2),
  470. mat(1, 0), mat(1, 1), -mat(1, 2),
  471. -mat(2, 0), -mat(2, 1), mat(2, 2));
  472. */
  473. unwind_yup_rotation(new_mat, hpr);
  474. is_left_handed = true;
  475. }
  476. break;
  477. default:
  478. linmath_cat.error()
  479. << "Unexpected coordinate system: " << (int)cs << "\n";
  480. return false;
  481. }
  482. if (linmath_cat.is_debug()) {
  483. linmath_cat.debug()
  484. << "after unwind, mat is " << new_mat << "\n";
  485. }
  486. scale[0] = new_mat._m.m._00;
  487. scale[1] = new_mat._m.m._11;
  488. scale[2] = new_mat._m.m._22;
  489. /*
  490. if (is_left_handed) {
  491. scale[0] = -new_mat._m.m._00;
  492. scale[1] = -new_mat._m.m._11;
  493. }
  494. */
  495. bool has_no_shear =
  496. (fabs(new_mat(0, 1)) + fabs(new_mat(0, 2)) +
  497. fabs(new_mat(1, 0)) + fabs(new_mat(1, 2)) +
  498. fabs(new_mat(2, 0)) + fabs(new_mat(2, 1))) < 0.0001;
  499. return has_no_shear;
  500. }
  501. ////////////////////////////////////////////////////////////////////
  502. // Function: decompose_matrix
  503. // Description: Extracts out the components of a 3x3 rotation matrix.
  504. // Returns true if the scale and hpr completely describe
  505. // the matrix, or false if there is also a shear
  506. // component or if the matrix is not affine.
  507. //
  508. // This flavor of the function accepts an expected roll
  509. // amount. This amount will be used as the roll
  510. // component, rather than attempting to determine roll
  511. // by examining the matrix; this helps alleviate roll
  512. // instability due to roundoff errors or gimbal lock.
  513. ////////////////////////////////////////////////////////////////////
  514. bool
  515. decompose_matrix(const FLOATNAME(LMatrix3) &mat,
  516. FLOATNAME(LVecBase3) &scale,
  517. FLOATNAME(LVecBase3) &hpr,
  518. FLOATTYPE roll,
  519. CoordinateSystem cs) {
  520. if (cs == CS_default) {
  521. cs = default_coordinate_system;
  522. }
  523. if (linmath_cat.is_debug()) {
  524. linmath_cat.debug()
  525. << "decomposing " << mat << " via cs " << cs
  526. << " with roll = " << roll << "\n";
  527. }
  528. // Extract the rotation and scale, according to the coordinate
  529. // system of choice.
  530. bool is_left_handed;
  531. FLOATNAME(LMatrix3) new_mat(mat);
  532. switch (cs) {
  533. case CS_zup_right:
  534. {
  535. unwind_zup_rotation(new_mat, hpr, roll);
  536. is_left_handed = false;
  537. }
  538. break;
  539. case CS_yup_right:
  540. {
  541. unwind_yup_rotation(new_mat, hpr, roll);
  542. is_left_handed = false;
  543. }
  544. break;
  545. case CS_zup_left:
  546. {
  547. new_mat._m.m._02 = -new_mat._m.m._02;
  548. new_mat._m.m._12 = -new_mat._m.m._12;
  549. new_mat._m.m._20 = -new_mat._m.m._20;
  550. new_mat._m.m._21 = -new_mat._m.m._21;
  551. /*
  552. FLOATNAME(LMatrix3) lm(mat(0, 0), mat(0, 1), -mat(0, 2),
  553. mat(1, 0), mat(1, 1), -mat(1, 2),
  554. -mat(2, 0), -mat(2, 1), mat(2, 2));
  555. */
  556. unwind_zup_rotation(new_mat, hpr, roll);
  557. is_left_handed = true;
  558. }
  559. break;
  560. case CS_yup_left:
  561. {
  562. new_mat._m.m._02 = -new_mat._m.m._02;
  563. new_mat._m.m._12 = -new_mat._m.m._12;
  564. new_mat._m.m._20 = -new_mat._m.m._20;
  565. new_mat._m.m._21 = -new_mat._m.m._21;
  566. /*
  567. FLOATNAME(LMatrix3) lm(mat(0, 0), mat(0, 1), -mat(0, 2),
  568. mat(1, 0), mat(1, 1), -mat(1, 2),
  569. -mat(2, 0), -mat(2, 1), mat(2, 2));
  570. */
  571. unwind_yup_rotation(new_mat, hpr, roll);
  572. is_left_handed = true;
  573. }
  574. break;
  575. default:
  576. linmath_cat.error()
  577. << "Unexpected coordinate system: " << (int)cs << "\n";
  578. return false;
  579. }
  580. if (linmath_cat.is_debug()) {
  581. linmath_cat.debug()
  582. << "after unwind, mat is " << new_mat << "\n";
  583. }
  584. scale[0] = new_mat._m.m._00;
  585. scale[1] = new_mat._m.m._11;
  586. scale[2] = new_mat._m.m._22;
  587. /*
  588. if (is_left_handed) {
  589. scale[0] = -new_mat._m.m._00;
  590. scale[1] = -new_mat._m.m._11;
  591. }
  592. */
  593. bool has_no_shear =
  594. (fabs(new_mat(0, 1)) + fabs(new_mat(0, 2)) +
  595. fabs(new_mat(1, 0)) + fabs(new_mat(1, 2)) +
  596. fabs(new_mat(2, 0)) + fabs(new_mat(2, 1))) < 0.0001;
  597. return has_no_shear;
  598. }