Euler.tests.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /**
  2. * @author bhouston / http://exocortex.com
  3. * @author TristanVALCKE / https://github.com/Itee
  4. */
  5. /* global QUnit */
  6. import { Euler } from '../../../../src/math/Euler';
  7. import { Matrix4 } from '../../../../src/math/Matrix4';
  8. import { Quaternion } from '../../../../src/math/Quaternion';
  9. import { Vector3 } from '../../../../src/math/Vector3';
  10. import { x, y, z } from './Constants.tests';
  11. const eulerZero = new Euler( 0, 0, 0, "XYZ" );
  12. const eulerAxyz = new Euler( 1, 0, 0, "XYZ" );
  13. const eulerAzyx = new Euler( 0, 1, 0, "ZYX" );
  14. function matrixEquals4( a, b, tolerance ) {
  15. tolerance = tolerance || 0.0001;
  16. if ( a.elements.length != b.elements.length ) {
  17. return false;
  18. }
  19. for ( var i = 0, il = a.elements.length; i < il; i ++ ) {
  20. var delta = a.elements[ i ] - b.elements[ i ];
  21. if ( delta > tolerance ) {
  22. return false;
  23. }
  24. }
  25. return true;
  26. }
  27. function eulerEquals( a, b, tolerance ) {
  28. tolerance = tolerance || 0.0001;
  29. var diff = Math.abs( a.x - b.x ) + Math.abs( a.y - b.y ) + Math.abs( a.z - b.z );
  30. return ( diff < tolerance );
  31. }
  32. function quatEquals( a, b, tolerance ) {
  33. tolerance = tolerance || 0.0001;
  34. var diff = Math.abs( a.x - b.x ) + Math.abs( a.y - b.y ) + Math.abs( a.z - b.z ) + Math.abs( a.w - b.w );
  35. return ( diff < tolerance );
  36. }
  37. export default QUnit.module( 'Maths', () => {
  38. QUnit.module( 'Euler', () => {
  39. // INSTANCING
  40. QUnit.test( "Instancing", ( assert ) => {
  41. var a = new Euler();
  42. assert.ok( a.equals( eulerZero ), "Passed!" );
  43. assert.ok( ! a.equals( eulerAxyz ), "Passed!" );
  44. assert.ok( ! a.equals( eulerAzyx ), "Passed!" );
  45. } );
  46. // STATIC STUFF
  47. QUnit.test( "RotationOrders", ( assert ) => {
  48. assert.ok( Array.isArray( Euler.RotationOrders ), "Passed!" );
  49. assert.deepEqual( Euler.RotationOrders, [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ], "Passed!" );
  50. } );
  51. QUnit.test( "DefaultOrder", ( assert ) => {
  52. assert.equal( Euler.DefaultOrder, "XYZ", "Passed!" );
  53. } );
  54. // PROPERTIES STUFF
  55. QUnit.test( "x", ( assert ) => {
  56. var a = new Euler();
  57. assert.ok( a.x === 0, "Passed!" );
  58. a = new Euler( 1, 2, 3 );
  59. assert.ok( a.x === 1, "Passed!" );
  60. a = new Euler( 4, 5, 6, "XYZ" );
  61. assert.ok( a.x === 4, "Passed!" );
  62. a = new Euler( 7, 8, 9, "XYZ" );
  63. a.x = 10;
  64. assert.ok( a.x === 10, "Passed!" );
  65. a = new Euler( 11, 12, 13, "XYZ" );
  66. var b = false;
  67. a._onChange( function () {
  68. b = true;
  69. } );
  70. a.x = 14;
  71. assert.ok( b, "Passed!" );
  72. assert.ok( a.x === 14, "Passed!" );
  73. } );
  74. QUnit.test( "y", ( assert ) => {
  75. var a = new Euler();
  76. assert.ok( a.y === 0, "Passed!" );
  77. a = new Euler( 1, 2, 3 );
  78. assert.ok( a.y === 2, "Passed!" );
  79. a = new Euler( 4, 5, 6, "XYZ" );
  80. assert.ok( a.y === 5, "Passed!" );
  81. a = new Euler( 7, 8, 9, "XYZ" );
  82. a.y = 10;
  83. assert.ok( a.y === 10, "Passed!" );
  84. a = new Euler( 11, 12, 13, "XYZ" );
  85. var b = false;
  86. a._onChange( function () {
  87. b = true;
  88. } );
  89. a.y = 14;
  90. assert.ok( b, "Passed!" );
  91. assert.ok( a.y === 14, "Passed!" );
  92. } );
  93. QUnit.test( "z", ( assert ) => {
  94. var a = new Euler();
  95. assert.ok( a.z === 0, "Passed!" );
  96. a = new Euler( 1, 2, 3 );
  97. assert.ok( a.z === 3, "Passed!" );
  98. a = new Euler( 4, 5, 6, "XYZ" );
  99. assert.ok( a.z === 6, "Passed!" );
  100. a = new Euler( 7, 8, 9, "XYZ" );
  101. a.z = 10;
  102. assert.ok( a.z === 10, "Passed!" );
  103. a = new Euler( 11, 12, 13, "XYZ" );
  104. var b = false;
  105. a._onChange( function () {
  106. b = true;
  107. } );
  108. a.z = 14;
  109. assert.ok( b, "Passed!" );
  110. assert.ok( a.z === 14, "Passed!" );
  111. } );
  112. QUnit.test( "order", ( assert ) => {
  113. var a = new Euler();
  114. assert.ok( a.order === Euler.DefaultOrder, "Passed!" );
  115. a = new Euler( 1, 2, 3 );
  116. assert.ok( a.order === Euler.DefaultOrder, "Passed!" );
  117. a = new Euler( 4, 5, 6, "YZX" );
  118. assert.ok( a.order === "YZX", "Passed!" );
  119. a = new Euler( 7, 8, 9, "YZX" );
  120. a.order = "ZXY";
  121. assert.ok( a.order === "ZXY", "Passed!" );
  122. a = new Euler( 11, 12, 13, "YZX" );
  123. var b = false;
  124. a._onChange( function () {
  125. b = true;
  126. } );
  127. a.order = "ZXY";
  128. assert.ok( b, "Passed!" );
  129. assert.ok( a.order === "ZXY", "Passed!" );
  130. } );
  131. // PUBLIC STUFF
  132. QUnit.test( "isEuler", ( assert ) => {
  133. var a = new Euler();
  134. assert.ok( a.isEuler, "Passed!" );
  135. var b = new Vector3();
  136. assert.ok( ! b.isEuler, "Passed!" );
  137. } );
  138. QUnit.test( "set/setFromVector3/toVector3", ( assert ) => {
  139. var a = new Euler();
  140. a.set( 0, 1, 0, "ZYX" );
  141. assert.ok( a.equals( eulerAzyx ), "Passed!" );
  142. assert.ok( ! a.equals( eulerAxyz ), "Passed!" );
  143. assert.ok( ! a.equals( eulerZero ), "Passed!" );
  144. var vec = new Vector3( 0, 1, 0 );
  145. var b = new Euler().setFromVector3( vec, "ZYX" );
  146. assert.ok( a.equals( b ), "Passed!" );
  147. var c = b.toVector3();
  148. assert.ok( c.equals( vec ), "Passed!" );
  149. } );
  150. QUnit.test( "clone/copy/equals", ( assert ) => {
  151. var a = eulerAxyz.clone();
  152. assert.ok( a.equals( eulerAxyz ), "Passed!" );
  153. assert.ok( ! a.equals( eulerZero ), "Passed!" );
  154. assert.ok( ! a.equals( eulerAzyx ), "Passed!" );
  155. a.copy( eulerAzyx );
  156. assert.ok( a.equals( eulerAzyx ), "Passed!" );
  157. assert.ok( ! a.equals( eulerAxyz ), "Passed!" );
  158. assert.ok( ! a.equals( eulerZero ), "Passed!" );
  159. } );
  160. QUnit.test( "Quaternion.setFromEuler/Euler.fromQuaternion", ( assert ) => {
  161. var testValues = [ eulerZero, eulerAxyz, eulerAzyx ];
  162. for ( var i = 0; i < testValues.length; i ++ ) {
  163. var v = testValues[ i ];
  164. var q = new Quaternion().setFromEuler( v );
  165. var v2 = new Euler().setFromQuaternion( q, v.order );
  166. var q2 = new Quaternion().setFromEuler( v2 );
  167. assert.ok( quatEquals( q, q2 ), "Passed!" );
  168. }
  169. } );
  170. QUnit.test( "Matrix4.setFromEuler/Euler.fromRotationMatrix", ( assert ) => {
  171. var testValues = [ eulerZero, eulerAxyz, eulerAzyx ];
  172. for ( var i = 0; i < testValues.length; i ++ ) {
  173. var v = testValues[ i ];
  174. var m = new Matrix4().makeRotationFromEuler( v );
  175. var v2 = new Euler().setFromRotationMatrix( m, v.order );
  176. var m2 = new Matrix4().makeRotationFromEuler( v2 );
  177. assert.ok( matrixEquals4( m, m2, 0.0001 ), "Passed!" );
  178. }
  179. } );
  180. QUnit.test( "reorder", ( assert ) => {
  181. var testValues = [ eulerZero, eulerAxyz, eulerAzyx ];
  182. for ( var i = 0; i < testValues.length; i ++ ) {
  183. var v = testValues[ i ];
  184. var q = new Quaternion().setFromEuler( v );
  185. v.reorder( 'YZX' );
  186. var q2 = new Quaternion().setFromEuler( v );
  187. assert.ok( quatEquals( q, q2 ), "Passed!" );
  188. v.reorder( 'ZXY' );
  189. var q3 = new Quaternion().setFromEuler( v );
  190. assert.ok( quatEquals( q, q3 ), "Passed!" );
  191. }
  192. } );
  193. QUnit.test( "set/get properties, check callbacks", ( assert ) => {
  194. var a = new Euler();
  195. a._onChange( function () {
  196. assert.step( "set: onChange called" );
  197. } );
  198. a.x = 1;
  199. a.y = 2;
  200. a.z = 3;
  201. a.order = "ZYX";
  202. assert.strictEqual( a.x, 1, "get: check x" );
  203. assert.strictEqual( a.y, 2, "get: check y" );
  204. assert.strictEqual( a.z, 3, "get: check z" );
  205. assert.strictEqual( a.order, "ZYX", "get: check order" );
  206. assert.verifySteps( Array( 4 ).fill( "set: onChange called" ) );
  207. } );
  208. QUnit.test( "clone/copy, check callbacks", ( assert ) => {
  209. var a = new Euler( 1, 2, 3, "ZXY" );
  210. var b = new Euler( 4, 5, 6, "XZY" );
  211. var cbSucceed = function () {
  212. assert.ok( true );
  213. assert.step( "onChange called" );
  214. };
  215. var cbFail = function () {
  216. assert.ok( false );
  217. };
  218. a._onChange( cbFail );
  219. b._onChange( cbFail );
  220. // clone doesn't trigger onChange
  221. a = b.clone();
  222. assert.ok( a.equals( b ), "clone: check if a equals b" );
  223. // copy triggers onChange once
  224. a = new Euler( 1, 2, 3, "ZXY" );
  225. a._onChange( cbSucceed );
  226. a.copy( b );
  227. assert.ok( a.equals( b ), "copy: check if a equals b" );
  228. assert.verifySteps( [ "onChange called" ] );
  229. } );
  230. QUnit.test( "toArray", ( assert ) => {
  231. var order = "YXZ";
  232. var a = new Euler( x, y, z, order );
  233. var array = a.toArray();
  234. assert.strictEqual( array[ 0 ], x, "No array, no offset: check x" );
  235. assert.strictEqual( array[ 1 ], y, "No array, no offset: check y" );
  236. assert.strictEqual( array[ 2 ], z, "No array, no offset: check z" );
  237. assert.strictEqual( array[ 3 ], order, "No array, no offset: check order" );
  238. var array = [];
  239. a.toArray( array );
  240. assert.strictEqual( array[ 0 ], x, "With array, no offset: check x" );
  241. assert.strictEqual( array[ 1 ], y, "With array, no offset: check y" );
  242. assert.strictEqual( array[ 2 ], z, "With array, no offset: check z" );
  243. assert.strictEqual( array[ 3 ], order, "With array, no offset: check order" );
  244. var array = [];
  245. a.toArray( array, 1 );
  246. assert.strictEqual( array[ 0 ], undefined, "With array and offset: check [0]" );
  247. assert.strictEqual( array[ 1 ], x, "With array and offset: check x" );
  248. assert.strictEqual( array[ 2 ], y, "With array and offset: check y" );
  249. assert.strictEqual( array[ 3 ], z, "With array and offset: check z" );
  250. assert.strictEqual( array[ 4 ], order, "With array and offset: check order" );
  251. } );
  252. QUnit.test( "fromArray", ( assert ) => {
  253. var a = new Euler();
  254. var array = [ x, y, z ];
  255. var cb = function () {
  256. assert.step( "onChange called" );
  257. };
  258. a._onChange( cb );
  259. a.fromArray( array );
  260. assert.strictEqual( a.x, x, "No order: check x" );
  261. assert.strictEqual( a.y, y, "No order: check y" );
  262. assert.strictEqual( a.z, z, "No order: check z" );
  263. assert.strictEqual( a.order, "XYZ", "No order: check order" );
  264. a = new Euler();
  265. array = [ x, y, z, "ZXY" ];
  266. a._onChange( cb );
  267. a.fromArray( array );
  268. assert.strictEqual( a.x, x, "With order: check x" );
  269. assert.strictEqual( a.y, y, "With order: check y" );
  270. assert.strictEqual( a.z, z, "With order: check z" );
  271. assert.strictEqual( a.order, "ZXY", "With order: check order" );
  272. assert.verifySteps( Array( 2 ).fill( "onChange called" ) );
  273. } );
  274. QUnit.test( "_onChange", ( assert ) => {
  275. var f = function () {
  276. var b = true;
  277. };
  278. var a = new Euler( 11, 12, 13, "XYZ" );
  279. a._onChange( f );
  280. assert.ok( a._onChangeCallback === f, "Passed!" );
  281. } );
  282. QUnit.test( "_onChangeCallback", ( assert ) => {
  283. var f = function () {
  284. var b = true;
  285. };
  286. var a = new Euler( 11, 12, 13, "XYZ" );
  287. a._onChangeCallback = f;
  288. assert.ok( a._onChangeCallback === f, "Passed!" );
  289. } );
  290. // OTHERS
  291. QUnit.test( "gimbalLocalQuat", ( assert ) => {
  292. // known problematic quaternions
  293. var q1 = new Quaternion( 0.5207769385244341, - 0.4783214164122354, 0.520776938524434, 0.47832141641223547 );
  294. var q2 = new Quaternion( 0.11284905712620674, 0.6980437630368944, - 0.11284905712620674, 0.6980437630368944 );
  295. var eulerOrder = "ZYX";
  296. // create Euler directly from a Quaternion
  297. var eViaQ1 = new Euler().setFromQuaternion( q1, eulerOrder ); // there is likely a bug here
  298. // create Euler from Quaternion via an intermediate Matrix4
  299. var mViaQ1 = new Matrix4().makeRotationFromQuaternion( q1 );
  300. var eViaMViaQ1 = new Euler().setFromRotationMatrix( mViaQ1, eulerOrder );
  301. // the results here are different
  302. assert.ok( eulerEquals( eViaQ1, eViaMViaQ1 ), "Passed!" ); // this result is correct
  303. } );
  304. } );
  305. } );