PageRenderTime 43ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/lipsofsuna/math/math-unittest.c

https://github.com/deldiablo/GodheadLips
C | 848 lines | 759 code | 54 blank | 35 comment | 87 complexity | 981ec6545a0f7b9ac4c6ba0862b385f6 MD5 | raw file
  1. /* Lips of Suna
  2. * Copyright© 2007-2011 Lips of Suna development team.
  3. *
  4. * Lips of Suna is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Lesser General Public License as
  6. * published by the Free Software Foundation, either version 3 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * Lips of Suna is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public License
  15. * along with Lips of Suna. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include "lipsofsuna/math.h"
  18. #define EPSILON 0.05
  19. static inline int check_matrix (LIMatMatrix m0, LIMatMatrix m1)
  20. {
  21. int i;
  22. for (i = 0 ; i < 15 ; i++)
  23. {
  24. if (LIMAT_ABS (m0.m[i] - m1.m[i]) > EPSILON)
  25. return 0;
  26. }
  27. return 1;
  28. }
  29. static inline int check_quaternion (LIMatQuaternion q0, LIMatQuaternion q1)
  30. {
  31. if (q0.w < 0.0f ||
  32. (q0.w == 0.0f && q0.z < 0.0f) ||
  33. (q0.w == 0.0f && q0.z == 0.0f && q0.y < 0.0f) ||
  34. (q0.w == 0.0f && q0.z == 0.0f && q0.y == 0.0f && q0.x < 0.0f))
  35. q0 = limat_quaternion_init (-q0.x, -q0.y, -q0.z, -q0.w);
  36. if (q1.w < 0.0f ||
  37. (q1.w == 0.0f && q1.z < 0.0f) ||
  38. (q1.w == 0.0f && q1.z == 0.0f && q1.y < 0.0f) ||
  39. (q1.w == 0.0f && q1.z == 0.0f && q1.y == 0.0f && q1.x < 0.0f))
  40. q1 = limat_quaternion_init (-q1.x, -q1.y, -q1.z, -q1.w);
  41. if (LIMAT_ABS (q0.x - q1.x) > EPSILON ||
  42. LIMAT_ABS (q0.y - q1.y) > EPSILON ||
  43. LIMAT_ABS (q0.z - q1.z) > EPSILON ||
  44. LIMAT_ABS (q0.w - q1.w) > EPSILON)
  45. return 0;
  46. return 1;
  47. }
  48. static inline int check_vector (LIMatVector v0, LIMatVector v1)
  49. {
  50. if (LIMAT_ABS (v0.x - v1.x) > EPSILON ||
  51. LIMAT_ABS (v0.y - v1.y) > EPSILON ||
  52. LIMAT_ABS (v0.z - v1.z) > EPSILON)
  53. return 0;
  54. return 1;
  55. }
  56. static inline int check_transform (LIMatTransform t0, LIMatTransform t1)
  57. {
  58. return check_vector (t0.position, t1.position) &&
  59. check_quaternion (t0.rotation, t1.rotation);
  60. }
  61. static inline void print_quaternion (const char* s, LIMatQuaternion q)
  62. {
  63. printf ("%s: Quaternion({%f,%f,%f,%f})\n",
  64. s, q.x, q.y, q.z, q.w);
  65. }
  66. static inline void print_vector (const char* s, LIMatVector v)
  67. {
  68. printf ("%s: Vector({%f,%f,%f})\n",
  69. s, v.x, v.y, v.z);
  70. }
  71. static inline void print_transform (const char* s, LIMatTransform t)
  72. {
  73. printf ("%s: Transform({%f,%f,%f}, {%f,%f,%f,%f})\n",
  74. s, t.position.x, t.position.y, t.position.z,
  75. t.rotation.x, t.rotation.y, t.rotation.z, t.rotation.w);
  76. }
  77. static inline void print_matrix (const char* s, LIMatMatrix m)
  78. {
  79. printf ("%s: Matrix({%f,%f,%f,%f}, {%f,%f,%f,%f}, {%f,%f,%f,%f}, {%f,%f,%f,%f})\n",
  80. s, m.m[0], m.m[1], m.m[2], m.m[3],
  81. m.m[4], m.m[5], m.m[6], m.m[7],
  82. m.m[8], m.m[9], m.m[10], m.m[11],
  83. m.m[12], m.m[13], m.m[14], m.m[15]);
  84. }
  85. static inline void print_dualquat (const char* s, LIMatDualquat dq)
  86. {
  87. printf ("%s: Dualquat({%f,%f,%f,%f}, {%f,%f,%f,%f})\n",
  88. s, dq.r.x, dq.r.y, dq.r.z, dq.r.w, dq.d.x, dq.d.y, dq.d.z, dq.d.w);
  89. }
  90. /*****************************************************************************/
  91. static void convert_quaternion_matrix ()
  92. {
  93. LIMatMatrix m0;
  94. LIMatMatrix m1;
  95. LIMatQuaternion q0;
  96. LIMatQuaternion q1;
  97. printf ("Testing quaternion-matrix conversion...\n");
  98. m0 = limat_matrix_rotation (2.0f, 1.0f, 0.0f, 0.0f);
  99. q0 = limat_convert_matrix_to_quaternion (m0);
  100. m1 = limat_convert_quaternion_to_matrix (q0);
  101. if (!check_matrix (m0, m1))
  102. {
  103. printf ("1: FAILED!\n");
  104. print_matrix ("M", m0);
  105. print_quaternion ("M->Q", q0);
  106. print_matrix ("Q->M", m1);
  107. }
  108. q0 = limat_quaternion_conjugate (q0);
  109. m0 = limat_convert_quaternion_to_matrix (q0);
  110. q1 = limat_convert_matrix_to_quaternion (m0);
  111. if (!check_quaternion (q0, q1))
  112. {
  113. printf ("2: FAILED!\n");
  114. print_quaternion ("Q", q0);
  115. print_matrix ("Q->M", m0);
  116. print_quaternion ("M->Q", q1);
  117. }
  118. }
  119. static void convert_transform_matrix ()
  120. {
  121. LIMatMatrix m0;
  122. LIMatMatrix m1;
  123. LIMatTransform t0;
  124. LIMatTransform t1;
  125. printf ("Testing transform-matrix conversion...\n");
  126. m0 = limat_matrix_rotation (2.0f, 1.0f, 0.0f, 0.0f);
  127. m1 = limat_matrix_translation (100.0f, 0.0f, -10.0f);
  128. m0 = limat_matrix_multiply (m0, m1);
  129. t0 = limat_convert_matrix_to_transform (m0);
  130. m1 = limat_convert_transform_to_matrix (t0);
  131. if (!check_matrix (m0, m1))
  132. {
  133. printf ("1: FAILED!\n");
  134. print_matrix ("M", m0);
  135. print_transform ("M->T", t0);
  136. print_matrix ("T->M", m1);
  137. }
  138. t0 = limat_transform_init (
  139. limat_vector_init (0.0f, -50.0f, 1000.0f),
  140. limat_quaternion_init (0.707f, 0.0f, 0.707f, 0.0f));
  141. m0 = limat_convert_transform_to_matrix (t0);
  142. t1 = limat_convert_matrix_to_transform (m0);
  143. if (!check_transform (t0, t1))
  144. {
  145. printf ("2: FAILED!\n");
  146. print_transform ("T", t0);
  147. print_matrix ("T->M", m0);
  148. print_transform ("M->T", t1);
  149. }
  150. }
  151. /**
  152. * The reference rotation matrix was created using Bullet maths library.
  153. *
  154. * The reference lookat matrices were created using gluLookAt.
  155. */
  156. static void matrix_basics ()
  157. {
  158. LIMatMatrix m0;
  159. LIMatMatrix m1 = {{ 0.877583, 0.000000, -0.479426, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.479426, 0.000000, 0.877583, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000 }};
  160. LIMatMatrix m2 = {{ 0.953184, -0.164941, 0.253446, 0.000000, 0.000000, 0.838140, 0.545455, 0.000000, -0.302391, -0.519919, 0.798901, 0.000000, -0.460111, 0.484196, -37.410606, 1.000000 }};
  161. LIMatMatrix m3 = {{ -0.103476, 0.023157, -0.994362, 0.000000, -0.819851, 0.564050, 0.098452, 0.000000, 0.563150, 0.825416, -0.039381, 0.000000, -1.585974, -2.499405, -100.460136, 1.000000 }};
  162. printf ("Testing matrix basics...\n");
  163. m0 = limat_matrix_rotation (0.5, 0.0, 1.0, 0.0);
  164. if (!check_matrix (m0, m1))
  165. {
  166. printf ("1: FAILED!\n");
  167. print_matrix ("Got", m0);
  168. print_matrix ("Expected", m1);
  169. }
  170. m0 = limat_matrix_lookat (10, 20, 30, 0.707, 0, 0.707, 0, 1, 0);
  171. if (!check_matrix (m0, m2))
  172. {
  173. printf ("2: FAILED!\n");
  174. print_matrix ("Got", m0);
  175. print_matrix ("Expected", m2);
  176. }
  177. m0 = limat_matrix_lookat (-100, 10, -1, 1, 0, 3, -2, 3, 4);
  178. if (!check_matrix (m0, m3))
  179. {
  180. printf ("3: FAILED!\n");
  181. print_matrix ("Got", m0);
  182. print_matrix ("Expected", m3);
  183. }
  184. }
  185. static void matrix_basis ()
  186. {
  187. LIMatVector v0;
  188. LIMatVector v1;
  189. LIMatMatrix m0 = {{ 0.621610, 0.783327, 0.000000, 0.000000, -0.783327, 0.621610, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000 }};
  190. printf ("Testing matrix basis...\n");
  191. v0 = limat_matrix_get_basis (m0, 0);
  192. v1 = limat_vector_init (0.621610, -0.783327, 0.000000);
  193. if (!check_vector (v0, v1))
  194. {
  195. printf ("1: FAILED!\n");
  196. print_vector ("Got", v0);
  197. print_vector ("Expected", v1);
  198. }
  199. v0 = limat_matrix_get_basis (m0, 1);
  200. v1 = limat_vector_init (0.783327, 0.621610, 0.000000);
  201. if (!check_vector (v0, v1))
  202. {
  203. printf ("2: FAILED!\n");
  204. print_vector ("Got", v0);
  205. print_vector ("Expected", v1);
  206. }
  207. v0 = limat_matrix_get_basis (m0, 2);
  208. v1 = limat_vector_init (0.000000, 0.000000, 1.000000);
  209. if (!check_vector (v0, v1))
  210. {
  211. printf ("3: FAILED!\n");
  212. print_vector ("Got", v0);
  213. print_vector ("Expected", v1);
  214. }
  215. }
  216. static void matrix_look ()
  217. {
  218. LIMatMatrix m0;
  219. LIMatVector v0;
  220. LIMatVector v1;
  221. printf ("Testing matrix look...\n");
  222. m0 = limat_matrix_look (10, 20, 30, 0, 0, -1, 0, 1, 0);
  223. v0 = limat_vector_init (0.0f, 0.0f, 0.0f);
  224. v1 = limat_vector_init (-10.0f, -20.0f, -30.0f);
  225. v0 = limat_matrix_transform (m0, v0);
  226. if (!check_vector (v0, v1))
  227. {
  228. printf ("1: FAILED!\n");
  229. print_vector ("Got", v0);
  230. print_vector ("Expected", v1);
  231. }
  232. v0 = limat_vector_init (1.0f, 0.0f, 0.0f);
  233. v1 = limat_vector_init (-9.0f, -20.0f, -30.0f);
  234. v0 = limat_matrix_transform (m0, v0);
  235. if (!check_vector (v0, v1))
  236. {
  237. printf ("2: FAILED!\n");
  238. print_vector ("Got", v0);
  239. print_vector ("Expected", v1);
  240. }
  241. v0 = limat_vector_init (0.0f, 1.0f, 0.0f);
  242. v1 = limat_vector_init (-10.0f, -19.0f, -30.0f);
  243. v0 = limat_matrix_transform (m0, v0);
  244. if (!check_vector (v0, v1))
  245. {
  246. printf ("3: FAILED!\n");
  247. print_vector ("Got", v0);
  248. print_vector ("Expected", v1);
  249. }
  250. v0 = limat_vector_init (0.0f, 0.0f, 1.0f);
  251. v1 = limat_vector_init (-10.0f, -20.0f, -29.0f);
  252. v0 = limat_matrix_transform (m0, v0);
  253. if (!check_vector (v0, v1))
  254. {
  255. printf ("4: FAILED!\n");
  256. print_vector ("Got", v0);
  257. print_vector ("Expected", v1);
  258. }
  259. }
  260. /**
  261. * The reference perpective matrix was created using gluPerspective.
  262. */
  263. static void matrix_perspective ()
  264. {
  265. LIMatMatrix m0;
  266. LIMatMatrix m1 = {{ 0.764657, 0.000000, 0.000000, 0.000000, 0.000000, 1.376382, 0.000000, 0.000000, 0.000000, 0.000000, -4.040000, -1.000000, 0.000000, 0.000000, -172.367996, 0.000000 }};
  267. printf ("Testing matrix perspective...\n");
  268. m0 = limat_matrix_perspective (72.0f / 180.0f * M_PI, 1.8, 34.2, 56.7);
  269. if (!check_matrix (m0, m1))
  270. {
  271. printf ("1: FAILED!\n");
  272. print_matrix ("Got", m0);
  273. print_matrix ("Expected", m1);
  274. }
  275. }
  276. /**
  277. * \brief Does a basic conformance test for quaternions.
  278. *
  279. * The reference results were calculated using the maths library of Bullet.
  280. * Vector by quaternion transformation was performed by first converting the
  281. * quaternion to a matrix and then multiplying the vector by the matrix.
  282. */
  283. static void quaternion_basics ()
  284. {
  285. LIMatQuaternion q0;
  286. LIMatQuaternion q1;
  287. LIMatVector v0;
  288. LIMatVector v1;
  289. printf ("Testing quaternion basics...\n");
  290. q0 = limat_quaternion_init (1.0, 2.0, 3.0, 4.0);
  291. q1 = limat_quaternion_init (-1.0, 0.5, 1.0, -2.0);
  292. q0 = limat_quaternion_multiply (q0, q1);
  293. q1 = limat_quaternion_init (-5.500000, -6.000000, 0.500000, -11.000000);
  294. if (!check_quaternion (q0, q1))
  295. {
  296. printf ("1: FAILED!\n");
  297. print_quaternion ("Got", q0);
  298. print_quaternion ("Expected", q1);
  299. }
  300. q0 = limat_quaternion_rotation (0.5f, limat_vector_init (0.0f, 1.0f, 0.0f));
  301. q1 = limat_quaternion_init (0.000000, 0.247404, 0.000000, 0.968912);
  302. if (!check_quaternion (q0, q1))
  303. {
  304. printf ("2: FAILED!\n");
  305. print_quaternion ("Got", q0);
  306. print_quaternion ("Expected", q1);
  307. }
  308. v0 = limat_quaternion_transform (q0, limat_vector_init (2.0f, 3.0f, 4.0f));
  309. v1 = limat_vector_init (3.672867, 3.000000, 2.551479);
  310. if (!check_vector (v0, v1))
  311. {
  312. printf ("3: FAILED!\n");
  313. print_vector ("Got", v0);
  314. print_vector ("Expected", v1);
  315. }
  316. q0 = limat_quaternion_rotation (-1.5f, limat_vector_init (1.0f, 0.0f, 0.0f));
  317. q1 = limat_quaternion_init (-0.681639, -0.000000, -0.000000, 0.731689);
  318. if (!check_quaternion (q0, q1))
  319. {
  320. printf ("4: FAILED!\n");
  321. print_quaternion ("Got", q0);
  322. print_quaternion ("Expected", q1);
  323. }
  324. v0 = limat_quaternion_transform (q0, limat_vector_init (-5.0f, 0.5f, 1.0f));
  325. v1 = limat_vector_init (-5.000000, 1.032864, -0.428010);
  326. if (!check_vector (v0, v1))
  327. {
  328. printf ("5: FAILED!\n");
  329. print_vector ("Got", v0);
  330. print_vector ("Expected", v1);
  331. }
  332. q0 = limat_quaternion_init (0.0f, 0.0f, 0.0f, 0.0f);
  333. q0 = limat_quaternion_normalize (q0);
  334. q1 = limat_quaternion_init (0.0f, 0.0f, 0.0f, 0.0f);
  335. if (isnan (q0.x) || isnan (q0.y) || isnan (q0.z) || isnan (q0.w))
  336. {
  337. printf ("6: FAILED!\n");
  338. print_quaternion ("Got", q0);
  339. print_quaternion ("Expected", q1);
  340. }
  341. }
  342. static void quaternion_multiply ()
  343. {
  344. LIMatMatrix m0;
  345. LIMatMatrix m1;
  346. LIMatMatrix m2;
  347. LIMatQuaternion q0;
  348. LIMatQuaternion q1;
  349. LIMatQuaternion q2;
  350. LIMatQuaternion q3;
  351. LIMatVector v0;
  352. LIMatVector v1;
  353. printf ("Testing quaternion multiplication...\n");
  354. q0 = limat_quaternion_rotation (0.5f, limat_vector_init (0.0f, 1.0f, 0.0f));
  355. m0 = limat_matrix_rotation (0.5f, 0.0f, 1.0f, 0.0f);
  356. v0 = limat_quaternion_transform (q0, limat_vector_init (10.0f, 100.0f, -50.0f));
  357. v1 = limat_matrix_transform (m0, limat_vector_init (10.0f, 100.0f, -50.0f));
  358. if (!check_vector (v0, v1))
  359. {
  360. printf ("1: FAILED!\n");
  361. print_matrix ("M", m0);
  362. print_quaternion ("M->Q", limat_convert_matrix_to_quaternion (m0));
  363. print_quaternion ("Q", q0);
  364. print_vector ("M*v", v0);
  365. print_vector ("Q*v", v1);
  366. }
  367. q1 = limat_quaternion_rotation (1.0f, limat_vector_init (1.0f, 0.0f, 0.0f));
  368. q2 = limat_quaternion_multiply (q0, q1);
  369. m1 = limat_matrix_rotation (1.0f, 1.0f, 0.0f, 0.0f);
  370. m2 = limat_matrix_multiply (m0, m1);
  371. q3 = limat_convert_matrix_to_quaternion (m2);
  372. if (!check_quaternion (q2, q3))
  373. {
  374. printf ("2: FAILED!\n");
  375. print_matrix ("M", m2);
  376. print_quaternion ("M->Q", q3);
  377. print_quaternion ("Q", q2);
  378. }
  379. q2 = limat_quaternion_multiply (q1, q0);
  380. m2 = limat_matrix_multiply (m1, m0);
  381. q3 = limat_convert_matrix_to_quaternion (m2);
  382. if (!check_quaternion (q2, q3))
  383. {
  384. printf ("3: FAILED!\n");
  385. print_matrix ("M", m2);
  386. print_quaternion ("M->Q", q3);
  387. print_quaternion ("Q", q2);
  388. }
  389. }
  390. static void quaternion_rotation ()
  391. {
  392. LIMatMatrix m0;
  393. LIMatQuaternion q0;
  394. LIMatQuaternion q1;
  395. LIMatVector v0;
  396. LIMatVector v1;
  397. printf ("Testing quaternion rotation...\n");
  398. m0 = limat_matrix_rotation (0.5f, 0.0f, 1.0f, 0.0f);
  399. q0 = limat_quaternion_rotation (0.5f, limat_vector_init (0.0f, 1.0f, 0.0f));
  400. q1 = limat_convert_matrix_to_quaternion (m0);
  401. if (!check_quaternion (q0, q1))
  402. {
  403. printf ("1: FAILED!\n");
  404. print_matrix ("M", m0);
  405. print_quaternion ("Q", q0);
  406. print_quaternion ("M->Q", q1);
  407. }
  408. v0 = limat_matrix_transform (m0, limat_vector_init (10.0f, -10.0f, 0.0f));
  409. v1 = limat_quaternion_transform (q0, limat_vector_init (10.0f, -10.0f, 0.0f));
  410. if (!check_vector (v0, v1))
  411. {
  412. printf ("2: FAILED!\n");
  413. print_matrix ("M", m0);
  414. print_vector ("Q*v", v0);
  415. print_vector ("M*v", v1);
  416. }
  417. }
  418. static void quaternion_look ()
  419. {
  420. LIMatMatrix m0;
  421. LIMatQuaternion q0;
  422. LIMatQuaternion q1;
  423. LIMatVector v0;
  424. LIMatVector v1;
  425. printf ("Testing quaternion look...\n");
  426. q0 = limat_quaternion_look (limat_vector_init (0.707, 0.0, 0.707), limat_vector_init (0.0, 1.0, 0.0));
  427. m0 = limat_matrix_look (0.0, 0.0, 0.0, 0.707, 0.0, 0.707, 0.0, 1.0, 0.0);
  428. q1 = limat_convert_matrix_to_quaternion (m0);
  429. if (!check_quaternion (q0, q1))
  430. {
  431. printf ("1: FAILED!\n");
  432. print_matrix ("M", m0);
  433. print_quaternion ("M->Q", q1);
  434. print_quaternion ("Q", q0);
  435. }
  436. v0 = limat_matrix_transform (m0, limat_vector_init (10.0f, -10.0f, 0.0f));
  437. v1 = limat_quaternion_transform (q0, limat_vector_init (10.0f, -10.0f, 0.0f));
  438. if (!check_vector (v0, v1))
  439. {
  440. printf ("2: FAILED!\n");
  441. print_vector ("M*v", v0);
  442. print_vector ("Q*v", v1);
  443. }
  444. }
  445. static void quaternion_basis ()
  446. {
  447. LIMatMatrix m0;
  448. LIMatQuaternion q0;
  449. LIMatQuaternion q1;
  450. LIMatVector v0;
  451. LIMatVector v1;
  452. printf ("Testing quaternion basis...\n");
  453. q0 = limat_quaternion_init (0.000000, 0.000000, 0.434966, 0.900447);
  454. v0 = limat_quaternion_get_basis (q0, 0);
  455. v1 = limat_vector_init (0.621610, -0.783327, 0.000000);
  456. if (!check_vector (v0, v1))
  457. {
  458. printf ("1: FAILED!\n");
  459. print_vector ("Got", v0);
  460. print_vector ("Expected", v1);
  461. }
  462. v0 = limat_quaternion_get_basis (q0, 1);
  463. v1 = limat_vector_init (0.783327, 0.621610, 0.000000);
  464. if (!check_vector (v0, v1))
  465. {
  466. printf ("2: FAILED!\n");
  467. print_vector ("Got", v0);
  468. print_vector ("Expected", v1);
  469. }
  470. v0 = limat_quaternion_get_basis (q0, 2);
  471. v1 = limat_vector_init (0.000000, 0.000000, 1.000000);
  472. if (!check_vector (v0, v1))
  473. {
  474. printf ("3: FAILED!\n");
  475. print_vector ("Got", v0);
  476. print_vector ("Expected", v1);
  477. }
  478. q0 = limat_quaternion_look (limat_vector_init (-0.707, 0.0, 0.707), limat_vector_init (0.0, 1.0, 0.0));
  479. m0 = limat_matrix_look (0.0, 0.0, 0.0, -0.707, 0.0, 0.707, 0.0, 1.0, 0.0);
  480. q1 = limat_convert_matrix_to_quaternion (m0);
  481. if (!check_quaternion (q0, q1))
  482. {
  483. printf ("4: FAILED!\n");
  484. print_matrix ("M", m0);
  485. print_quaternion ("M->Q", q1);
  486. print_quaternion ("Q", q0);
  487. }
  488. v0 = limat_matrix_get_basis (m0, 0);
  489. v1 = limat_quaternion_get_basis (q0, 0);
  490. if (!check_vector (v0, v1))
  491. {
  492. printf ("5: FAILED!\n");
  493. print_vector ("M.x", v0);
  494. print_vector ("Q.x", v1);
  495. }
  496. v0 = limat_matrix_get_basis (m0, 1);
  497. v1 = limat_quaternion_get_basis (q0, 1);
  498. if (!check_vector (v0, v1))
  499. {
  500. printf ("6: FAILED!\n");
  501. print_vector ("M.y", v0);
  502. print_vector ("Q.y", v1);
  503. }
  504. v0 = limat_matrix_get_basis (m0, 2);
  505. v1 = limat_quaternion_get_basis (q0, 2);
  506. if (!check_vector (v0, v1))
  507. {
  508. printf ("7: FAILED!\n");
  509. print_vector ("M.z", v0);
  510. print_vector ("Q.z", v1);
  511. }
  512. }
  513. static void transform_look ()
  514. {
  515. LIMatMatrix m0;
  516. LIMatTransform t0;
  517. LIMatTransform t1;
  518. printf ("Testing transform look...\n");
  519. m0 = limat_matrix_look (100.0, 0.0, 0.0, 0.707, 0.0, 0.707, 0.0, 1.0, 0.0);
  520. t0 = limat_transform_look (
  521. limat_vector_init (100.0, 0.0, 0.0),
  522. limat_vector_init (0.707, 0.0, 0.707),
  523. limat_vector_init (0.0, 1.0, 0.0));
  524. t1 = limat_convert_matrix_to_transform (m0);
  525. if (!check_transform (t0, t1))
  526. {
  527. printf ("1: FAILED!\n");
  528. print_matrix ("M", m0);
  529. print_transform ("M->T", t1);
  530. print_transform ("T", t0);
  531. }
  532. }
  533. static void transform_multiply ()
  534. {
  535. LIMatMatrix m0;
  536. LIMatMatrix m1;
  537. LIMatMatrix m2;
  538. LIMatTransform t0;
  539. LIMatTransform t1;
  540. LIMatTransform t2;
  541. LIMatTransform t3;
  542. printf ("Testing transform multiplication...\n");
  543. t0 = limat_convert_quaternion_to_transform (limat_quaternion_rotation (0.5f, limat_vector_init (0.0f, 1.0f, 0.0f)));
  544. t1 = limat_convert_vector_to_transform (limat_vector_init (100.0f, 0.0f, 0.0f));
  545. t2 = limat_transform_multiply (t0, t1);
  546. m0 = limat_matrix_rotation (0.5f, 0.0f, 1.0f, 0.0f);
  547. m1 = limat_matrix_translation (100.0f, 0.0f, 0.0f);
  548. m2 = limat_matrix_multiply (m0, m1);
  549. t3 = limat_convert_matrix_to_transform (m2);
  550. if (!check_transform (t2, t3))
  551. {
  552. printf ("1: FAILED!\n");
  553. print_matrix ("M", m2);
  554. print_transform ("M->T", t3);
  555. print_transform ("T", t2);
  556. }
  557. t2 = limat_transform_multiply (t1, t2);
  558. m2 = limat_matrix_multiply (m1, m2);
  559. t3 = limat_convert_matrix_to_transform (m2);
  560. if (!check_transform (t2, t3))
  561. {
  562. printf ("2: FAILED!\n");
  563. print_matrix ("M", m2);
  564. print_transform ("M->T", t3);
  565. print_transform ("T", t2);
  566. }
  567. t0 = limat_transform_init (limat_vector_init (1.0f, 2.0f, -3.0f), limat_quaternion_init (1.0f, 0.0f, 0.0f, 0.0f));
  568. t1 = limat_transform_init (limat_vector_init (10.0f, -5.0f, 1.0f), limat_quaternion_init (0.0f, 0.0f, 1.0f, 0.0f));
  569. t2 = limat_transform_multiply (t0, t1);
  570. m0 = limat_convert_transform_to_matrix (t0);
  571. m1 = limat_convert_transform_to_matrix (t1);
  572. m2 = limat_matrix_multiply (m0, m1);
  573. t3 = limat_convert_matrix_to_transform (m2);
  574. if (!check_transform (t2, t3))
  575. {
  576. printf ("3: FAILED!\n");
  577. print_matrix ("M", m2);
  578. print_transform ("M->T", t3);
  579. print_transform ("T", t2);
  580. }
  581. t2 = limat_transform_multiply (t1, t2);
  582. m2 = limat_matrix_multiply (m1, m2);
  583. t3 = limat_convert_matrix_to_transform (m2);
  584. if (!check_transform (t2, t3))
  585. {
  586. printf ("4: FAILED!\n");
  587. print_matrix ("M", m2);
  588. print_transform ("M->T", t3);
  589. print_transform ("T", t2);
  590. }
  591. }
  592. static void transform_invert ()
  593. {
  594. LIMatMatrix m0;
  595. LIMatMatrix m1;
  596. LIMatTransform t0;
  597. LIMatTransform t1;
  598. LIMatTransform t2;
  599. printf ("Testing transform inverse...\n");
  600. t0 = limat_transform_init (limat_vector_init (10, -3, 9), limat_quaternion_init (0.5, -0.5, 0.5, -0.5));
  601. t1 = limat_transform_invert (t0);
  602. m0 = limat_convert_transform_to_matrix (t0);
  603. m1 = limat_matrix_invert (m0);
  604. t2 = limat_convert_matrix_to_transform (m1);
  605. if (!check_transform (t1, t2))
  606. {
  607. printf ("1: FAILED!\n");
  608. print_matrix ("M", m1);
  609. print_transform ("M->T", t2);
  610. print_transform ("T", t1);
  611. }
  612. t0 = limat_transform_init (limat_vector_init (-1, 7, -2), limat_quaternion_init (-1, 0, 0, 0));
  613. t1 = limat_transform_invert (t0);
  614. m0 = limat_convert_transform_to_matrix (t0);
  615. m1 = limat_matrix_invert (m0);
  616. t2 = limat_convert_matrix_to_transform (m1);
  617. if (!check_transform (t1, t2))
  618. {
  619. printf ("2: FAILED!\n");
  620. print_matrix ("M", m1);
  621. print_transform ("M->T", t2);
  622. print_transform ("T", t1);
  623. }
  624. }
  625. static void transform_vector ()
  626. {
  627. LIMatMatrix m0;
  628. LIMatTransform t0;
  629. LIMatVector v0;
  630. LIMatVector v1;
  631. LIMatVector v2;
  632. printf ("Testing vector transforming...\n");
  633. v0 = limat_vector_init (10.0f, 20.0f, 30.0f);
  634. v1 = limat_vector_normalize (limat_vector_init (1.0f, 0.5f, 0.25f));
  635. v2 = limat_vector_init (0.0f, 1.0f, 0.0f);
  636. m0 = limat_matrix_look (v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z);
  637. t0 = limat_transform_look (v0, v1, v2);
  638. v0 = limat_vector_init (-30.0f, 10.0f, -20.0f);
  639. v1 = limat_matrix_transform (m0, v0);
  640. v2 = limat_transform_transform (t0, v0);
  641. if (!check_vector (v1, v2))
  642. {
  643. printf ("1: FAILED!\n");
  644. print_matrix ("M", m0);
  645. print_transform ("T", t0);
  646. print_vector ("M*v", v0);
  647. print_vector ("T*v", v1);
  648. }
  649. v0 = limat_vector_init (1000.0f, -20.0f, 1.0f);
  650. v1 = limat_vector_normalize (limat_vector_init (0.1f, 0.1f, 0.9f));
  651. v2 = limat_vector_init (1.0f, 0.0f, 0.0f);
  652. m0 = limat_matrix_look (v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z);
  653. t0 = limat_transform_look (v0, v1, v2);
  654. v0 = limat_vector_init (1.0f, 1.0f, 1.0f);
  655. v1 = limat_matrix_transform (m0, v0);
  656. v2 = limat_transform_transform (t0, v0);
  657. if (!check_vector (v1, v2))
  658. {
  659. printf ("2: FAILED!\n");
  660. print_matrix ("M", m0);
  661. print_transform ("T", t0);
  662. print_vector ("M*v", v0);
  663. print_vector ("T*v", v1);
  664. }
  665. }
  666. static void transform_multiply_2 ()
  667. {
  668. LIMatMatrix m0;
  669. LIMatMatrix m1;
  670. LIMatMatrix m2;
  671. LIMatMatrix m3;
  672. LIMatTransform t0 = {{61.829472,20.202068,67.273712}, {-0.545886,0.190507,-0.467286,0.668849}};
  673. LIMatTransform t1 = {{0.006661,0.008117,0.009031}, {-0.707107,-0.000000,0.000000,0.707107}};
  674. LIMatTransform t2 = {{-0.006661,0.009031,-0.008117}, {0.707107,0.000000,-0.000000,0.707107}};
  675. LIMatTransform t3 = {{61.823761,20.202841,67.261116}, {0.086948,-0.195712,-0.465130,0.858948}};
  676. LIMatTransform t4;
  677. printf ("Testing transform multiplication 2...\n");
  678. m0 = limat_convert_transform_to_matrix (t0);
  679. t4 = limat_convert_matrix_to_transform (m0);
  680. if (!check_transform (t0, t4))
  681. {
  682. printf ("1: FAILED!\n");
  683. print_matrix ("M", m0);
  684. print_transform ("T", t0);
  685. print_transform ("Tm", t4);
  686. }
  687. m1 = limat_convert_transform_to_matrix (t1);
  688. t4 = limat_convert_matrix_to_transform (m1);
  689. if (!check_transform (t1, t4))
  690. {
  691. printf ("2: FAILED!\n");
  692. print_matrix ("M", m1);
  693. print_transform ("T", t1);
  694. print_transform ("Tm", t4);
  695. }
  696. m2 = limat_matrix_invert (m1);
  697. t4 = limat_convert_matrix_to_transform (m2);
  698. if (!check_transform (t2, t4))
  699. {
  700. printf ("3: FAILED!\n");
  701. print_matrix ("M", m2);
  702. print_transform ("T", t1);
  703. print_transform ("Tm", t4);
  704. }
  705. m3 = limat_matrix_multiply (m0, m2);
  706. t4 = limat_convert_matrix_to_transform (m3);
  707. if (!check_transform (t3, t4))
  708. {
  709. printf ("4: FAILED!\n");
  710. print_matrix ("M", m3);
  711. print_transform ("T", t1);
  712. print_transform ("Tm", t4);
  713. }
  714. t4 = limat_transform_multiply (t0, t2);
  715. if (!check_transform (t3, t4))
  716. {
  717. printf ("5: FAILED!\n");
  718. print_transform ("Got", t4);
  719. print_transform ("Expected", t3);
  720. }
  721. }
  722. static void vector_basics ()
  723. {
  724. LIMatVector v0;
  725. LIMatVector v1;
  726. printf ("Testing vector basics...\n");
  727. v0 = limat_vector_init (0.0f, 0.0f, 0.0f);
  728. v0 = limat_vector_normalize (v0);
  729. v1 = limat_vector_init (0.0f, 0.0f, 0.0f);
  730. if (isnan (v0.x) || isnan (v0.y) || isnan (v0.z))
  731. {
  732. printf ("1: FAILED!\n");
  733. print_vector ("Got", v0);
  734. print_vector ("Expected", v1);
  735. }
  736. }
  737. /*****************************************************************************/
  738. static void dualquat_basics ()
  739. {
  740. LIMatDualquat dq0;
  741. LIMatDualquat dq1;
  742. LIMatVector v0;
  743. LIMatVector v1;
  744. LIMatVector v2;
  745. LIMatQuaternion q0;
  746. printf ("Testing dual quaternion basics...\n");
  747. /* Multiplication. */
  748. v0 = limat_vector_init (-10.0f, 20.0f, 30.0f);
  749. q0 = limat_quaternion_init (0.0f, 1.0f, 0.0f, 0.0f);
  750. dq0 = limat_dualquat_init (v0, q0);
  751. dq1 = limat_dualquat_multiply (
  752. limat_dualquat_init_translation (v0),
  753. limat_dualquat_init_rotation (q0));
  754. if (!check_quaternion (dq0.r, dq1.r) ||
  755. !check_quaternion (dq0.d, dq1.d))
  756. {
  757. printf ("1: FAILED!\n");
  758. print_dualquat ("Got", dq0);
  759. print_dualquat ("Expected", dq1);
  760. }
  761. /* Transforming vectors. */
  762. v0 = limat_vector_init (10.0f, 20.0f, 30.0f);
  763. dq0 = limat_dualquat_init_translation (v0);
  764. v1 = limat_dualquat_transform (dq0, limat_vector_init (3.0f, 2.0f, 1.0f));
  765. v2 = limat_vector_init (13.0f, 22.0f, 31.0f);
  766. if (!check_vector (v1, v2))
  767. {
  768. printf ("2: FAILED!\n");
  769. print_dualquat ("DQ", dq0);
  770. print_vector ("Got", v0);
  771. print_vector ("Expected", v1);
  772. }
  773. }
  774. void limat_math_unittest ()
  775. {
  776. convert_quaternion_matrix ();
  777. convert_transform_matrix ();
  778. matrix_basics ();
  779. matrix_basis ();
  780. matrix_look ();
  781. matrix_perspective ();
  782. quaternion_basics ();
  783. quaternion_rotation ();
  784. quaternion_multiply ();
  785. quaternion_look ();
  786. quaternion_basis ();
  787. transform_multiply ();
  788. transform_multiply_2 ();
  789. transform_invert ();
  790. transform_look ();
  791. transform_vector ();
  792. vector_basics ();
  793. dualquat_basics ();
  794. }