Dali 3D User Interface Engine
utc-Dali-Quaternion.cpp
Go to the documentation of this file.
1 /*
2  * Copyright ( c ) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 ( the "License" );
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 #include <iostream>
19 #include <sstream>
20 
21 #include <stdlib.h>
23 #include <dali-test-suite-utils.h>
24 
25 using namespace Dali;
26 
27 
29 {
31 }
32 
34 {
36 }
37 
38 
40 {
41  Quaternion q;
46  END_TEST;
47 }
48 
50 {
51  Quaternion q( 1.0f, 0.1f, 0.2f, 0.3f );
52 
57  END_TEST;
58 }
59 
61 {
62  Quaternion q( Vector4( 1.0f, 0.1f, 0.2f, 0.3f ) );
63 
68  END_TEST;
69 }
70 
72 {
73  Quaternion q( Dali::ANGLE_90, Vector3( 1.0f, 2.0f, 3.0f ) );
74 
75  // This will be normalised:
76  DALI_TEST_EQUALS( q.AsVector().w, 0.707f, 0.001, TEST_LOCATION );
77  DALI_TEST_EQUALS( q.AsVector().x, 0.189f, 0.001, TEST_LOCATION );
78  DALI_TEST_EQUALS( q.AsVector().y, 0.378f, 0.001, TEST_LOCATION );
79  DALI_TEST_EQUALS( q.AsVector().z, 0.567f, 0.001, TEST_LOCATION );
80  END_TEST;
81 }
82 
84 {
85  Quaternion q1(0.924f, 0.383f, 0.0f, 0.0f);
86  Vector4 r1(Radian(Degree(45)), 0.0f, 0.0f, 0.0f);
87 
88  Quaternion q2(0.793f, 0.0f, 0.609f, 0.0f);
89  Vector4 r2(0.0f, Radian(Degree(75)), 0.0f, 0.0f);
90 
91  Quaternion q3(0.383f, 0.0f, 0.0f, 0.924f);
92  Vector4 r3(0.0f, 0.0f, Radian(Degree(135)), 0.0f);
93 
94  Quaternion q4(0.795f, 0.478f, 0.374f, 0.006f);
95  Vector4 r4(Radian(Degree(71)), Radian(Degree(36)), Radian(Degree(27)), 0.0f);
96 
97  Quaternion q5( -0.149f, -0.697f, 0.145f, -0.686f);
98  Vector4 r5(Radian(Degree(148.0)), Radian(Degree(-88.2)), Radian(Degree(8.0)), 0.0f);
99 
100  DALI_TEST_EQUALS(q1.EulerAngles(), r1, 0.001, TEST_LOCATION);
101  DALI_TEST_EQUALS(q2.EulerAngles(), r2, 0.001, TEST_LOCATION);
102  DALI_TEST_EQUALS(q3.EulerAngles(), r3, 0.001, TEST_LOCATION);
103  DALI_TEST_EQUALS(q4.EulerAngles(), r4, 0.01, TEST_LOCATION);
104  DALI_TEST_EQUALS(q5.EulerAngles(), r5, 0.01, TEST_LOCATION);
105  END_TEST;
106 }
107 
109 {
110  // angle: 60 deg, axis: [1,2,3]
111  float Mref_raw[16] = { 0.535714f, 0.765794f, -0.355767f, 0.0f,
112  -0.622936f, 0.642857f, 0.445741f, 0.0f,
113  0.570053f, -0.0171693f, 0.821429f, 0.0f,
114  0.0f, 0.0f, 0.0f, 1.0f};
115  Matrix Mref( Mref_raw );
116 
117  Quaternion q1( Radian(M_PI/3.0f), Vector3( 1.0f, 2.0f, 3.0f ) );
118  Quaternion q2( Mref );
119 
120  DALI_TEST_EQUALS( q1, q2, 0.001, TEST_LOCATION );
121  END_TEST;
122 }
123 
125 {
126  // IDENTITY rotation
127  Quaternion q;
128 
129  Matrix m( q ); // Convert to matrix
130 
131  Quaternion q2( m ); // and back to a quaternion
132 
133  DALI_TEST_EQUALS( q, q2, 0.001, TEST_LOCATION );
135  END_TEST;
136 }
137 
139 {
140  // Create an arbitrary forward vector
141  for( float x=-1.0f; x<=1.0f; x+=0.1f )
142  {
143  for( float y=-1.0f; y<1.0f; y+=0.1f )
144  {
145  for( float z=-1.0f; z<1.0f; z+=0.1f )
146  {
147  Vector3 vForward( x, y, z );
148  vForward.Normalize();
149 
150  // Construct an up vector from a sideways move
151  Vector3 vSide;
152  Vector3 vUp = vForward.Cross( Vector3( vForward.x+1.0f, vForward.y, vForward.z ) );
153  if( vUp.Length() > 0.01 )
154  {
155  vUp.Normalize();
156  vSide = vUp.Cross( vForward );
157  vSide.Normalize();
158  }
159  else
160  {
161  vSide = vForward.Cross( Vector3( vForward.x, vForward.y+1.0f, vForward.z ) );
162  vSide.Normalize();
163  vUp = vForward.Cross( vSide );
164  vUp.Normalize();
165  }
166 
167  // Generate a matrix, and then a quaternion from it
168  Matrix rotMatrix( Matrix::IDENTITY );
169  rotMatrix.SetXAxis( vSide );
170  rotMatrix.SetYAxis( vUp );
171  rotMatrix.SetZAxis( vForward );
172  Quaternion q( rotMatrix );
173 
174  // Generate a matrix from the quaternion, check they are the same
175  Matrix resultMatrix( q );
176  DALI_TEST_EQUALS( resultMatrix, rotMatrix, 0.001f, TEST_LOCATION );
177 
178  // Rotate an arbitrary vector by both quaternion and rotation matrix,
179  // check the result is the same
180 
181  Vector4 aVector( -2.983f, -3.213f, 8.2239f, 1.0f );
182  Vector3 aVectorRotatedByQ = q.Rotate( Vector3( aVector ) );
183  Vector4 aVectorRotatedByR = rotMatrix*aVector;
184  DALI_TEST_EQUALS( aVectorRotatedByQ, Vector3( aVectorRotatedByR ), 0.001f, TEST_LOCATION );
185  }
186  }
187  }
188  END_TEST;
189 }
190 
192 {
193  // angle: 60 deg, axis: [1,2,3]
194  float Mref_raw[16] = { 0.535714f, 0.765794f, -0.355767f, 0.0f,
195  -0.622936f, 0.642857f, 0.445741f, 0.0f,
196  0.570053f, -0.0171693f, 0.821429f, 0.0f,
197  0.0f, 0.0f, 0.0f, 1.0f};
198  Matrix Mref( Mref_raw );
199 
200  Quaternion q1( Radian(M_PI/3.0f), Vector3( 1.0f, 2.0f, 3.0f ) );
201  Quaternion q2( Mref.GetXAxis(), Mref.GetYAxis(), Mref.GetZAxis() );
202 
203  DALI_TEST_EQUALS( q1, q2, 0.001, TEST_LOCATION );
204  END_TEST;
205 }
206 
208 {
209  Vector3 xAxis( Vector3::XAXIS );
210  Vector3 yAxis( Vector3::YAXIS );
211  Vector3 zAxis( Vector3::ZAXIS );
212 
213  Quaternion q1( xAxis, yAxis, zAxis );
214 
216 
217  xAxis = Vector3( 1.0f, 1.0f, 0.0f );
218  xAxis.Normalize();
219  yAxis = Vector3( -1.0f, 1.0f, 0.0f ); // 45 degrees anticlockwise ( +ve ) around z
220  yAxis.Normalize();
221  zAxis = xAxis.Cross( yAxis );
222  zAxis.Normalize();
223  Quaternion q2( xAxis, yAxis, zAxis );
224 
226  END_TEST;
227 }
228 
229 
231 {
232  // Create an arbitrary forward vector
233  for( float x=-1.0f; x<=1.0f; x+=0.1f )
234  {
235  for( float y=-1.0f; y<1.0f; y+=0.1f )
236  {
237  for( float z=-1.0f; z<1.0f; z+=0.1f )
238  {
239  Vector3 vForward( x, y, z );
240  vForward.Normalize();
241 
242  // Construct an up vector from a sideways move
243  Vector3 vSide;
244  Vector3 vUp = vForward.Cross( Vector3( vForward.x+1.0f, vForward.y, vForward.z ) );
245  if( vUp.Length() > 0.01 )
246  {
247  vUp.Normalize();
248  vSide = vUp.Cross( vForward );
249  vSide.Normalize();
250  }
251  else
252  {
253  vSide = vForward.Cross( Vector3( vForward.x, vForward.y+1.0f, vForward.z ) );
254  vSide.Normalize();
255  vUp = vForward.Cross( vSide );
256  vUp.Normalize();
257  }
258 
259  // Generate a quaternion
260  Quaternion q( vSide, vUp, vForward );
261 
262  Matrix rotMatrix;
263  rotMatrix.SetXAxis( vSide );
264  rotMatrix.SetYAxis( vUp );
265  rotMatrix.SetZAxis( vForward );
266 
267  // Generate a matrix from the quaternion, check they are the same
268  Matrix m( q );
269  DALI_TEST_EQUALS( m.GetXAxis(), vSide, 0.001f, TEST_LOCATION );
270  DALI_TEST_EQUALS( m.GetYAxis(), vUp, 0.001f, TEST_LOCATION );
271  DALI_TEST_EQUALS( m.GetZAxis(), vForward, 0.001f, TEST_LOCATION );
272 
273  // Rotate an arbitrary vector by both quaternion and rotation matrix,
274  // check the result is the same
275 
276  Vector4 aVector( 2.043f, 12.8f, -3.872f, 1.0f );
277  Vector3 aVectorRotatedByQ = q.Rotate( Vector3( aVector ) );
278  Vector4 aVectorRotatedByR = rotMatrix*aVector;
279  DALI_TEST_EQUALS( aVectorRotatedByQ, Vector3( aVectorRotatedByR ), 0.001f, TEST_LOCATION );
280  }
281  }
282  }
283  END_TEST;
284 }
285 
287 {
288  Vector3 v0( 1.0f, 2.0f, 3.0f );
289  Vector3 v1( -2.0f, 10.0f, -1.0f );
290  v0.Normalize();
291  v1.Normalize();
292  Quaternion q( v0, v1 );
293 
294  DALI_TEST_EQUALS( q*v0, v1, 0.001, TEST_LOCATION );
295  END_TEST;
296 }
297 
299 {
300  Vector4 v( 1.0f, 0.1f, 0.2f, 0.3f );
301  Quaternion q( v );
302 
304  END_TEST;
305 }
306 
308 {
309  Quaternion q( 0.932f, 1.1f, 3.4f, 2.7f );
310  Radian angle;
311  Vector3 axis;
312  bool converted = q.ToAxisAngle( axis, angle );
313  DALI_TEST_EQUALS( converted, true, TEST_LOCATION );
314  DALI_TEST_EQUALS( angle.radian, 0.74f, 0.01f, TEST_LOCATION );
315  DALI_TEST_EQUALS( axis.x, 3.03f, 0.01f, TEST_LOCATION );
316  DALI_TEST_EQUALS( axis.y, 9.38f, 0.01f, TEST_LOCATION );
317  DALI_TEST_EQUALS( axis.z, 7.45f, 0.01f, TEST_LOCATION );
318  END_TEST;
319 }
320 
322 {
323  Quaternion q( 1, 2, 3, 4 );
324  Radian angle;
325  Vector3 axis;
326  bool converted = q.ToAxisAngle( axis, angle );
327  DALI_TEST_EQUALS( converted, false, TEST_LOCATION );
328  DALI_TEST_EQUALS( angle.radian, 0.0f, 0.01f, TEST_LOCATION );
329  DALI_TEST_EQUALS( axis.x, 0.0f, 0.01f, TEST_LOCATION );
330  DALI_TEST_EQUALS( axis.y, 0.0f, 0.01f, TEST_LOCATION );
331  DALI_TEST_EQUALS( axis.z, 0.0f, 0.01f, TEST_LOCATION );
332  END_TEST;
333 }
334 
336 {
337  // Test from euler angles
338  Quaternion e1;
340  Vector4 r1( 0.383f, 0.0f, 0.0f, 0.924f );
341 
342  Quaternion e2;
344  Vector4 r2( 0.0f, 0.609f, 0.0f, 0.793f );
345 
346  Quaternion e3;
348  Vector4 r3( 0.0f, 0.0f, 0.924f, 0.383f );
349 
350  Quaternion e4;
351  e4.SetEuler( Radian( Degree( 71 ) ), Radian( Degree( 36 ) ), Radian( Degree( 27 ) ) );
352  Vector4 r4( 0.478f, 0.374f, 0.006f, 0.795f );
353 
354  Quaternion e5;
355  e5.SetEuler( Radian( Degree( -31 ) ), Radian( Degree( -91 ) ), Radian( Degree( -173 ) ) );
356  Vector4 r5( -0.697f, 0.145f, -0.686f, -0.149f );
357 
358  DALI_TEST_EQUALS( e1.AsVector(), r1, 0.001, TEST_LOCATION );
359  DALI_TEST_EQUALS( e2.AsVector(), r2, 0.001, TEST_LOCATION );
360  DALI_TEST_EQUALS( e3.AsVector(), r3, 0.001, TEST_LOCATION );
361  DALI_TEST_EQUALS( e4.AsVector(), r4, 0.001, TEST_LOCATION );
362  DALI_TEST_EQUALS( e5.AsVector(), r5, 0.001, TEST_LOCATION );
363  END_TEST;
364 }
365 
367 {
368  Quaternion q1( 0.924f, 0.383f, 0.0f, 0.0f );
369  Vector4 r1( Radian( Degree( 45 ) ), 0.0f, 0.0f, 0.0f );
370 
371  Quaternion q2( 0.793f, 0.0f, 0.609f, 0.0f );
372  Vector4 r2( 0.0f, Radian( Degree( 75 ) ), 0.0f, 0.0f );
373 
374  Quaternion q3( 0.383f, 0.0f, 0.0f, 0.924f );
375  Vector4 r3( 0.0f, 0.0f, Radian( Degree( 135 ) ), 0.0f );
376 
377  Quaternion q4( 0.795f, 0.478f, 0.374f, 0.006f );
378  Vector4 r4( Radian( Degree( 71 ) ), Radian( Degree( 36 ) ), Radian( Degree( 27 ) ), 0.0f );
379 
380  Quaternion q5( -0.149f, -0.697f, 0.145f, -0.686f );
381  Vector4 r5( Radian( Degree( 148.0 ) ), Radian( Degree( -88.2 ) ), Radian( Degree( 8.0 ) ), 0.0f );
382 
383  DALI_TEST_EQUALS( q1.EulerAngles(), r1, 0.001, TEST_LOCATION );
384  DALI_TEST_EQUALS( q2.EulerAngles(), r2, 0.001, TEST_LOCATION );
385  DALI_TEST_EQUALS( q3.EulerAngles(), r3, 0.001, TEST_LOCATION );
386  DALI_TEST_EQUALS( q4.EulerAngles(), r4, 0.01, TEST_LOCATION );
387  DALI_TEST_EQUALS( q5.EulerAngles(), r5, 0.01, TEST_LOCATION );
388  END_TEST;
389 }
390 
391 
393 {
394  Quaternion q( Radian( 0.69813 ), Vector3( 1.0f, 0.0f, 0.0f ) ); // 40 degree rotation around X axis
395 
396  // Result calculated using a different maths library ( with appropriate row/col ordering )
397 
398  float els[] = { 1.0f, 0.0f, 0.0f, 0.0f,
399  0.0f, 0.766f, 0.643f, 0.0f,
400  0.0f, -0.643f, 0.766f, 0.0f,
401  0.0f, 0.0f, 0.0f, 1.0f };
402  Matrix mRes( els );
403  Matrix m( q );
404 
405  DALI_TEST_EQUALS( m, mRes, 0.01, TEST_LOCATION );
406  END_TEST;
407 }
408 
410 {
411  // rotation around arbitrary axis
412  Quaternion q2( Radian( -1.23918f ), Vector3( 7.0f, -13.0f, 11.0f ) );
413 
414  float els[] = { 0.423f, -0.746f, -0.514f, 0.00f,
415  0.384f, 0.662f, -0.644f, 0.00f,
416  0.821f, 0.075f, 0.566f, 0.00f,
417  0.000f, 0.000f, 0.000f, 1.00f };
418  Matrix mRes2( els );
419 
420  Matrix m2( q2 );
421 
422  DALI_TEST_EQUALS( m2, mRes2, 0.01, TEST_LOCATION );
423  END_TEST;
424 }
425 
426 
428 {
429  Quaternion q1( 0.383f, 0.0f, 0.0f, 0.924f );
430  Quaternion q2( 0.0f, 0.609f, 0.0f, 0.793f );
431 
432  Quaternion r1( 0.383f, 0.609f, 0.0f, 1.717f );
433 
434  DALI_TEST_EQUALS( q1+q2, r1, 0.001f, TEST_LOCATION );
435  END_TEST;
436 }
437 
439 {
440  Quaternion q1( 0.383f, 0.450f, 0.123f, 0.924f );
441  Quaternion q2( 0.383f, 0.690f, 0.234f, 1.917f );
442 
443  Quaternion r1( 0.0f, 0.240f, 0.111f, 0.993f );
444 
445  DALI_TEST_EQUALS( q2-q1, r1, 0.001f, TEST_LOCATION );
446  END_TEST;
447 }
448 
450 {
451  float s1 = 0.784f; Vector3 v1( 0.045f, 0.443f, 0.432f );
452  float s2 = 0.697f; Vector3 v2( 0.612, 0.344, -0.144 );
453 
454  Quaternion q1( s1, v1.x, v1.y, v1.z );
455  Quaternion q2( s2, v2.x, v2.y, v2.z );
456  q1.Conjugate();
457  q2.Conjugate();
458 
459  Quaternion r1( s1, -v1.x, -v1.y, -v1.z );
460  Quaternion r2( s2, -v2.x, -v2.y, -v2.z );
461 
462  DALI_TEST_EQUALS( q1, r1, 0.001f, TEST_LOCATION );
463  DALI_TEST_EQUALS( q2, r2, 0.001f, TEST_LOCATION );
464  END_TEST;
465 }
466 
468 {
469  float s1=0.784f; Vector3 v1( 0.045f, 0.443f, 0.432f );
470  float s2=0.697f; Vector3 v2( 0.612, 0.344, -0.144 );
471 
472  Quaternion q1( s1, v1.x, v1.y, v1.z );
473  Quaternion q2( s2, v2.x, v2.y, v2.z );
474 
475  Vector3 vp = v1.Cross( v2 ) + v2*s1 + v1*s2;
476  Quaternion r1( s1*s2-v1.Dot( v2 ), vp.x, vp.y, vp.z );
477 
478  DALI_TEST_EQUALS( q1*q2, r1, 0.001f, TEST_LOCATION );
479  END_TEST;
480 }
481 
482 // Quaternion * vector == Vector rotation
484 {
485  // Rotation of vector p = ( x,y,z ) by Quaternion q == q [0,p] q^-1
486  Vector3 v( 2, 3, 4 );
487  Quaternion q( Radian( Degree( 72 ) ), Vector3::ZAXIS );
488  Quaternion qI = q;
489  qI.Invert();
490  Quaternion qv( 0.0f, v.x, v.y, v.z );
491  Quaternion r1 = ( q * qv ) * qI;
492 
493  Vector3 r2 = q * v;
494 
495  DALI_TEST_EQUALS( r1.mVector.x, r2.x, 0.001, TEST_LOCATION );
496  DALI_TEST_EQUALS( r1.mVector.y, r2.y, 0.001, TEST_LOCATION );
497  DALI_TEST_EQUALS( r1.mVector.z, r2.z, 0.001, TEST_LOCATION );
498  END_TEST;
499 }
500 
502 {
503  // Rotation of vector p = ( x,y,z ) by Quaternion q == q [0,p] q^-1
504  Quaternion q( Vector4( 0.1f, 0.2f, 0.3f, 1.0f ) );
505  Quaternion q2 = q * 2.f;
506  Vector4 v2( 0.2f, 0.4f, 0.6f, 2.0f );
507 
508  DALI_TEST_EQUALS( q2.AsVector(), v2, 0.001, TEST_LOCATION );
509  END_TEST;
510 }
511 
513 {
514  Quaternion q1( 0.383f, 0.0f, 0.0f, 0.924f );
515  Quaternion r1( 2.0f* 0.383f, 0.0f, 0.0f, 2.0f * 0.924f );
516 
517  DALI_TEST_EQUALS( q1 * 2.0f, r1, 0.001f, TEST_LOCATION );
518  END_TEST;
519 }
520 
522 {
523  Quaternion q1( 0.383f, 0.0f, 0.0f, 0.924f );
524  Quaternion r1( 0.5f* 0.383f, 0.0f, 0.0f, 0.5f * 0.924f );
525 
526  DALI_TEST_EQUALS( q1 / 2.0f, r1, 0.001f, TEST_LOCATION );
527  END_TEST;
528 }
529 
531 {
532  Quaternion q1( 0.383f, 0.0f, 0.0f, 0.924f );
533  Quaternion q2( 0.0f, 0.609f, 0.0f, 0.793f );
534 
535  // q1 / q2 = q1 * q2^-1
536  // q2^-1 = q2* / ||q2||^2
537  // = Conjugate of q2 / Square of Norm of q2
538 
539  Quaternion r1 = q2;
540  r1.Conjugate();
541  r1 *= 1.0f/q2.LengthSquared();
542  Quaternion r2 = q1 * r1;
543 
544  DALI_TEST_EQUALS( q1 / q2, r2, 0.001f, TEST_LOCATION );
545  END_TEST;
546 }
547 
549 {
550  Quaternion q1( 0.383f, 0.0f, 0.0f, 0.924f );
551  Quaternion r1( 2.0f* 0.383f, 0.0f, 0.0f, 2.0f * 0.924f );
552 
553  DALI_TEST_EQUALS( q1, r1/2.0f, 0.001f, TEST_LOCATION );
554  END_TEST;
555 }
556 
558 {
559  Quaternion q1( 0.383f, 0.0f, 0.0f, 0.924f );
560  Quaternion r1( 2.0f* 0.383f, 0.0f, 0.0f, 2.0f * 0.924f );
561  r1 /= 2.0f;
562 
563  DALI_TEST_EQUALS( q1, r1, 0.001f, TEST_LOCATION );
564  END_TEST;
565 }
566 
568 {
569  Quaternion q1( 0.383f, 0.0f, 0.0f, 0.924f );
570  Quaternion r1( -0.383f, -0.0f, -0.0f, -0.924f );
571 
572  DALI_TEST_EQUALS( -q1, r1, 0.001f, TEST_LOCATION );
573  END_TEST;
574 }
575 
577 {
578  Quaternion q1( 0.383f, 0.0f, 0.0f, 0.924f );
579  Quaternion q2( 0.0f, 0.609f, 0.0f, 0.793f );
580 
581  Quaternion r1( 0.383f, 0.609f, 0.0f, 1.717f );
582 
583  q1 += q2;
584  DALI_TEST_EQUALS( q1, r1, 0.001f, TEST_LOCATION );
585  END_TEST;
586 }
587 
589 {
590  Quaternion q1( 0.383f, 0.450f, 0.123f, 0.924f );
591  Quaternion q2( 0.383f, 0.690f, 0.234f, 1.917f );
592 
593  Quaternion r1( 0.0f, 0.240f, 0.111f, 0.993f );
594  q2 -= q1;
595  DALI_TEST_EQUALS( q2, r1, 0.001f, TEST_LOCATION );
596  END_TEST;
597 }
598 
600 {
601  float s1=0.784f; Vector3 v1( 0.045f, 0.443f, 0.432f );
602  float s2=0.697f; Vector3 v2( 0.612, 0.344, -0.144 );
603 
604  Quaternion q1( s1, v1.x, v1.y, v1.z );
605  Quaternion q2( s2, v2.x, v2.y, v2.z );
606 
607  Quaternion r3 = q2 * q1;
608  q2 *= q1;
609  DALI_TEST_EQUALS( q2, r3, 0.001f, TEST_LOCATION );
610  END_TEST;
611 }
612 
614 {
615  Quaternion q1( 0.383f, 0.450f, 0.123f, 0.924f );
616  float scale = 2.5f;
617  Quaternion r1( scale*0.383f, scale*0.450f, scale*0.123f, scale*0.924f );
618  q1 *= scale;
619  DALI_TEST_EQUALS( q1, r1, 0.001f, TEST_LOCATION );
620  END_TEST;
621 }
622 
624 {
625  Quaternion q1( 0.383f, 0.450f, 0.123f, 0.924f );
626  float scale = 2.5f;
627  Quaternion r1( 0.383f/scale, 0.450f/scale, 0.123f/scale, 0.924f/scale );
628  q1 /= scale;
629  DALI_TEST_EQUALS( q1, r1, 0.001f, TEST_LOCATION );
630  END_TEST;
631 }
632 
634 {
635  Quaternion q1( 0.383f, 0.450f, 0.123f, 0.924f );
636  Quaternion q2( 0.383f, 0.450f, 0.123f, 0.924f );
637  Quaternion q3( 0.383f, 0.450f, 0.123f, 0.800f );
638  Quaternion q4( 0.383f, 0.450f, 0.100f, 0.800f );
639  Quaternion q5( 0.383f, 0.100f, 0.100f, 0.800f );
640  Quaternion q6( 0.100f, 0.100f, 0.100f, 0.800f );
641 
642  Quaternion q7( -0.383f, -0.450f, -0.123f, -0.924f );
643  Quaternion q8( -0.383f, -0.450f, -0.123f, 0.924f );
644  Quaternion q9( -0.383f, -0.450f, 0.123f, 0.924f );
645  Quaternion q10( -0.383f, 0.450f, 0.123f, 0.924f );
646 
647  DALI_TEST_CHECK( q1 == q2 );
648  DALI_TEST_CHECK( !( q1 == q3 ) );
649  DALI_TEST_CHECK( !( q1 == q4 ) );
650  DALI_TEST_CHECK( !( q1 == q5 ) );
651  DALI_TEST_CHECK( !( q1 == q6 ) );
652  DALI_TEST_CHECK( ( q1 == q7 ) );
653  DALI_TEST_CHECK( !( q1 == q8 ) );
654  DALI_TEST_CHECK( !( q1 == q9 ) );
655  DALI_TEST_CHECK( !( q1 == q10 ) );
656  END_TEST;
657 }
658 
660 {
661  Quaternion q1( 0.383f, 0.450f, 0.123f, 0.924f );
662  Quaternion q2( 0.383f, 0.450f, 0.123f, 0.924f );
663  Quaternion q3( -0.383f, -0.0f, -0.0f, -0.924f );
664  DALI_TEST_CHECK( !( q1 != q2 ) );
665  DALI_TEST_CHECK( q1 != q3 );
666  END_TEST;
667 }
668 
670 {
671  Quaternion q1( 0.383f, 0.450f, 0.123f, 0.924f );
672  float length = sqrtf( 0.383f*0.383f + 0.450f*0.450f + 0.123f*0.123f + 0.924f*0.924f );
673  DALI_TEST_EQUALS( q1.Length(), length, 0.001f, TEST_LOCATION );
674  END_TEST;
675 }
676 
678 {
679  Quaternion q1( 0.383f, 0.450f, 0.123f, 0.924f );
680  float lengthSquared = 0.383f*0.383f + 0.450f*0.450f + 0.123f*0.123f + 0.924f*0.924f;
681  DALI_TEST_EQUALS( q1.LengthSquared(), lengthSquared, 0.01f, TEST_LOCATION );
682  END_TEST;
683 }
684 
686 {
687  Quaternion q1( 0.118f, 0.692f, -0.127f, 0.701f );
688  Quaternion q2 = q1;
689  q2 *= 5.0f;
690  q2.Normalize();
691  DALI_TEST_EQUALS( q1, q2, 0.001f, TEST_LOCATION );
692  END_TEST;
693 }
694 
696 {
697  Quaternion q1( 0.118f, 0.692f, -0.127f, 0.701f );
698  Quaternion q2 = q1;
699  q2 *= 5.0f;
700  DALI_TEST_EQUALS( q1, q2.Normalized(), 0.001f, TEST_LOCATION );
701  END_TEST;
702 }
703 
705 {
706  Quaternion q( 1.0f, 0.0f, 0.0f, 0.0f );
708  END_TEST;
709 }
710 
712 {
713  Quaternion q( 1.0f, 0.1f, 0.0f, 0.0f );
715  END_TEST;
716 }
717 
719 {
720  Quaternion q1( 0.383f, 0.0f, 0.0f, 0.924f );
721 
722  // q1^-1 = q1* / ||q1||^2
723  // = Conjugate of q1 / Square of Norm of q1
724 
725  Quaternion r1 = q1;
726  r1.Conjugate();
727  r1 *= 1.0f/q1.LengthSquared();
728 
729  Quaternion q2 = q1;
730  q2.Invert();
731  DALI_TEST_EQUALS( q2, r1, 0.001f, TEST_LOCATION );
732  END_TEST;
733 }
734 
735 
737 {
738  // q.q' = s*s' + v dot v'
739  float s1 = 0.784f; Vector3 v1( 0.045f, 0.443f, 0.432f );
740  float s2 = 0.697f; Vector3 v2( 0.612, 0.344, -0.144 );
741 
742  Quaternion q1( s1, v1.x, v1.y, v1.z );
743  Quaternion q2( s2, v2.x, v2.y, v2.z );
744 
745  float r1 = s1*s2 + v1.Dot( v2 );
746 
748  END_TEST;
749 }
750 
751 
753 {
754  // Rotation of vector p = ( x,y,z ) by Quaternion q == q [0,p] q^-1
755  Vector3 v( 2, 3, 4 );
756  Quaternion q( Radian( Degree( 72 ) ), Vector3::ZAXIS );
757  Quaternion qI = q;
758  qI.Invert();
759  Quaternion qv( 0.0f, v.x, v.y, v.z );
760  Quaternion r1 = q * qv * qI;
761 
762  Vector3 r2 = q.Rotate( v );
763 
764  DALI_TEST_EQUALS( r1.mVector.x, r2.x, 0.001f, TEST_LOCATION );
765  DALI_TEST_EQUALS( r1.mVector.y, r2.y, 0.001f, TEST_LOCATION );
766  DALI_TEST_EQUALS( r1.mVector.z, r2.z, 0.001f, TEST_LOCATION );
767 
768  DALI_TEST_EQUALS( q.Rotate( v ), q*v, 0.001f, TEST_LOCATION );
769  END_TEST;
770 }
771 
772 
774 {
775  // Rotation of vector p = ( x,y,z ) by Quaternion q == q [0,p] q^-1
776  Vector4 v( 2, 3, 4, 5 );
777  Quaternion q( Radian( Degree( 72 ) ), Vector3::ZAXIS );
778  Quaternion qI = q;
779  qI.Invert();
780  Quaternion qv( 0.0f, v.x, v.y, v.z );
781  Quaternion r1 = q * qv * qI;
782 
783  Vector4 r2 = q.Rotate( v );
784 
785  DALI_TEST_EQUALS( r1.mVector.x, r2.x, 0.001f, TEST_LOCATION );
786  DALI_TEST_EQUALS( r1.mVector.y, r2.y, 0.001f, TEST_LOCATION );
787  DALI_TEST_EQUALS( r1.mVector.z, r2.z, 0.001f, TEST_LOCATION );
788  DALI_TEST_EQUALS( r1.mVector.w, 0.0f, 0.001f, TEST_LOCATION );
789  END_TEST;
790 }
791 
792 
794 {
795  Quaternion q1( 0.0f, 1.0f, 1.2f, 1.3f );
796  Quaternion q2 = q1.Exp();
797  Quaternion r2( -0.4452, 0.4406, 0.5287, 0.5728 );
798 
799  DALI_TEST_EQUALS( q2.Length(), 1.0f, 0.01f, TEST_LOCATION );
800 
801  DALI_TEST_EQUALS( q2, r2, 0.001f, TEST_LOCATION );
802 
803  // Note, this trick only works when |v| < pi, which it is!
804  Quaternion q3 = q2.Log();
805  DALI_TEST_EQUALS( q1, q3, 0.01f, TEST_LOCATION );
806  END_TEST;
807 }
808 
809 
811 {
812  Quaternion q1( 0.0f, 0.0f, 0.0f, 0.0f );
813  Quaternion q2 = q1.Exp();
814  Quaternion r2( 1.0f, 0.0f, 0.0f, 0.0f );
815 
816  DALI_TEST_EQUALS( q2.Length(), 1.0f, 0.01f, TEST_LOCATION );
817 
818  DALI_TEST_EQUALS( q2, r2, 0.001f, TEST_LOCATION );
819 
820  // Note, this trick only works when |v| < pi, which it is!
821  Quaternion q3 = q2.Log();
822  DALI_TEST_EQUALS( q1, q3, 0.01f, TEST_LOCATION );
823  END_TEST;
824 }
825 
826 
828 {
829  Quaternion q( Radian( 0.0f ), Vector3(5.0f, 6.0f, 7.0f) );
830 
831  // q.w is non-zero. Should assert.
832  try
833  {
834  q.Exp();
835  DALI_TEST_CHECK( false );
836  }
837  catch( DaliException& e )
838  {
839  DALI_TEST_CHECK( true );
840  }
841  END_TEST;
842 }
843 
844 
846 {
847  Quaternion q( Radian( Math::PI*0.73f ), Vector3(2,3,4) );
848  Quaternion q2 = q;
849  q2.Normalize();
850 
851  Quaternion r = q2.Log();
852  DALI_TEST_EQUALS( r.mVector.w, 0.0f, 0.01f, TEST_LOCATION );
853 
854  Quaternion r2 = r.Exp();
855  DALI_TEST_EQUALS( r2, q2, 0.01f, TEST_LOCATION );
856  END_TEST;
857 }
858 
860 {
861  Quaternion q1( 1.0f, 0.0f, 0.0f, 0.0f );
862  Quaternion r1( 0.0f, 0.0f, 0.0f, 0.0f );
863 
864  Quaternion q2 = q1.Log();
865 
866  DALI_TEST_EQUALS( q2, r1, 0.01f, TEST_LOCATION );
867 
868  Quaternion q3 = q2.Exp();
869  DALI_TEST_EQUALS( q1, q3, 0.01f, TEST_LOCATION );
870  END_TEST;
871 }
872 
874 {
875  Quaternion q1( Radian( Degree( -80 ) ), Vector3( 0.0f, 0.0f, 1.0f ) );
876  Quaternion q2( Radian( Degree( 80 ) ), Vector3( 0.0f, 0.0f, 1.0f ) );
877 
878  Quaternion p = Quaternion::Lerp( q1, q2, 0.0f );
879  DALI_TEST_EQUALS( p, q1, 0.001f, TEST_LOCATION );
880 
881  p = Quaternion::Lerp( q1, q2, 1.0f );
882  DALI_TEST_EQUALS( p, q2, 0.001f, TEST_LOCATION );
883 
884  p = Quaternion::Lerp( q1, q2, 0.5f );
885  Quaternion r1 = ( q1 + q2 ) * 0.5f;
886  r1.Normalize();
887  DALI_TEST_EQUALS( p, r1, 0.001f, TEST_LOCATION );
888  END_TEST;
889 }
890 
892 {
893  Quaternion q1(Radian(M_PI/4.0f), Vector3(0.0f, 0.0f, 1.0f));
894  Quaternion q2(Radian(-M_PI/4.0f), Vector3(0.0f, 0.0f, 1.0f));
895 
896  Quaternion q = Quaternion::Slerp( q1, q2, 0.0f );
897  DALI_TEST_EQUALS( q, q1, 0.001, TEST_LOCATION );
898 
899  q = Quaternion::Slerp( q1, q2, 1.0f );
900  DALI_TEST_EQUALS( q, q2, 0.001, TEST_LOCATION );
901 
902  // @ 25%, will be at M_PI/8
903  q = Quaternion::Slerp( q1, q2, 0.25f );
904  Vector3 axis;
905  Radian angle;
906  bool converted = q.ToAxisAngle( axis, angle );
907  DALI_TEST_EQUALS( converted, true, TEST_LOCATION );
908  DALI_TEST_EQUALS( angle.radian, Math::PI/8.0f, 0.001, TEST_LOCATION );
909  DALI_TEST_EQUALS( axis.x, 0.0f, 0.001, TEST_LOCATION );
910  DALI_TEST_EQUALS( axis.y, 0.0f, 0.001, TEST_LOCATION );
911  DALI_TEST_EQUALS( axis.z, 1.0f, 0.001, TEST_LOCATION );
912  END_TEST;
913 }
914 
915 
916 
918 {
919  Quaternion q1( Dali::ANGLE_30, Vector3(0.0f, 0.0f, 1.0f));
920  Quaternion q2( Dali::ANGLE_90, Vector3(0.0f, 0.0f, 1.0f));
921 
922  Quaternion q = Quaternion::Slerp( q1, q2, 0.0f );
923 
924  DALI_TEST_EQUALS( q, q1, 0.001, TEST_LOCATION );
925 
926  q = Quaternion::Slerp( q1, q2, 1.0f );
927 
928  DALI_TEST_EQUALS( q, q2, 0.001, TEST_LOCATION );
929 
930  // @ 50%, will be at M_PI/3 around z
931  q = Quaternion::Slerp( q1, q2, 0.5f );
932 
933  Quaternion r( Dali::ANGLE_60, Vector3( 0.0f, 0.0f, 1.0f));
934  DALI_TEST_EQUALS( q, r, 0.001, TEST_LOCATION );
935  END_TEST;
936 }
937 
938 
940 {
941  Quaternion q1( Radian( Degree( 125 ) ), Vector3( 0.0f, 0.0f, 1.0f ) );
942  Quaternion q2( Radian( Degree( -125 ) ), Vector3( 0.002f, 0.001f, 1.001f ) );
943 
944  Quaternion q = Quaternion::Slerp( q1, q2, 0.0f );
945  DALI_TEST_EQUALS( q, q1, 0.001, TEST_LOCATION );
946 
947  q = Quaternion::Slerp( q1, q2, 1.0f );
948  DALI_TEST_EQUALS( q, q2, 0.001, TEST_LOCATION );
949 
950  q = Quaternion::Slerp(q1, q2, 0.05f);
951  Vector3 axis;
952  Radian angle;
953  bool converted = q.ToAxisAngle(axis, angle);
954  DALI_TEST_EQUALS(converted, true, TEST_LOCATION);
955 
956  DALI_TEST_EQUALS( axis.x, 0.0f, 0.01, TEST_LOCATION );
957  DALI_TEST_EQUALS( axis.y, 0.0f, 0.01, TEST_LOCATION );
958  DALI_TEST_EQUALS( axis.z, 1.0f, 0.01, TEST_LOCATION );
959  END_TEST;
960 }
961 
962 
963 
965 {
966  Quaternion q1( Radian( Degree( 120 ) ), Vector3( 0.0f, 0.0f, 1.0f ) );
967  Quaternion q2( Radian( Degree( 130 ) ), Vector3( 0.0f, 0.0f, 1.0f ) );
968 
969  Quaternion q = Quaternion::Slerp( q1, q2, 0.0f );
970  DALI_TEST_EQUALS( q, q1, 0.001, TEST_LOCATION );
971 
972  q = Quaternion::Slerp( q1, q2, 1.0f );
973  DALI_TEST_EQUALS( q, q2, 0.001, TEST_LOCATION );
974 
975  q = Quaternion::Slerp(q1, q2, 0.5f);
976  Vector3 axis;
977  Radian angle;
978  bool converted = q.ToAxisAngle(axis, angle);
979  DALI_TEST_EQUALS(converted, true, TEST_LOCATION);
980  DALI_TEST_EQUALS(angle.radian, float(Radian(Degree(125))), 0.01f, TEST_LOCATION);
981  DALI_TEST_EQUALS(axis.x, 0.0f, 0.01, TEST_LOCATION);
982  DALI_TEST_EQUALS(axis.y, 0.0f, 0.01, TEST_LOCATION);
983  DALI_TEST_EQUALS(axis.z, 1.0f, 0.01, TEST_LOCATION);
984  END_TEST;
985 }
986 
987 
988 
990 {
991  Quaternion q1( Dali::ANGLE_45, Vector3(0.0f, 0.0f, 1.0f));
992  Quaternion q2(-Dali::ANGLE_45, Vector3(0.0f, 0.0f, 1.0f));
993 
994  Quaternion q = Quaternion::SlerpNoInvert( q1, q2, 0.0f );
995  DALI_TEST_EQUALS( q, q1, 0.001, TEST_LOCATION );
996 
997  q = Quaternion::SlerpNoInvert( q1, q2, 1.0f );
998  DALI_TEST_EQUALS( q, q2, 0.001, TEST_LOCATION );
999 
1000  // @ 25%, will be at M_PI/8
1001  q = Quaternion::SlerpNoInvert(q1, q2, 0.25f);
1002  Vector3 axis;
1003  Radian angle;
1004  bool converted = q.ToAxisAngle(axis, angle);
1005  DALI_TEST_EQUALS(converted, true, TEST_LOCATION);
1006  DALI_TEST_EQUALS(angle.radian, Math::PI/8.0f, 0.001, TEST_LOCATION);
1007  DALI_TEST_EQUALS(axis.x, 0.0f, 0.001, TEST_LOCATION);
1008  DALI_TEST_EQUALS(axis.y, 0.0f, 0.001, TEST_LOCATION);
1009  DALI_TEST_EQUALS(axis.z, 1.0f, 0.001, TEST_LOCATION);
1010  END_TEST;
1011 }
1012 
1013 
1015 {
1016  Quaternion q1( Radian( Degree( 120 ) ), Vector3( 0.0f, 0.0f, 1.0f ) );
1017  Quaternion q2( Radian( Degree( 130 ) ), Vector3( 0.0f, 0.0f, 1.0f ) );
1018 
1019  Quaternion q = Quaternion::SlerpNoInvert( q1, q2, 0.0f );
1020  DALI_TEST_EQUALS( q, q1, 0.001, TEST_LOCATION );
1021 
1022  q = Quaternion::SlerpNoInvert( q1, q2, 1.0f );
1023  DALI_TEST_EQUALS( q, q2, 0.001, TEST_LOCATION );
1024 
1025  q = Quaternion::SlerpNoInvert(q1, q2, 0.5f);
1026  Vector3 axis;
1027  Radian angle;
1028  bool converted = q.ToAxisAngle(axis, angle);
1029  DALI_TEST_EQUALS(converted, true, TEST_LOCATION);
1030  DALI_TEST_EQUALS(angle.radian, float(Radian(Degree(125))), 0.01f, TEST_LOCATION);
1031  DALI_TEST_EQUALS(axis.x, 0.0f, 0.01, TEST_LOCATION);
1032  DALI_TEST_EQUALS(axis.y, 0.0f, 0.01, TEST_LOCATION);
1033  DALI_TEST_EQUALS(axis.z, 1.0f, 0.01, TEST_LOCATION);
1034  END_TEST;
1035 }
1036 
1037 
1039 {
1040  Quaternion q1( Radian( Degree( 45 ) ), Vector3( 0.0f, 0.0f, 1.0f ) );
1041  Quaternion q1out( Radian( Degree( 40 ) ), Vector3( 0.0f, 1.0f, 2.0f ) );
1042  Quaternion q2in( Radian( Degree( 35 ) ), Vector3( 0.0f, 2.0f, 3.0f ) );
1043  Quaternion q2( Radian( Degree( 30 ) ), Vector3( 0.0f, 1.0f, 3.0f ) );
1044 
1045  Quaternion q = Quaternion::Squad( q1, q2, q1out, q2in, 0.0f );
1046  DALI_TEST_EQUALS( q, q1, 0.001f, TEST_LOCATION );
1047 
1048  q = Quaternion::Squad( q1, q2, q1out, q2in, 1.0f );
1049  DALI_TEST_EQUALS( q, q2, 0.001f, TEST_LOCATION );
1050 
1051  // Don't know what actual value should be, but can make some informed guesses.
1052  q = Quaternion::Squad(q1, q2, q1out, q2in, 0.5f);
1053  Radian angle;
1054  Vector3 axis;
1055  q.Normalize();
1056  q.ToAxisAngle( axis, angle );
1057 
1058  if( angle < 0.0f )
1059  {
1060  q = -q; // Might get negative quat
1061  q.ToAxisAngle( axis, angle );
1062  }
1063  float deg = Degree(angle).degree;
1064  DALI_TEST_CHECK(deg >= 0 && deg <= 90);
1065  DALI_TEST_CHECK(axis.y > 0);
1066  DALI_TEST_CHECK(axis.z > 0);
1067  END_TEST;
1068 }
1069 
1071 {
1073  Quaternion q2(Radian(Degree(47)), ANGLE_0, ANGLE_0 );
1074  DALI_TEST_EQUALS(Quaternion::AngleBetween(q1, q2), fabsf(Radian(Degree(45)) - Radian(Degree(47))), 0.001f, TEST_LOCATION);
1075 
1076  Quaternion q3( Radian( Degree( 80 ) ), Vector3::YAXIS );
1077  Quaternion q4( Radian( Degree( 90 ) ), Vector3::YAXIS );
1078  DALI_TEST_EQUALS( Quaternion::AngleBetween( q3, q4 ), fabsf( Radian( Degree( 80 ) ) - Radian( Degree( 90 ) ) ), 0.001f, TEST_LOCATION );
1079 
1080  Quaternion q5( Radian( Degree( 0 ) ), Vector3::YAXIS );
1081  Quaternion q6( Radian( Degree( 90 ) ), Vector3::XAXIS );
1082  DALI_TEST_EQUALS( Quaternion::AngleBetween( q5, q6 ), fabsf( Radian( Degree( 0 ) ) - Radian( Degree( 90 ) ) ), 0.001f, TEST_LOCATION );
1083 
1084  Quaternion q7( Radian( Degree( 0 ) ), Vector3::YAXIS );
1085  Quaternion q8( Radian( Degree( 0 ) ), Vector3::XAXIS );
1086  DALI_TEST_EQUALS( Quaternion::AngleBetween( q7, q8 ), fabsf( Radian( Degree( 0 ) ) - Radian( Degree( 0 ) ) ), 0.001f, TEST_LOCATION );
1087 
1088  Quaternion q9( Radian( Degree( 0 ) ), Vector3::XAXIS );
1089  Quaternion q10( Radian( Degree( 180 ) ), Vector3::XAXIS );
1090  DALI_TEST_EQUALS( Quaternion::AngleBetween( q9, q10 ), fabsf( Radian( Degree( 0 ) ) - Radian( Degree( 180 ) ) ), 0.001f, TEST_LOCATION );
1091 
1092  Quaternion q11( Radian( Degree( 1 ) ), Vector3::YAXIS );
1093  Quaternion q12( Radian( Degree( 240 ) ), Vector3::YAXIS );
1094  DALI_TEST_EQUALS( Quaternion::AngleBetween( q11, q12 ), fabsf( Radian( Degree( 1 - 240 + 360 ) ) ), 0.001f, TEST_LOCATION );
1095 
1096  Quaternion q13( Radian( Degree( 240 ) ), Vector3::YAXIS );
1097  Quaternion q14( Radian( Degree( 1 ) ), Vector3::YAXIS );
1098  DALI_TEST_EQUALS( Quaternion::AngleBetween( q13, q14 ), fabsf( Radian( Degree( 240 - 1 - 360 ) ) ), 0.001f, TEST_LOCATION );
1099 
1100  Quaternion q15( Radian( Degree( 240 ) ), Vector3::YAXIS );
1101  Quaternion q16( Radian( Degree( 1 ) ), Vector3::ZAXIS );
1103  END_TEST;
1104 }
1105 
1107 {
1108  std::ostringstream oss;
1109 
1110  Quaternion quaternion( Dali::ANGLE_180, Vector3::YAXIS );
1111 
1112  oss << quaternion;
1113 
1114  std::string expectedOutput = "[ Axis: [0, 1, 0], Angle: 180 degrees ]";
1115 
1116  DALI_TEST_EQUALS( oss.str(), expectedOutput, TEST_LOCATION );
1117  END_TEST;
1118 }
Dali Docs Home
Read more about Dali