testQuaternion.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. // Copyright (C) 2008-2012 Colin MacDonald
  2. // No rights reserved: this software is in the public domain.
  3. #include "testUtils.h"
  4. using namespace irr;
  5. namespace
  6. {
  7. inline bool compareQ(const core::vector3df& v, const core::vector3df& turn=core::vector3df(0,0,1))
  8. {
  9. core::quaternion q(v*core::DEGTORAD);
  10. core::vector3df v2;
  11. const core::vector3df v3=v.rotationToDirection(turn);
  12. if (!v3.equals(q*turn, 0.002f))
  13. {
  14. logTestString("Inequality before quat.toEuler(): %f,%f,%f\n", v.X,v.Y,v.Z);
  15. return false;
  16. }
  17. q.toEuler(v2);
  18. v2*=core::RADTODEG;
  19. v2=v2.rotationToDirection(turn);
  20. // this yields pretty far values sometimes, so don't be too picky
  21. if (!v3.equals(v2, 0.0035f))
  22. {
  23. logTestString("Inequality: %f,%f,%f != %f,%f,%f\n", v.X,v.Y,v.Z, v2.X,v2.Y,v2.Z);
  24. return false;
  25. }
  26. return true;
  27. }
  28. const core::vector3df vals[] = {
  29. core::vector3df(0.f, 0.f, 0.f),
  30. core::vector3df(0.f, 0.f, 24.04f),
  31. core::vector3df(0.f, 0.f, 71.f),
  32. core::vector3df(0.f, 0.f, 71.19f),
  33. core::vector3df(0.f, 0.f, 80.f),
  34. core::vector3df(0.f, 0.f, 103.99f),
  35. core::vector3df(0.f, 0.f, 261.73f),
  36. core::vector3df(0.f, 0.f, 276.f),
  37. core::vector3df(0.f, 0.f, 286.29f),
  38. core::vector3df(0.f, 0.f, 295.f),
  39. core::vector3df(0.f, 0.f, 318.3f),
  40. core::vector3df(360.f, 75.55f, 155.89f),
  41. core::vector3df(0.f, 90.f, 159.51f),
  42. core::vector3df(0.f, 90.f, 249.48f),
  43. core::vector3df(0.f, 90.f, 269.91f),
  44. core::vector3df(0.f, 90.f, 270.f),
  45. core::vector3df(0.f, 284.45f, 155.89f),
  46. core::vector3df(0.01f, 0.42f, 90.38f),
  47. core::vector3df(0.04f, 359.99f, 9.5f),
  48. core::vector3df(0.34f, 89.58f, 360.f),
  49. core::vector3df(0.58f, 4.36f, 334.36f),
  50. core::vector3df(3.23f, 359.65f, 10.17f),
  51. core::vector3df(3.23f, 359.65f, 10.21f),
  52. core::vector3df(4.85f, 359.3f, 94.33f),
  53. core::vector3df(8.90f, 6.63f, 9.27f),
  54. core::vector3df(11.64f, 311.52f, 345.35f),
  55. core::vector3df(12.1f, 4.72f, 11.24f),
  56. core::vector3df(14.63f, 48.72f, 31.79f),
  57. core::vector3df(76.68f, 1.11f, 18.65f),
  58. core::vector3df(90.f, 0.f, 0.f),
  59. core::vector3df(90.01f, 270.49f, 360.f),
  60. core::vector3df(90.95f, 0.f, 0.f),
  61. core::vector3df(173.58f, 348.13f, 132.25f),
  62. core::vector3df(115.52f, 89.04f, 205.51f),
  63. core::vector3df(179.3f, 359.18f, 0.58f),
  64. core::vector3df(180.09f, 270.06f, 0.f),
  65. core::vector3df(180.41f, 359.94f, 179.69f),
  66. core::vector3df(180.92f, 10.79f, 144.53f),
  67. core::vector3df(181.95f, 270.03f, 0.f),
  68. core::vector3df(269.05f, 0.f, 0.f),
  69. core::vector3df(269.99f, 270.49f, 360.f),
  70. core::vector3df(283.32f, 358.89f, 18.65f),
  71. core::vector3df(347.9f, 355.28f, 11.24f),
  72. core::vector3df(351.1f, 353.37f, 9.27f),
  73. core::vector3df(355.82f, 345.96f, 273.26f),
  74. core::vector3df(358.24f, 358.07f, 342.82f),
  75. core::vector3df(359.78f, 357.69f, 7.52f),
  76. core::vector3df(359.96f, 0.01f, 9.5f),
  77. core::vector3df(-57.197479f,-90.f,0.f),
  78. core::vector3df(-57.187481f,-90.f,0.f)
  79. };
  80. bool testQuatEulerMatrix()
  81. {
  82. // Test fromAngleAxis
  83. core::vector3df v4;
  84. core::quaternion q1;
  85. f32 angle = 60.f;
  86. q1.fromAngleAxis(angle*core::DEGTORAD, core::vector3df(1, 0, 0));
  87. q1.toEuler(v4);
  88. bool result = v4.equals(core::vector3df(angle*core::DEGTORAD,0,0));
  89. // Test maxtrix constructor
  90. core::vector3df v5;
  91. core::matrix4 mx4;
  92. mx4.setRotationDegrees(core::vector3df(angle,0,0));
  93. core::quaternion q2(mx4);
  94. q2.toEuler(v5);
  95. result &= q1.equals(q2);
  96. result &= v4.equals(v5);
  97. // Test matrix conversion via getMatrix
  98. core::matrix4 mat;
  99. mat.setRotationDegrees(core::vector3df(angle,0,0));
  100. core::vector3df v6 = mat.getRotationDegrees()*core::DEGTORAD;
  101. // make sure comparison matrix is correct
  102. result &= v4.equals(v6);
  103. core::matrix4 mat2 = q1.getMatrix();
  104. result &= mat.equals(mat2, 0.0005f);
  105. // test for proper handedness
  106. angle=90;
  107. q1.fromAngleAxis(angle*core::DEGTORAD, core::vector3df(0,0,1));
  108. // check we have the correct quat
  109. result &= q1.equals(core::quaternion(0,0,sqrtf(2)/2,sqrtf(2)/2));
  110. q1.toEuler(v4);
  111. // and the correct rotation vector
  112. result &= v4.equals(core::vector3df(0,0,90*core::DEGTORAD));
  113. mat.setRotationRadians(v4);
  114. mat2=q1.getMatrix();
  115. // check matrix
  116. result &= mat.equals(mat2, 0.0005f);
  117. // and to be absolutely sure, check rotation results
  118. v5.set(1,0,0);
  119. mat.transformVect(v5);
  120. v6.set(1,0,0);
  121. mat2.transformVect(v6);
  122. result &= v5.equals(v6);
  123. return result;
  124. }
  125. bool testEulerConversion()
  126. {
  127. bool result = true;
  128. for (u32 i=0; i<sizeof(vals)/sizeof(vals[0]); ++i)
  129. {
  130. // make sure the rotations work with different turn vectors
  131. result &= compareQ(vals[i]) && compareQ(vals[i], core::vector3df(1,2,3)) &&
  132. compareQ(vals[i], core::vector3df(0,1,0));
  133. }
  134. result &= testQuatEulerMatrix();
  135. return result;
  136. }
  137. bool testRotationFromTo()
  138. {
  139. bool result = true;
  140. core::quaternion q;
  141. q.rotationFromTo(core::vector3df(1.f,0.f,0.f), core::vector3df(1.f,0.f,0.f));
  142. if (q != core::quaternion())
  143. {
  144. logTestString("Quaternion rotationFromTo method did not yield identity.\n");
  145. result = false;
  146. }
  147. core::vector3df from(1.f,0.f,0.f);
  148. q.rotationFromTo(from, core::vector3df(-1.f,0.f,0.f));
  149. from=q*from;
  150. if (from != core::vector3df(-1.f,0.f,0.f))
  151. {
  152. logTestString("Quaternion rotationFromTo method did not yield x flip.\n");
  153. result = false;
  154. }
  155. from.set(1.f,2.f,3.f);
  156. q.rotationFromTo(from, core::vector3df(-1.f,-2.f,-3.f));
  157. from=q*from;
  158. if (from != core::vector3df(-1.f,-2.f,-3.f))
  159. {
  160. logTestString("Quaternion rotationFromTo method did not yield x flip for non-axis.\n");
  161. result = false;
  162. }
  163. from.set(1.f,0.f,0.f);
  164. q.rotationFromTo(from, core::vector3df(0.f,1.f,0.f));
  165. from=q*from;
  166. if (from != core::vector3df(0.f,1.f,0.f))
  167. {
  168. logTestString("Quaternion rotationFromTo method did not yield 90 degree rotation.\n");
  169. result = false;
  170. }
  171. for (u32 i=1; i<sizeof(vals)/sizeof(vals[0])-1; ++i)
  172. {
  173. from.set(vals[i]).normalize();
  174. core::vector3df to(vals[i+1]);
  175. to.normalize();
  176. q.rotationFromTo(from, to);
  177. from = q*from;
  178. result &= (from.equals(to, 0.00012f));
  179. }
  180. return result;
  181. }
  182. bool testInterpolation()
  183. {
  184. bool result=true;
  185. core::quaternion q(1.f,2.f,3.f,4.f);
  186. core::quaternion q2;
  187. q2.lerp(q,q,0);
  188. if (q != q2)
  189. {
  190. logTestString("Quaternion lerp with same quaternion did not yield same quaternion back (with t==0).\n");
  191. result = false;
  192. }
  193. q2.lerp(q,q,0.5f);
  194. if (q != q2)
  195. {
  196. logTestString("Quaternion lerp with same quaternion did not yield same quaternion back (with t==0.5).\n");
  197. result = false;
  198. }
  199. q2.lerp(q,q,1);
  200. if (q != q2)
  201. {
  202. logTestString("Quaternion lerp with same quaternion did not yield same quaternion back (with t==1).\n");
  203. result = false;
  204. }
  205. q2.lerp(q,q,0.2345f);
  206. if (q != q2)
  207. {
  208. logTestString("Quaternion lerp with same quaternion did not yield same quaternion back (with t==0.2345).\n");
  209. result = false;
  210. }
  211. q2.slerp(q,q,0);
  212. if (q != q2)
  213. {
  214. logTestString("Quaternion slerp with same quaternion did not yield same quaternion back (with t==0).\n");
  215. result = false;
  216. }
  217. q2.slerp(q,q,0.5f);
  218. if (q != q2)
  219. {
  220. logTestString("Quaternion slerp with same quaternion did not yield same quaternion back (with t==0.5).\n");
  221. result = false;
  222. }
  223. q2.slerp(q,q,1);
  224. if (q != q2)
  225. {
  226. logTestString("Quaternion slerp with same quaternion did not yield same quaternion back (with t==1).\n");
  227. result = false;
  228. }
  229. q2.slerp(q,q,0.2345f);
  230. if (q != q2)
  231. {
  232. logTestString("Quaternion slerp with same quaternion did not yield same quaternion back (with t==0.2345).\n");
  233. result = false;
  234. }
  235. core::quaternion q3(core::vector3df(45,135,85)*core::DEGTORAD);
  236. q.set(core::vector3df(35,125,75)*core::DEGTORAD);
  237. q2.slerp(q,q3,0);
  238. if (q != q2)
  239. {
  240. logTestString("Quaternion slerp with different quaternions did not yield first quaternion back (with t==0).\n");
  241. result = false;
  242. }
  243. q2.slerp(q,q3,1);
  244. if (q3 != q2)
  245. {
  246. logTestString("Quaternion slerp with different quaternions did not yield second quaternion back (with t==1).\n");
  247. result = false;
  248. }
  249. q2.slerp(q,q3,0.5);
  250. if (!q2.equals(core::quaternion(-0.437f,0.742f,0.017f,0.506f),0.001f))
  251. {
  252. logTestString("Quaternion slerp with different quaternions did not yield correct result (with t==0.5).\n");
  253. result = false;
  254. }
  255. q2.slerp(q,q3,0.2345f);
  256. if (!q2.equals(core::quaternion(-0.4202f,0.7499f,0.03814f,0.5093f),0.0007f))
  257. {
  258. logTestString("Quaternion slerp with different quaternions did not yield correct result (with t==0.2345).\n");
  259. result = false;
  260. }
  261. return result;
  262. }
  263. }
  264. bool testQuaternion(void)
  265. {
  266. bool result = true;
  267. core::quaternion q1;
  268. if ((q1.W != 1.f)||(q1.X != 0.f)||(q1.Y != 0.f)||(q1.Z != 0.f))
  269. {
  270. logTestString("Default constructor did not create proper quaternion.\n");
  271. result = false;
  272. }
  273. core::quaternion q2(1.f,2.f,3.f,4.f);
  274. if ((q2.W != 4.f)||(q2.X != 1.f)||(q2.Y != 2.f)||(q2.Z != 3.f))
  275. {
  276. logTestString("Element constructor did not create proper quaternion.\n");
  277. result = false;
  278. }
  279. q2.set(4.f,3.f,2.f,1.f);
  280. if ((q2.W != 1.f)||(q2.X != 4.f)||(q2.Y != 3.f)||(q2.Z != 2.f))
  281. {
  282. logTestString("Quaternion set method not working(1).\n");
  283. result = false;
  284. }
  285. q2.set(0.f,0.f,0.f,1.f);
  286. if ((q2.W != 1.f)||(q2.X != 0.f)||(q2.Y != 0.f)||(q2.Z != 0.f))
  287. {
  288. logTestString("Quaternion set method not working(2).\n");
  289. result = false;
  290. }
  291. if (q1 != q2)
  292. {
  293. logTestString("Quaternion equals method not working.\n");
  294. result = false;
  295. }
  296. result &= testRotationFromTo();
  297. result &= testInterpolation();
  298. result &= testEulerConversion();
  299. return result;
  300. }