2 * Copyright ( c ) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <dali-test-suite-utils.h>
19 #include <dali/public-api/dali-core.h>
27 void utc_dali_quaternion_startup(void)
29 test_return_value = TET_UNDEF;
32 void utc_dali_quaternion_cleanup(void)
34 test_return_value = TET_PASS;
37 int UtcDaliQuaternionCtorDefaultP(void)
40 DALI_TEST_EQUALS(q.AsVector().w, 1.0f, TEST_LOCATION);
41 DALI_TEST_EQUALS(q.AsVector().x, 0.0f, TEST_LOCATION);
42 DALI_TEST_EQUALS(q.AsVector().y, 0.0f, TEST_LOCATION);
43 DALI_TEST_EQUALS(q.AsVector().z, 0.0f, TEST_LOCATION);
47 int UtcDaliQuaternionCtorCosSinThetaP(void)
49 Quaternion q(1.0f, 0.1f, 0.2f, 0.3f);
51 DALI_TEST_EQUALS(q.AsVector().w, 1.0f, TEST_LOCATION);
52 DALI_TEST_EQUALS(q.AsVector().x, 0.1f, TEST_LOCATION);
53 DALI_TEST_EQUALS(q.AsVector().y, 0.2f, TEST_LOCATION);
54 DALI_TEST_EQUALS(q.AsVector().z, 0.3f, TEST_LOCATION);
58 int UtcDaliQuaternionCtorVector4P(void)
60 Quaternion q(Vector4(1.0f, 0.1f, 0.2f, 0.3f));
62 DALI_TEST_EQUALS(q.AsVector().x, 1.0f, TEST_LOCATION);
63 DALI_TEST_EQUALS(q.AsVector().y, 0.1f, TEST_LOCATION);
64 DALI_TEST_EQUALS(q.AsVector().z, 0.2f, TEST_LOCATION);
65 DALI_TEST_EQUALS(q.AsVector().w, 0.3f, TEST_LOCATION);
69 int UtcDaliQuaternionCtorAxisAngleVector3P(void)
71 Quaternion q(Dali::ANGLE_90, Vector3(1.0f, 2.0f, 3.0f));
73 // This will be normalised:
74 DALI_TEST_EQUALS(q.AsVector().w, 0.707f, 0.001, TEST_LOCATION);
75 DALI_TEST_EQUALS(q.AsVector().x, 0.189f, 0.001, TEST_LOCATION);
76 DALI_TEST_EQUALS(q.AsVector().y, 0.378f, 0.001, TEST_LOCATION);
77 DALI_TEST_EQUALS(q.AsVector().z, 0.567f, 0.001, TEST_LOCATION);
81 int UtcDaliQuaternionCtorEulerAngleP(void)
83 Quaternion q1(0.924f, 0.383f, 0.0f, 0.0f);
84 Vector4 r1(Radian(Degree(45)), 0.0f, 0.0f, 0.0f);
86 Quaternion q2(0.793f, 0.0f, 0.609f, 0.0f);
87 Vector4 r2(0.0f, Radian(Degree(75)), 0.0f, 0.0f);
89 Quaternion q3(0.383f, 0.0f, 0.0f, 0.924f);
90 Vector4 r3(0.0f, 0.0f, Radian(Degree(135)), 0.0f);
92 Quaternion q4(0.795f, 0.478f, 0.374f, 0.006f);
93 Vector4 r4(Radian(Degree(71)), Radian(Degree(36)), Radian(Degree(27)), 0.0f);
95 Quaternion q5(-0.149f, -0.697f, 0.145f, -0.686f);
96 Vector4 r5(Radian(Degree(148.0)), Radian(Degree(-88.2)), Radian(Degree(8.0)), 0.0f);
98 DALI_TEST_EQUALS(q1.EulerAngles(), r1, 0.001, TEST_LOCATION);
99 DALI_TEST_EQUALS(q2.EulerAngles(), r2, 0.001, TEST_LOCATION);
100 DALI_TEST_EQUALS(q3.EulerAngles(), r3, 0.001, TEST_LOCATION);
101 DALI_TEST_EQUALS(q4.EulerAngles(), r4, 0.01, TEST_LOCATION);
102 DALI_TEST_EQUALS(q5.EulerAngles(), r5, 0.01, TEST_LOCATION);
106 int UtcDaliQuaternionCtorMatrixP01(void)
108 // angle: 60 deg, axis: [1,2,3]
109 float Mref_raw[16] = {0.535714f, 0.765794f, -0.355767f, 0.0f, -0.622936f, 0.642857f, 0.445741f, 0.0f, 0.570053f, -0.0171693f, 0.821429f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
110 Matrix Mref(Mref_raw);
112 Quaternion q1(Radian(M_PI / 3.0f), Vector3(1.0f, 2.0f, 3.0f));
115 DALI_TEST_EQUALS(q1, q2, 0.001, TEST_LOCATION);
119 int UtcDaliQuaternionCtorMatrixP02(void)
124 Matrix m(q); // Convert to matrix
126 Quaternion q2(m); // and back to a quaternion
128 DALI_TEST_EQUALS(q, q2, 0.001, TEST_LOCATION);
129 DALI_TEST_EQUALS(m, Matrix::IDENTITY, 0.001f, TEST_LOCATION);
133 int UtcDaliQuaternionCtorMatrixP03(void)
135 // Create an arbitrary forward vector
136 for(float x = -1.0f; x <= 1.0f; x += 0.1f)
138 for(float y = -1.0f; y < 1.0f; y += 0.1f)
140 for(float z = -1.0f; z < 1.0f; z += 0.1f)
142 Vector3 vForward(x, y, z);
143 vForward.Normalize();
145 // Construct an up vector from a sideways move
147 Vector3 vUp = vForward.Cross(Vector3(vForward.x + 1.0f, vForward.y, vForward.z));
148 if(vUp.Length() > 0.01)
151 vSide = vUp.Cross(vForward);
156 vSide = vForward.Cross(Vector3(vForward.x, vForward.y + 1.0f, vForward.z));
158 vUp = vForward.Cross(vSide);
162 // Generate a matrix, and then a quaternion from it
163 Matrix rotMatrix(Matrix::IDENTITY);
164 rotMatrix.SetXAxis(vSide);
165 rotMatrix.SetYAxis(vUp);
166 rotMatrix.SetZAxis(vForward);
167 Quaternion q(rotMatrix);
169 // Generate a matrix from the quaternion, check they are the same
170 Matrix resultMatrix(q);
171 DALI_TEST_EQUALS(resultMatrix, rotMatrix, 0.001f, TEST_LOCATION);
173 // Rotate an arbitrary vector by both quaternion and rotation matrix,
174 // check the result is the same
176 Vector4 aVector(-2.983f, -3.213f, 8.2239f, 1.0f);
177 Vector3 aVectorRotatedByQ = q.Rotate(Vector3(aVector));
178 Vector4 aVectorRotatedByR = rotMatrix * aVector;
179 DALI_TEST_EQUALS(aVectorRotatedByQ, Vector3(aVectorRotatedByR), 0.001f, TEST_LOCATION);
186 int UtcDaliQuaternionCopyConstructor(void)
188 Quaternion q0(1.0f, 0.1f, 0.2f, 0.3f);
190 DALI_TEST_EQUALS(q1.AsVector().w, 1.0f, TEST_LOCATION);
191 DALI_TEST_EQUALS(q1.AsVector().x, 0.1f, TEST_LOCATION);
192 DALI_TEST_EQUALS(q1.AsVector().y, 0.2f, TEST_LOCATION);
193 DALI_TEST_EQUALS(q1.AsVector().z, 0.3f, TEST_LOCATION);
198 int UtcDaliQuaternionMoveConstructor(void)
200 Quaternion q0(1.0f, 0.1f, 0.2f, 0.3f);
201 Quaternion q1 = std::move(q0);
202 DALI_TEST_EQUALS(q1.AsVector().w, 1.0f, TEST_LOCATION);
203 DALI_TEST_EQUALS(q1.AsVector().x, 0.1f, TEST_LOCATION);
204 DALI_TEST_EQUALS(q1.AsVector().y, 0.2f, TEST_LOCATION);
205 DALI_TEST_EQUALS(q1.AsVector().z, 0.3f, TEST_LOCATION);
210 int UtcDaliQuaternionCopyAssignment(void)
212 Quaternion q0(1.0f, 0.1f, 0.2f, 0.3f);
215 DALI_TEST_EQUALS(q1.AsVector().w, 1.0f, TEST_LOCATION);
216 DALI_TEST_EQUALS(q1.AsVector().x, 0.1f, TEST_LOCATION);
217 DALI_TEST_EQUALS(q1.AsVector().y, 0.2f, TEST_LOCATION);
218 DALI_TEST_EQUALS(q1.AsVector().z, 0.3f, TEST_LOCATION);
223 int UtcDaliQuaternionMoveAssignment(void)
225 Quaternion q0(1.0f, 0.1f, 0.2f, 0.3f);
228 DALI_TEST_EQUALS(q1.AsVector().w, 1.0f, TEST_LOCATION);
229 DALI_TEST_EQUALS(q1.AsVector().x, 0.1f, TEST_LOCATION);
230 DALI_TEST_EQUALS(q1.AsVector().y, 0.2f, TEST_LOCATION);
231 DALI_TEST_EQUALS(q1.AsVector().z, 0.3f, TEST_LOCATION);
236 int UtcDaliQuaternionCtorAxesP01(void)
238 // angle: 60 deg, axis: [1,2,3]
239 float Mref_raw[16] = {0.535714f, 0.765794f, -0.355767f, 0.0f, -0.622936f, 0.642857f, 0.445741f, 0.0f, 0.570053f, -0.0171693f, 0.821429f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
240 Matrix Mref(Mref_raw);
242 Quaternion q1(Radian(M_PI / 3.0f), Vector3(1.0f, 2.0f, 3.0f));
243 Quaternion q2(Mref.GetXAxis(), Mref.GetYAxis(), Mref.GetZAxis());
245 DALI_TEST_EQUALS(q1, q2, 0.001, TEST_LOCATION);
249 int UtcDaliQuaternionCtorAxesP02(void)
251 Vector3 xAxis(Vector3::XAXIS);
252 Vector3 yAxis(Vector3::YAXIS);
253 Vector3 zAxis(Vector3::ZAXIS);
255 Quaternion q1(xAxis, yAxis, zAxis);
257 DALI_TEST_EQUALS(q1, Quaternion::IDENTITY, TEST_LOCATION);
259 xAxis = Vector3(1.0f, 1.0f, 0.0f);
261 yAxis = Vector3(-1.0f, 1.0f, 0.0f); // 45 degrees anticlockwise ( +ve ) around z
263 zAxis = xAxis.Cross(yAxis);
265 Quaternion q2(xAxis, yAxis, zAxis);
267 DALI_TEST_EQUALS(q2, Quaternion(Radian(Degree(45)), Vector3::ZAXIS), 0.001f, TEST_LOCATION);
271 int UtcDaliQuaternionCtorAxesP03(void)
273 // Create an arbitrary forward vector
274 for(float x = -1.0f; x <= 1.0f; x += 0.1f)
276 for(float y = -1.0f; y < 1.0f; y += 0.1f)
278 for(float z = -1.0f; z < 1.0f; z += 0.1f)
280 Vector3 vForward(x, y, z);
281 vForward.Normalize();
283 // Construct an up vector from a sideways move
285 Vector3 vUp = vForward.Cross(Vector3(vForward.x + 1.0f, vForward.y, vForward.z));
286 if(vUp.Length() > 0.01)
289 vSide = vUp.Cross(vForward);
294 vSide = vForward.Cross(Vector3(vForward.x, vForward.y + 1.0f, vForward.z));
296 vUp = vForward.Cross(vSide);
300 // Generate a quaternion
301 Quaternion q(vSide, vUp, vForward);
304 rotMatrix.SetXAxis(vSide);
305 rotMatrix.SetYAxis(vUp);
306 rotMatrix.SetZAxis(vForward);
308 // Generate a matrix from the quaternion, check they are the same
310 DALI_TEST_EQUALS(m.GetXAxis(), vSide, 0.001f, TEST_LOCATION);
311 DALI_TEST_EQUALS(m.GetYAxis(), vUp, 0.001f, TEST_LOCATION);
312 DALI_TEST_EQUALS(m.GetZAxis(), vForward, 0.001f, TEST_LOCATION);
314 // Rotate an arbitrary vector by both quaternion and rotation matrix,
315 // check the result is the same
317 Vector4 aVector(2.043f, 12.8f, -3.872f, 1.0f);
318 Vector3 aVectorRotatedByQ = q.Rotate(Vector3(aVector));
319 Vector4 aVectorRotatedByR = rotMatrix * aVector;
320 DALI_TEST_EQUALS(aVectorRotatedByQ, Vector3(aVectorRotatedByR), 0.001f, TEST_LOCATION);
327 int UtcDaliQuaternionCtorTwoVectorsP(void)
329 Vector3 v0(1.0f, 2.0f, 3.0f);
330 Vector3 v1(-2.0f, 10.0f, -1.0f);
333 Quaternion q(v0, v1);
335 DALI_TEST_EQUALS(q * v0, v1, 0.001, TEST_LOCATION);
339 int UtcDaliQuaternionAsVectorP(void)
341 Vector4 v(1.0f, 0.1f, 0.2f, 0.3f);
344 DALI_TEST_EQUALS(v, q.AsVector(), TEST_LOCATION);
348 int UtcDaliQuaternionToAxisAngleVector3P(void)
350 Quaternion q(0.932f, 1.1f, 3.4f, 2.7f);
353 bool converted = q.ToAxisAngle(axis, angle);
354 DALI_TEST_EQUALS(converted, true, TEST_LOCATION);
355 DALI_TEST_EQUALS(angle.radian, 0.74f, 0.01f, TEST_LOCATION);
356 DALI_TEST_EQUALS(axis.x, 3.03f, 0.01f, TEST_LOCATION);
357 DALI_TEST_EQUALS(axis.y, 9.38f, 0.01f, TEST_LOCATION);
358 DALI_TEST_EQUALS(axis.z, 7.45f, 0.01f, TEST_LOCATION);
362 int UtcDaliQuaternionToAxisAngleVector3N(void)
364 Quaternion q(1, 2, 3, 4);
367 bool converted = q.ToAxisAngle(axis, angle);
368 DALI_TEST_EQUALS(converted, false, TEST_LOCATION);
369 DALI_TEST_EQUALS(angle.radian, 0.0f, 0.01f, TEST_LOCATION);
370 DALI_TEST_EQUALS(axis.x, 0.0f, 0.01f, TEST_LOCATION);
371 DALI_TEST_EQUALS(axis.y, 0.0f, 0.01f, TEST_LOCATION);
372 DALI_TEST_EQUALS(axis.z, 0.0f, 0.01f, TEST_LOCATION);
376 int UtcDaliQuaternionSetEulerP(void)
378 // Test from euler angles
380 e1.SetEuler(Dali::ANGLE_45, Dali::ANGLE_0, Dali::ANGLE_0);
381 Vector4 r1(0.383f, 0.0f, 0.0f, 0.924f);
384 e2.SetEuler(Dali::ANGLE_0, Radian(Degree(75)), Dali::ANGLE_0);
385 Vector4 r2(0.0f, 0.609f, 0.0f, 0.793f);
388 e3.SetEuler(Dali::ANGLE_0, Dali::ANGLE_0, Radian(Degree(135)));
389 Vector4 r3(0.0f, 0.0f, 0.924f, 0.383f);
392 e4.SetEuler(Radian(Degree(71)), Radian(Degree(36)), Radian(Degree(27)));
393 Vector4 r4(0.478f, 0.374f, 0.006f, 0.795f);
396 e5.SetEuler(Radian(Degree(-31)), Radian(Degree(-91)), Radian(Degree(-173)));
397 Vector4 r5(-0.697f, 0.145f, -0.686f, -0.149f);
399 DALI_TEST_EQUALS(e1.AsVector(), r1, 0.001, TEST_LOCATION);
400 DALI_TEST_EQUALS(e2.AsVector(), r2, 0.001, TEST_LOCATION);
401 DALI_TEST_EQUALS(e3.AsVector(), r3, 0.001, TEST_LOCATION);
402 DALI_TEST_EQUALS(e4.AsVector(), r4, 0.001, TEST_LOCATION);
403 DALI_TEST_EQUALS(e5.AsVector(), r5, 0.001, TEST_LOCATION);
407 int UtcDaliQuaternionEulerAnglesP(void)
409 Quaternion q1(0.924f, 0.383f, 0.0f, 0.0f);
410 Vector4 r1(Radian(Degree(45)), 0.0f, 0.0f, 0.0f);
412 Quaternion q2(0.793f, 0.0f, 0.609f, 0.0f);
413 Vector4 r2(0.0f, Radian(Degree(75)), 0.0f, 0.0f);
415 Quaternion q3(0.383f, 0.0f, 0.0f, 0.924f);
416 Vector4 r3(0.0f, 0.0f, Radian(Degree(135)), 0.0f);
418 Quaternion q4(0.795f, 0.478f, 0.374f, 0.006f);
419 Vector4 r4(Radian(Degree(71)), Radian(Degree(36)), Radian(Degree(27)), 0.0f);
421 Quaternion q5(-0.149f, -0.697f, 0.145f, -0.686f);
422 Vector4 r5(Radian(Degree(148.0)), Radian(Degree(-88.2)), Radian(Degree(8.0)), 0.0f);
424 DALI_TEST_EQUALS(q1.EulerAngles(), r1, 0.001, TEST_LOCATION);
425 DALI_TEST_EQUALS(q2.EulerAngles(), r2, 0.001, TEST_LOCATION);
426 DALI_TEST_EQUALS(q3.EulerAngles(), r3, 0.001, TEST_LOCATION);
427 DALI_TEST_EQUALS(q4.EulerAngles(), r4, 0.01, TEST_LOCATION);
428 DALI_TEST_EQUALS(q5.EulerAngles(), r5, 0.01, TEST_LOCATION);
432 int UtcDaliQuaternionToMatrixP01(void)
434 Quaternion q(Radian(0.69813), Vector3(1.0f, 0.0f, 0.0f)); // 40 degree rotation around X axis
436 // Result calculated using a different maths library ( with appropriate row/col ordering )
438 float els[] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.766f, 0.643f, 0.0f, 0.0f, -0.643f, 0.766f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
442 DALI_TEST_EQUALS(m, mRes, 0.01, TEST_LOCATION);
446 int UtcDaliQuaternionToMatrixP02(void)
448 // rotation around arbitrary axis
449 Quaternion q2(Radian(-1.23918f), Vector3(7.0f, -13.0f, 11.0f));
451 float els[] = {0.423f, -0.746f, -0.514f, 0.00f, 0.384f, 0.662f, -0.644f, 0.00f, 0.821f, 0.075f, 0.566f, 0.00f, 0.000f, 0.000f, 0.000f, 1.00f};
456 DALI_TEST_EQUALS(m2, mRes2, 0.01, TEST_LOCATION);
460 int UtcDaliQuaternionOperatorAdditionP(void)
462 Quaternion q1(0.383f, 0.0f, 0.0f, 0.924f);
463 Quaternion q2(0.0f, 0.609f, 0.0f, 0.793f);
465 Quaternion r1(0.383f, 0.609f, 0.0f, 1.717f);
467 DALI_TEST_EQUALS(q1 + q2, r1, 0.001f, TEST_LOCATION);
471 int UtcDaliQuaternionOperatorSubtractionP(void)
473 Quaternion q1(0.383f, 0.450f, 0.123f, 0.924f);
474 Quaternion q2(0.383f, 0.690f, 0.234f, 1.917f);
476 Quaternion r1(0.0f, 0.240f, 0.111f, 0.993f);
478 DALI_TEST_EQUALS(q2 - q1, r1, 0.001f, TEST_LOCATION);
482 int UtcDaliQuaternionConjugateP(void)
485 Vector3 v1(0.045f, 0.443f, 0.432f);
487 Vector3 v2(0.612, 0.344, -0.144);
489 Quaternion q1(s1, v1.x, v1.y, v1.z);
490 Quaternion q2(s2, v2.x, v2.y, v2.z);
494 Quaternion r1(s1, -v1.x, -v1.y, -v1.z);
495 Quaternion r2(s2, -v2.x, -v2.y, -v2.z);
497 DALI_TEST_EQUALS(q1, r1, 0.001f, TEST_LOCATION);
498 DALI_TEST_EQUALS(q2, r2, 0.001f, TEST_LOCATION);
502 int UtcDaliQuaternionOperatorMultiplicationQuaternionP(void)
505 Vector3 v1(0.045f, 0.443f, 0.432f);
507 Vector3 v2(0.612, 0.344, -0.144);
509 Quaternion q1(s1, v1.x, v1.y, v1.z);
510 Quaternion q2(s2, v2.x, v2.y, v2.z);
512 Vector3 vp = v1.Cross(v2) + v2 * s1 + v1 * s2;
513 Quaternion r1(s1 * s2 - v1.Dot(v2), vp.x, vp.y, vp.z);
515 DALI_TEST_EQUALS(q1 * q2, r1, 0.001f, TEST_LOCATION);
519 // Quaternion * vector == Vector rotation
520 int UtcDaliQuaternionOperatorMultiplicationVector3P(void)
522 // Rotation of vector p = ( x,y,z ) by Quaternion q == q [0,p] q^-1
524 Quaternion q(Radian(Degree(72)), Vector3::ZAXIS);
527 Quaternion qv(0.0f, v.x, v.y, v.z);
528 Quaternion r1 = (q * qv) * qI;
532 DALI_TEST_EQUALS(r1.mVector.x, r2.x, 0.001, TEST_LOCATION);
533 DALI_TEST_EQUALS(r1.mVector.y, r2.y, 0.001, TEST_LOCATION);
534 DALI_TEST_EQUALS(r1.mVector.z, r2.z, 0.001, TEST_LOCATION);
538 int UtcDaliQuaternionOperatorMultiplicationFloatP01(void)
540 // Rotation of vector p = ( x,y,z ) by Quaternion q == q [0,p] q^-1
541 Quaternion q(Vector4(0.1f, 0.2f, 0.3f, 1.0f));
542 Quaternion q2 = q * 2.f;
543 Vector4 v2(0.2f, 0.4f, 0.6f, 2.0f);
545 DALI_TEST_EQUALS(q2.AsVector(), v2, 0.001, TEST_LOCATION);
549 int UtcDaliQuaternionOperatorMultiplicationFloatP02(void)
551 Quaternion q1(0.383f, 0.0f, 0.0f, 0.924f);
552 Quaternion r1(2.0f * 0.383f, 0.0f, 0.0f, 2.0f * 0.924f);
554 DALI_TEST_EQUALS(q1 * 2.0f, r1, 0.001f, TEST_LOCATION);
558 int UtcDaliQuaternionOperatorMultiplicationFloatP03(void)
560 Quaternion q1(0.383f, 0.0f, 0.0f, 0.924f);
561 Quaternion r1(0.5f * 0.383f, 0.0f, 0.0f, 0.5f * 0.924f);
563 DALI_TEST_EQUALS(q1 / 2.0f, r1, 0.001f, TEST_LOCATION);
567 int UtcDaliQuaternionOperatorDivisionQuaternionP(void)
569 Quaternion q1(0.383f, 0.0f, 0.0f, 0.924f);
570 Quaternion q2(0.0f, 0.609f, 0.0f, 0.793f);
572 // q1 / q2 = q1 * q2^-1
573 // q2^-1 = q2* / ||q2||^2
574 // = Conjugate of q2 / Square of Norm of q2
578 r1 *= 1.0f / q2.LengthSquared();
579 Quaternion r2 = q1 * r1;
581 DALI_TEST_EQUALS(q1 / q2, r2, 0.001f, TEST_LOCATION);
585 int UtcDaliQuaternionOperatorDivisionFloatP(void)
587 Quaternion q1(0.383f, 0.0f, 0.0f, 0.924f);
588 Quaternion r1(2.0f * 0.383f, 0.0f, 0.0f, 2.0f * 0.924f);
590 DALI_TEST_EQUALS(q1, r1 / 2.0f, 0.001f, TEST_LOCATION);
594 int UtcDaliQuaternionOperatorDivideAssignedFloatP(void)
596 Quaternion q1(0.383f, 0.0f, 0.0f, 0.924f);
597 Quaternion r1(2.0f * 0.383f, 0.0f, 0.0f, 2.0f * 0.924f);
600 DALI_TEST_EQUALS(q1, r1, 0.001f, TEST_LOCATION);
604 int UtcDaliQuaternionOperatorNegationP(void)
606 Quaternion q1(0.383f, 0.0f, 0.0f, 0.924f);
607 Quaternion r1(-0.383f, -0.0f, -0.0f, -0.924f);
609 DALI_TEST_EQUALS(-q1, r1, 0.001f, TEST_LOCATION);
613 int UtcDaliQuaternionOperatorAddAssignP(void)
615 Quaternion q1(0.383f, 0.0f, 0.0f, 0.924f);
616 Quaternion q2(0.0f, 0.609f, 0.0f, 0.793f);
618 Quaternion r1(0.383f, 0.609f, 0.0f, 1.717f);
621 DALI_TEST_EQUALS(q1, r1, 0.001f, TEST_LOCATION);
625 int UtcDaliQuaternionOperatorSubtractAssignP(void)
627 Quaternion q1(0.383f, 0.450f, 0.123f, 0.924f);
628 Quaternion q2(0.383f, 0.690f, 0.234f, 1.917f);
630 Quaternion r1(0.0f, 0.240f, 0.111f, 0.993f);
632 DALI_TEST_EQUALS(q2, r1, 0.001f, TEST_LOCATION);
636 int UtcDaliQuaternionOperatorMultiplyAssignQuaternionP(void)
639 Vector3 v1(0.045f, 0.443f, 0.432f);
641 Vector3 v2(0.612, 0.344, -0.144);
643 Quaternion q1(s1, v1.x, v1.y, v1.z);
644 Quaternion q2(s2, v2.x, v2.y, v2.z);
646 Quaternion r3 = q2 * q1;
648 DALI_TEST_EQUALS(q2, r3, 0.001f, TEST_LOCATION);
652 int UtcDaliQuaternionOperatorMultiplyAssignFloatP01(void)
654 Quaternion q1(0.383f, 0.450f, 0.123f, 0.924f);
656 Quaternion r1(scale * 0.383f, scale * 0.450f, scale * 0.123f, scale * 0.924f);
658 DALI_TEST_EQUALS(q1, r1, 0.001f, TEST_LOCATION);
662 int UtcDaliQuaternionOperatorMultiplyAssignFloatP02(void)
664 Quaternion q1(0.383f, 0.450f, 0.123f, 0.924f);
666 Quaternion r1(0.383f / scale, 0.450f / scale, 0.123f / scale, 0.924f / scale);
668 DALI_TEST_EQUALS(q1, r1, 0.001f, TEST_LOCATION);
672 int UtcDaliQuaternionOperatorEqualityP(void)
674 Quaternion q1(0.383f, 0.450f, 0.123f, 0.924f);
675 Quaternion q2(0.383f, 0.450f, 0.123f, 0.924f);
676 Quaternion q3(0.383f, 0.450f, 0.123f, 0.800f);
677 Quaternion q4(0.383f, 0.450f, 0.100f, 0.800f);
678 Quaternion q5(0.383f, 0.100f, 0.100f, 0.800f);
679 Quaternion q6(0.100f, 0.100f, 0.100f, 0.800f);
681 Quaternion q7(-0.383f, -0.450f, -0.123f, -0.924f);
682 Quaternion q8(-0.383f, -0.450f, -0.123f, 0.924f);
683 Quaternion q9(-0.383f, -0.450f, 0.123f, 0.924f);
684 Quaternion q10(-0.383f, 0.450f, 0.123f, 0.924f);
686 DALI_TEST_CHECK(q1 == q2);
687 DALI_TEST_CHECK(!(q1 == q3));
688 DALI_TEST_CHECK(!(q1 == q4));
689 DALI_TEST_CHECK(!(q1 == q5));
690 DALI_TEST_CHECK(!(q1 == q6));
691 DALI_TEST_CHECK((q1 == q7));
692 DALI_TEST_CHECK(!(q1 == q8));
693 DALI_TEST_CHECK(!(q1 == q9));
694 DALI_TEST_CHECK(!(q1 == q10));
698 int UtcDaliQuaternionOperatorInequalityP(void)
700 Quaternion q1(0.383f, 0.450f, 0.123f, 0.924f);
701 Quaternion q2(0.383f, 0.450f, 0.123f, 0.924f);
702 Quaternion q3(-0.383f, -0.0f, -0.0f, -0.924f);
703 DALI_TEST_CHECK(!(q1 != q2));
704 DALI_TEST_CHECK(q1 != q3);
708 int UtcDaliQuaternionLengthP(void)
710 Quaternion q1(0.383f, 0.450f, 0.123f, 0.924f);
711 float length = sqrtf(0.383f * 0.383f + 0.450f * 0.450f + 0.123f * 0.123f + 0.924f * 0.924f);
712 DALI_TEST_EQUALS(q1.Length(), length, 0.001f, TEST_LOCATION);
716 int UtcDaliQuaternionLengthSquaredP(void)
718 Quaternion q1(0.383f, 0.450f, 0.123f, 0.924f);
719 float lengthSquared = 0.383f * 0.383f + 0.450f * 0.450f + 0.123f * 0.123f + 0.924f * 0.924f;
720 DALI_TEST_EQUALS(q1.LengthSquared(), lengthSquared, 0.01f, TEST_LOCATION);
724 int UtcDaliQuaternionNormalizeP(void)
726 Quaternion q1(0.118f, 0.692f, -0.127f, 0.701f);
730 DALI_TEST_EQUALS(q1, q2, 0.001f, TEST_LOCATION);
734 int UtcDaliQuaternionNormalizedP(void)
736 Quaternion q1(0.118f, 0.692f, -0.127f, 0.701f);
739 DALI_TEST_EQUALS(q1, q2.Normalized(), 0.001f, TEST_LOCATION);
743 int UtcDaliQuaternionIsIdentityP(void)
745 Quaternion q(1.0f, 0.0f, 0.0f, 0.0f);
746 DALI_TEST_EQUALS(q.IsIdentity(), true, TEST_LOCATION);
750 int UtcDaliQuaternionIsIdentityN(void)
752 Quaternion q(1.0f, 0.1f, 0.0f, 0.0f);
753 DALI_TEST_EQUALS(q.IsIdentity(), false, TEST_LOCATION);
757 int UtcDaliQuaternionInvertP(void)
759 Quaternion q1(0.383f, 0.0f, 0.0f, 0.924f);
761 // q1^-1 = q1* / ||q1||^2
762 // = Conjugate of q1 / Square of Norm of q1
766 r1 *= 1.0f / q1.LengthSquared();
770 DALI_TEST_EQUALS(q2, r1, 0.001f, TEST_LOCATION);
774 int UtcDaliQuaternionDotP(void)
776 // q.q' = s*s' + v dot v'
778 Vector3 v1(0.045f, 0.443f, 0.432f);
780 Vector3 v2(0.612, 0.344, -0.144);
782 Quaternion q1(s1, v1.x, v1.y, v1.z);
783 Quaternion q2(s2, v2.x, v2.y, v2.z);
785 float r1 = s1 * s2 + v1.Dot(v2);
787 DALI_TEST_EQUALS(Quaternion::Dot(q1, q2), r1, TEST_LOCATION);
791 int UtcDaliQuaternionRotateVector3P(void)
793 // Rotation of vector p = ( x,y,z ) by Quaternion q == q [0,p] q^-1
795 Quaternion q(Radian(Degree(72)), Vector3::ZAXIS);
798 Quaternion qv(0.0f, v.x, v.y, v.z);
799 Quaternion r1 = q * qv * qI;
801 Vector3 r2 = q.Rotate(v);
803 DALI_TEST_EQUALS(r1.mVector.x, r2.x, 0.001f, TEST_LOCATION);
804 DALI_TEST_EQUALS(r1.mVector.y, r2.y, 0.001f, TEST_LOCATION);
805 DALI_TEST_EQUALS(r1.mVector.z, r2.z, 0.001f, TEST_LOCATION);
807 DALI_TEST_EQUALS(q.Rotate(v), q * v, 0.001f, TEST_LOCATION);
811 int UtcDaliQuaternionRotateVector4P(void)
813 // Rotation of vector p = ( x,y,z ) by Quaternion q == q [0,p] q^-1
814 Vector4 v(2, 3, 4, 5);
815 Quaternion q(Radian(Degree(72)), Vector3::ZAXIS);
818 Quaternion qv(0.0f, v.x, v.y, v.z);
819 Quaternion r1 = q * qv * qI;
821 Vector4 r2 = q.Rotate(v);
823 DALI_TEST_EQUALS(r1.mVector.x, r2.x, 0.001f, TEST_LOCATION);
824 DALI_TEST_EQUALS(r1.mVector.y, r2.y, 0.001f, TEST_LOCATION);
825 DALI_TEST_EQUALS(r1.mVector.z, r2.z, 0.001f, TEST_LOCATION);
826 DALI_TEST_EQUALS(r1.mVector.w, 0.0f, 0.001f, TEST_LOCATION);
830 int UtcDaliQuaternionExpP01(void)
832 Quaternion q1(0.0f, 1.0f, 1.2f, 1.3f);
833 Quaternion q2 = q1.Exp();
834 Quaternion r2(-0.4452, 0.4406, 0.5287, 0.5728);
836 DALI_TEST_EQUALS(q2.Length(), 1.0f, 0.01f, TEST_LOCATION);
838 DALI_TEST_EQUALS(q2, r2, 0.001f, TEST_LOCATION);
840 // Note, this trick only works when |v| < pi, which it is!
841 Quaternion q3 = q2.Log();
842 DALI_TEST_EQUALS(q1, q3, 0.01f, TEST_LOCATION);
846 int UtcDaliQuaternionExpP02(void)
848 Quaternion q1(0.0f, 0.0f, 0.0f, 0.0f);
849 Quaternion q2 = q1.Exp();
850 Quaternion r2(1.0f, 0.0f, 0.0f, 0.0f);
852 DALI_TEST_EQUALS(q2.Length(), 1.0f, 0.01f, TEST_LOCATION);
854 DALI_TEST_EQUALS(q2, r2, 0.001f, TEST_LOCATION);
856 // Note, this trick only works when |v| < pi, which it is!
857 Quaternion q3 = q2.Log();
858 DALI_TEST_EQUALS(q1, q3, 0.01f, TEST_LOCATION);
862 int UtcDaliQuaternionExpN(void)
864 Quaternion q(Radian(0.0f), Vector3(5.0f, 6.0f, 7.0f));
866 // q.w is non-zero. Should assert.
870 DALI_TEST_CHECK(false);
872 catch(DaliException& e)
874 DALI_TEST_CHECK(true);
879 int UtcDaliQuaternionLogP01(void)
881 Quaternion q(Radian(Math::PI * 0.73f), Vector3(2, 3, 4));
885 Quaternion r = q2.Log();
886 DALI_TEST_EQUALS(r.mVector.w, 0.0f, 0.01f, TEST_LOCATION);
888 Quaternion r2 = r.Exp();
889 DALI_TEST_EQUALS(r2, q2, 0.01f, TEST_LOCATION);
893 int UtcDaliQuaternionLogP02(void)
895 Quaternion q1(1.0f, 0.0f, 0.0f, 0.0f);
896 Quaternion r1(0.0f, 0.0f, 0.0f, 0.0f);
898 Quaternion q2 = q1.Log();
900 DALI_TEST_EQUALS(q2, r1, 0.01f, TEST_LOCATION);
902 Quaternion q3 = q2.Exp();
903 DALI_TEST_EQUALS(q1, q3, 0.01f, TEST_LOCATION);
907 int UtcDaliQuaternionLerpP(void)
909 Quaternion q1(Radian(Degree(-80)), Vector3(0.0f, 0.0f, 1.0f));
910 Quaternion q2(Radian(Degree(80)), Vector3(0.0f, 0.0f, 1.0f));
912 Quaternion p = Quaternion::Lerp(q1, q2, 0.0f);
913 DALI_TEST_EQUALS(p, q1, 0.001f, TEST_LOCATION);
915 p = Quaternion::Lerp(q1, q2, 1.0f);
916 DALI_TEST_EQUALS(p, q2, 0.001f, TEST_LOCATION);
918 p = Quaternion::Lerp(q1, q2, 0.5f);
919 Quaternion r1 = (q1 + q2) * 0.5f;
921 DALI_TEST_EQUALS(p, r1, 0.001f, TEST_LOCATION);
925 int UtcDaliQuaternionSlerpP01(void)
927 Quaternion q1(Radian(M_PI / 4.0f), Vector3(0.0f, 0.0f, 1.0f));
928 Quaternion q2(Radian(-M_PI / 4.0f), Vector3(0.0f, 0.0f, 1.0f));
930 Quaternion q = Quaternion::Slerp(q1, q2, 0.0f);
931 DALI_TEST_EQUALS(q, q1, 0.001, TEST_LOCATION);
933 q = Quaternion::Slerp(q1, q2, 1.0f);
934 DALI_TEST_EQUALS(q, q2, 0.001, TEST_LOCATION);
936 // @ 25%, will be at M_PI/8
937 q = Quaternion::Slerp(q1, q2, 0.25f);
940 bool converted = q.ToAxisAngle(axis, angle);
941 DALI_TEST_EQUALS(converted, true, TEST_LOCATION);
942 DALI_TEST_EQUALS(angle.radian, Math::PI / 8.0f, 0.001, TEST_LOCATION);
943 DALI_TEST_EQUALS(axis.x, 0.0f, 0.001, TEST_LOCATION);
944 DALI_TEST_EQUALS(axis.y, 0.0f, 0.001, TEST_LOCATION);
945 DALI_TEST_EQUALS(axis.z, 1.0f, 0.001, TEST_LOCATION);
949 int UtcDaliQuaternionSlerpP02(void)
951 Quaternion q1(Dali::ANGLE_30, Vector3(0.0f, 0.0f, 1.0f));
952 Quaternion q2(Dali::ANGLE_90, Vector3(0.0f, 0.0f, 1.0f));
954 Quaternion q = Quaternion::Slerp(q1, q2, 0.0f);
956 DALI_TEST_EQUALS(q, q1, 0.001, TEST_LOCATION);
958 q = Quaternion::Slerp(q1, q2, 1.0f);
960 DALI_TEST_EQUALS(q, q2, 0.001, TEST_LOCATION);
962 // @ 50%, will be at M_PI/3 around z
963 q = Quaternion::Slerp(q1, q2, 0.5f);
965 Quaternion r(Dali::ANGLE_60, Vector3(0.0f, 0.0f, 1.0f));
966 DALI_TEST_EQUALS(q, r, 0.001, TEST_LOCATION);
970 int UtcDaliQuaternionSlerpP03(void)
972 Quaternion q1(Radian(Degree(125)), Vector3(0.0f, 0.0f, 1.0f));
973 Quaternion q2(Radian(Degree(-125)), Vector3(0.002f, 0.001f, 1.001f));
975 Quaternion q = Quaternion::Slerp(q1, q2, 0.0f);
976 DALI_TEST_EQUALS(q, q1, 0.001, TEST_LOCATION);
978 q = Quaternion::Slerp(q1, q2, 1.0f);
979 DALI_TEST_EQUALS(q, q2, 0.001, TEST_LOCATION);
981 q = Quaternion::Slerp(q1, q2, 0.05f);
984 bool converted = q.ToAxisAngle(axis, angle);
985 DALI_TEST_EQUALS(converted, true, TEST_LOCATION);
987 DALI_TEST_EQUALS(axis.x, 0.0f, 0.01, TEST_LOCATION);
988 DALI_TEST_EQUALS(axis.y, 0.0f, 0.01, TEST_LOCATION);
989 DALI_TEST_EQUALS(axis.z, 1.0f, 0.01, TEST_LOCATION);
993 int UtcDaliQuaternionSlerpP04(void)
995 Quaternion q1(Radian(Degree(120)), Vector3(0.0f, 0.0f, 1.0f));
996 Quaternion q2(Radian(Degree(130)), Vector3(0.0f, 0.0f, 1.0f));
998 Quaternion q = Quaternion::Slerp(q1, q2, 0.0f);
999 DALI_TEST_EQUALS(q, q1, 0.001, TEST_LOCATION);
1001 q = Quaternion::Slerp(q1, q2, 1.0f);
1002 DALI_TEST_EQUALS(q, q2, 0.001, TEST_LOCATION);
1004 q = Quaternion::Slerp(q1, q2, 0.5f);
1007 bool converted = q.ToAxisAngle(axis, angle);
1008 DALI_TEST_EQUALS(converted, true, TEST_LOCATION);
1009 DALI_TEST_EQUALS(angle.radian, float(Radian(Degree(125))), 0.01f, TEST_LOCATION);
1010 DALI_TEST_EQUALS(axis.x, 0.0f, 0.01, TEST_LOCATION);
1011 DALI_TEST_EQUALS(axis.y, 0.0f, 0.01, TEST_LOCATION);
1012 DALI_TEST_EQUALS(axis.z, 1.0f, 0.01, TEST_LOCATION);
1016 int UtcDaliQuaternionSlerpNoInvertP01(void)
1018 Quaternion q1(Dali::ANGLE_45, Vector3(0.0f, 0.0f, 1.0f));
1019 Quaternion q2(-Dali::ANGLE_45, Vector3(0.0f, 0.0f, 1.0f));
1021 Quaternion q = Quaternion::SlerpNoInvert(q1, q2, 0.0f);
1022 DALI_TEST_EQUALS(q, q1, 0.001, TEST_LOCATION);
1024 q = Quaternion::SlerpNoInvert(q1, q2, 1.0f);
1025 DALI_TEST_EQUALS(q, q2, 0.001, TEST_LOCATION);
1027 // @ 25%, will be at M_PI/8
1028 q = Quaternion::SlerpNoInvert(q1, q2, 0.25f);
1031 bool converted = q.ToAxisAngle(axis, angle);
1032 DALI_TEST_EQUALS(converted, true, TEST_LOCATION);
1033 DALI_TEST_EQUALS(angle.radian, Math::PI / 8.0f, 0.001, TEST_LOCATION);
1034 DALI_TEST_EQUALS(axis.x, 0.0f, 0.001, TEST_LOCATION);
1035 DALI_TEST_EQUALS(axis.y, 0.0f, 0.001, TEST_LOCATION);
1036 DALI_TEST_EQUALS(axis.z, 1.0f, 0.001, TEST_LOCATION);
1040 int UtcDaliQuaternionSlerpNoInvertP02(void)
1042 Quaternion q1(Radian(Degree(120)), Vector3(0.0f, 0.0f, 1.0f));
1043 Quaternion q2(Radian(Degree(130)), Vector3(0.0f, 0.0f, 1.0f));
1045 Quaternion q = Quaternion::SlerpNoInvert(q1, q2, 0.0f);
1046 DALI_TEST_EQUALS(q, q1, 0.001, TEST_LOCATION);
1048 q = Quaternion::SlerpNoInvert(q1, q2, 1.0f);
1049 DALI_TEST_EQUALS(q, q2, 0.001, TEST_LOCATION);
1051 q = Quaternion::SlerpNoInvert(q1, q2, 0.5f);
1054 bool converted = q.ToAxisAngle(axis, angle);
1055 DALI_TEST_EQUALS(converted, true, TEST_LOCATION);
1056 DALI_TEST_EQUALS(angle.radian, float(Radian(Degree(125))), 0.01f, TEST_LOCATION);
1057 DALI_TEST_EQUALS(axis.x, 0.0f, 0.01, TEST_LOCATION);
1058 DALI_TEST_EQUALS(axis.y, 0.0f, 0.01, TEST_LOCATION);
1059 DALI_TEST_EQUALS(axis.z, 1.0f, 0.01, TEST_LOCATION);
1063 int UtcDaliQuaternionSquadP(void)
1065 Quaternion q1(Radian(Degree(45)), Vector3(0.0f, 0.0f, 1.0f));
1066 Quaternion q1out(Radian(Degree(40)), Vector3(0.0f, 1.0f, 2.0f));
1067 Quaternion q2in(Radian(Degree(35)), Vector3(0.0f, 2.0f, 3.0f));
1068 Quaternion q2(Radian(Degree(30)), Vector3(0.0f, 1.0f, 3.0f));
1070 Quaternion q = Quaternion::Squad(q1, q2, q1out, q2in, 0.0f);
1071 DALI_TEST_EQUALS(q, q1, 0.001f, TEST_LOCATION);
1073 q = Quaternion::Squad(q1, q2, q1out, q2in, 1.0f);
1074 DALI_TEST_EQUALS(q, q2, 0.001f, TEST_LOCATION);
1076 // Don't know what actual value should be, but can make some informed guesses.
1077 q = Quaternion::Squad(q1, q2, q1out, q2in, 0.5f);
1081 q.ToAxisAngle(axis, angle);
1085 q = -q; // Might get negative quat
1086 q.ToAxisAngle(axis, angle);
1088 float deg = Degree(angle).degree;
1089 DALI_TEST_CHECK(deg >= 0 && deg <= 90);
1090 DALI_TEST_CHECK(axis.y > 0);
1091 DALI_TEST_CHECK(axis.z > 0);
1095 int UtcDaliAngleBetweenP(void)
1097 Quaternion q1(ANGLE_45, ANGLE_0, ANGLE_0);
1098 Quaternion q2(Radian(Degree(47)), ANGLE_0, ANGLE_0);
1099 DALI_TEST_EQUALS(Quaternion::AngleBetween(q1, q2), fabsf(Radian(Degree(45)) - Radian(Degree(47))), 0.001f, TEST_LOCATION);
1101 Quaternion q3(Radian(Degree(80)), Vector3::YAXIS);
1102 Quaternion q4(Radian(Degree(90)), Vector3::YAXIS);
1103 DALI_TEST_EQUALS(Quaternion::AngleBetween(q3, q4), fabsf(Radian(Degree(80)) - Radian(Degree(90))), 0.001f, TEST_LOCATION);
1105 Quaternion q5(Radian(Degree(0)), Vector3::YAXIS);
1106 Quaternion q6(Radian(Degree(90)), Vector3::XAXIS);
1107 DALI_TEST_EQUALS(Quaternion::AngleBetween(q5, q6), fabsf(Radian(Degree(0)) - Radian(Degree(90))), 0.001f, TEST_LOCATION);
1109 Quaternion q7(Radian(Degree(0)), Vector3::YAXIS);
1110 Quaternion q8(Radian(Degree(0)), Vector3::XAXIS);
1111 DALI_TEST_EQUALS(Quaternion::AngleBetween(q7, q8), fabsf(Radian(Degree(0)) - Radian(Degree(0))), 0.001f, TEST_LOCATION);
1113 Quaternion q9(Radian(Degree(0)), Vector3::XAXIS);
1114 Quaternion q10(Radian(Degree(180)), Vector3::XAXIS);
1115 DALI_TEST_EQUALS(Quaternion::AngleBetween(q9, q10), fabsf(Radian(Degree(0)) - Radian(Degree(180))), 0.001f, TEST_LOCATION);
1117 Quaternion q11(Radian(Degree(1)), Vector3::YAXIS);
1118 Quaternion q12(Radian(Degree(240)), Vector3::YAXIS);
1119 DALI_TEST_EQUALS(Quaternion::AngleBetween(q11, q12), fabsf(Radian(Degree(1 - 240 + 360))), 0.001f, TEST_LOCATION);
1121 Quaternion q13(Radian(Degree(240)), Vector3::YAXIS);
1122 Quaternion q14(Radian(Degree(1)), Vector3::YAXIS);
1123 DALI_TEST_EQUALS(Quaternion::AngleBetween(q13, q14), fabsf(Radian(Degree(240 - 1 - 360))), 0.001f, TEST_LOCATION);
1125 Quaternion q15(Radian(Degree(240)), Vector3::YAXIS);
1126 Quaternion q16(Radian(Degree(1)), Vector3::ZAXIS);
1127 DALI_TEST_EQUALS(Quaternion::AngleBetween(q15, q16), Quaternion::AngleBetween(q16, q15), 0.001f, TEST_LOCATION);
1131 int UtcDaliQuaternionOStreamOperatorP(void)
1133 std::ostringstream oss;
1135 Quaternion quaternion(Dali::ANGLE_180, Vector3::YAXIS);
1139 std::string expectedOutput = "[ Axis: [0, 1, 0], Angle: 180 degrees ]";
1141 DALI_TEST_EQUALS(oss.str(), expectedOutput, TEST_LOCATION);