MathLib
Loading...
Searching...
No Matches
TestQuaternion.cpp
Go to the documentation of this file.
4#include <cassert>
5#include <iostream>
6#include <cstdlib>
7
27{
28
29using namespace Math;
30using namespace Math::Literals;
31
32void TestRotationAtRegularIntervals(Quaternionf begin, Degreef amount_of_rotation, Vector3Df rotation_axis, int num_equal_steps)
33{
34 Quaternionf end_rotation{ Quaternionf::make_rotation(amount_of_rotation, rotation_axis) };
35 float step_percentage = 1.0f / num_equal_steps;
36
37 for (int iCurrentStep = 0; iCurrentStep < num_equal_steps; ++iCurrentStep)
38 {
39 float current_percentage{ step_percentage * iCurrentStep };
40 Degreef current_rotation_amount{ amount_of_rotation * current_percentage };
41 Quaternionf new_rotation{ Quaternionf::make_rotation(current_rotation_amount, rotation_axis) };
42 Quaternionf slerp_result = slerp(begin, end_rotation, current_percentage);
43
44 CHECK_IF_EQUAL( slerp_result, new_rotation);
45 }
46 CHECK_IF_EQUAL( slerp(begin, end_rotation, 1.0f), end_rotation);
47}
48
51{
52 std::cout << __func__ << std::endl;
53
54 Quaternionf unit = Quaternionf::identity();
55
56 CHECK_IF_EQUAL(unit.w(), 1.0f);
57 CHECK_IF_EQUAL(unit.i(), 0.0f);
58 CHECK_IF_EQUAL(unit.j(), 0.0f);
59 CHECK_IF_EQUAL(unit.k(), 0.0f);
60}
61
63{
64 std::cout << __func__ << std::endl;
65
66 Quaternionf zero = Quaternionf::zero();
67
68 CHECK_IF_EQUAL(zero.w(), 0.0f);
69 CHECK_IF_EQUAL(zero.i(), 0.0f);
70 CHECK_IF_EQUAL(zero.j(), 0.0f);
71 CHECK_IF_EQUAL(zero.k(), 0.0f);
72}
73
75{
76 std::cout << __func__ << std::endl;
77
78 Quaternionf q{ 1.0, 2.0, 3.0, 4.0 };
79
80 CHECK_IF_EQUAL(q.w(), 1.0f);
81 CHECK_IF_EQUAL(q.i(), 2.0f);
82 CHECK_IF_EQUAL(q.j(), 3.0f);
83 CHECK_IF_EQUAL(q.k(), 4.0f);
84}
85
87{
88 std::cout << __func__ << std::endl;
89
90 Quaternionf q_left{ 1.0, 2.0, 3.0, 4.0 };
91 Quaternionf q_right{ 5.0, 6.0, 7.0, 8.0 };
92 Quaternionf q_result = q_left + q_right;
93
94 CHECK_IF_EQUAL(q_result.w(), 6.0f);
95 CHECK_IF_EQUAL(q_result.i(), 8.0f);
96 CHECK_IF_EQUAL(q_result.j(), 10.0f);
97 CHECK_IF_EQUAL(q_result.k(), 12.0f);
98}
99
101{
102 std::cout << __func__ << std::endl;
103
104 Quaternionf q_original{ 1.0, 2.0, 3.0, 4.0 };
105 Quaternionf q_tocompareagainst{ 1.0, 2.0, 3.0, 4.0 };
106
107 CHECK_IF_EQUAL(q_original, q_tocompareagainst);
108 CHECK_IF_EQUAL(q_original.w(), q_tocompareagainst.w());
109 CHECK_IF_EQUAL(q_original.i(), q_tocompareagainst.i());
110 CHECK_IF_EQUAL(q_original.j(), q_tocompareagainst.j());
111 CHECK_IF_EQUAL(q_original.k(), q_tocompareagainst.k());
112}
113
115{
116 std::cout << __func__ << std::endl;
117
118 Quaternionf q_original{ 1.0, 2.0, 3.0, 4.0 };
119 Quaternionf q_tocompareagainst{ 1.0, 2.0, 3.0, 4.0 };
120 Quaternionf q_different4{ 1.0, 2.0, 3.0, 5.0 };
121 Quaternionf q_different3{ 1.0, 2.0, 9.0, 4.0 };
122 Quaternionf q_different2{ 1.0, 12.0, 3.0, 4.0 };
123 Quaternionf q_different1{ 100.0, 2.0, 3.0, 4.0 };
124
125 CHECK_IF_EQUAL(q_original, q_tocompareagainst);
126
127 assert( (q_original != q_tocompareagainst) == false );
128
129 // Now test for each component individually
130 CHECK_IF_NOT_EQUAL(q_original, q_different1);
131 CHECK_IF_NOT_EQUAL(q_original, q_different2);
132 CHECK_IF_NOT_EQUAL(q_original, q_different3);
133 CHECK_IF_NOT_EQUAL(q_original, q_different4);
134}
135
137{
138 std::cout << __func__ << std::endl;
139
140 Quaternionf q_original{ 2.0, 4.0, 6.0, 8.0 };
141 Quaternionf q_copy{ q_original };
142
143 CHECK_IF_EQUAL(q_original, q_copy);
144}
145
147{
148 std::cout << __func__ << std::endl;
149
150 Quaternionf arbitrary_value1{ 1.0, 2.0, 3.0, 4.0 };
151 Quaternionf arbitrary_value2{ 1.0, -2.0, 3.0, 4.0 };
152 Quaternionf arbitrary_value3{ 1.0, 2.0, -3.0, 4.0 };
153 Quaternionf arbitrary_value4{ 1.0, 2.0, 3.0, -4.0 };
154
155 Quaternionf expected_value1{ 1.0, -2.0, -3.0, -4.0 };
156 Quaternionf expected_value2{ 1.0, 2.0, -3.0, -4.0 };
157 Quaternionf expected_value3{ 1.0, -2.0, 3.0, -4.0 };
158 Quaternionf expected_value4{ 1.0, -2.0, -3.0, 4.0 };
159
160 CHECK_IF_EQUAL(arbitrary_value1.conjugate(), expected_value1);
161 CHECK_IF_EQUAL(arbitrary_value2.conjugate(), expected_value2);
162 CHECK_IF_EQUAL(arbitrary_value3.conjugate(), expected_value3);
163 CHECK_IF_EQUAL(arbitrary_value4.conjugate(), expected_value4);
164}
165
167{
168 std::cout << __func__ << std::endl;
169
170 Quaternionf arbitrary_value1{ 6.0, 7.0, 8.0, 9.0 };
171
172 CHECK_IF_EQUAL(arbitrary_value1.conjugate().conjugate(), arbitrary_value1);
173}
174
176{
177 std::cout << __func__ << std::endl;
178
179 // The rotation must be of unit length
180 Quaternionf unit_rotation = Quaternionf::identity();
181 const float point[3] = { 1.0, 3.0, 7.0 };
182
183 // Place 3D point in the imaginary part, leaving the real part as 0.0
184 Quaternionf value_to_rotate{ 0.0f, point[0], point[1], point[2] };
185
186 CHECK_IF_EQUAL((unit_rotation * value_to_rotate * unit_rotation.conjugate()), value_to_rotate);
187}
188
190{
191 std::cout << __func__ << std::endl;
192
193 CHECK_IF_EQUAL( Quaternionf::unit_i(), Quaternionf{ 0.0, 1.0, 0.0, 0.0 } );
194 CHECK_IF_EQUAL( Quaternionf::unit_j(), Quaternionf{ 0.0, 0.0, 1.0, 0.0 } );
195 CHECK_IF_EQUAL( Quaternionf::unit_k(), Quaternionf{ 0.0, 0.0, 0.0, 1.0 } );
196}
197
199{
200 std::cout << __func__ << std::endl;
201
202 Quaternionf negative_1{ -1.0, 0.0, 0.0, 0.0 };
203 Quaternionf i = Quaternionf::unit_i();
204
205 CHECK_IF_EQUAL( i * i, negative_1 );
206}
207
209{
210 std::cout << __func__ << std::endl;
211
212 Quaternionf negative_1{ -1.0, 0.0, 0.0, 0.0 };
213 Quaternionf j = Quaternionf::unit_j();
214
215 CHECK_IF_EQUAL( j * j, negative_1 );
216}
217
219{
220 std::cout << __func__ << std::endl;
221
222 Quaternionf negative_1{ -1.0, 0.0, 0.0, 0.0 };
223 Quaternionf k = Quaternionf::unit_k();
224
225 CHECK_IF_EQUAL( k * k, negative_1 );
226}
227
229{
230 std::cout << __func__ << std::endl;
231
232 Quaternionf negative_1{ -1.0, 0.0, 0.0, 0.0 };
233
234 CHECK_IF_EQUAL( Quaternionf::unit_i() * Quaternionf::unit_j() * Quaternionf::unit_k(), negative_1 );
235}
236
238{
239 std::cout << __func__ << std::endl;
240
241 CHECK_IF_EQUAL( Quaternionf::unit_i() * Quaternionf::unit_j(), Quaternionf::unit_k() );
242}
243
245{
246 std::cout << __func__ << std::endl;
247
248 Quaternionf negative_k{ 0.0, 0.0, 0.0, -1.0 };
249
250 CHECK_IF_EQUAL( Quaternionf::unit_j() * Quaternionf::unit_i(), negative_k );
251}
253{
254 std::cout << __func__ << std::endl;
255
256 CHECK_IF_EQUAL( Quaternionf::unit_j() * Quaternionf::unit_k(), Quaternionf::unit_i() );
257}
258
260{
261 std::cout << __func__ << std::endl;
262
263 Quaternionf negative_i{ 0.0, -1.0, 0.0, 0.0 };
264
265 CHECK_IF_EQUAL( Quaternionf::unit_k() * Quaternionf::unit_j(), negative_i );
266}
267
269{
270 std::cout << __func__ << std::endl;
271
272 CHECK_IF_EQUAL( Quaternionf::unit_k() * Quaternionf::unit_i(), Quaternionf::unit_j() );
273}
274
276{
277 std::cout << __func__ << std::endl;
278
279 Quaternionf negative_j{ 0.0, 0.0, -1.0, 0.0 };
280
281 CHECK_IF_EQUAL( Quaternionf::unit_i() * Quaternionf::unit_k(), negative_j );
282}
283
285{
286 std::cout << __func__ << std::endl;
287
288 CHECK_IF_EQUAL( -Quaternionf::identity(), Quaternionf{ -1.0, 0.0, 0.0, 0.0 } );
289 CHECK_IF_EQUAL( -Quaternionf::unit_i(), Quaternionf{ 0.0, -1.0, 0.0, 0.0 } );
290 CHECK_IF_EQUAL( -Quaternionf::unit_j(), Quaternionf{ 0.0, 0.0, -1.0, 0.0 } );
291 CHECK_IF_EQUAL( -Quaternionf::unit_k(), Quaternionf{ 0.0, 0.0, 0.0, -1.0 } );
292
293 CHECK_IF_EQUAL( -Quaternionf(1.0f, -2.2f, 3.0f, -4.0f), Quaternionf(-1.0f, 2.2f, -3.0f, 4.0f) );
294}
295
297{
298 std::cout << __func__ << std::endl;
299
300 Quaternionf::value_type starting_value = 0;
301 Quaternionf::value_type value = 6;
302 Quaternionf::value_type added_value = starting_value + value;
303 Quaternionf::value_type subtracted_value = starting_value - value;
304
305 CHECK_IF_EQUAL( added_value - value, starting_value );
306 CHECK_IF_EQUAL( subtracted_value + value, starting_value );
307}
308
310{
311 std::cout << __func__ << std::endl;
312
313 // Show that sqrt(4) == 2.
314 // i.e. qrt) of a^2 + b^2 + c^2 + d^2 == 2
315 // i.e. a^2 + b^2 + c^2 + d^2 == 4
316 CHECK_IF_EQUAL( Quaternionf{ 1.0, 1.0, 1.0, 1.0 }.norm(), 2.0f );
317
318 CHECK_IF_EQUAL( Quaternionf{ 2.0, 2.0, 2.0, 2.0 }.norm(), 4.0f );
319 CHECK_IF_EQUAL( Quaternionf{ 1.0, 2.0, 3.0, 4.0 }.norm(), std::sqrt(30.0f) ); // 1^2 + 2^2 + 3^2 + 4^2
320}
321
323{
324 std::cout << __func__ << std::endl;
325
326 CHECK_IF_EQUAL( Quaternionf::identity().norm(), 1.0f );
327 CHECK_IF_EQUAL( Quaternionf::unit_i().norm(), 1.0f );
328 CHECK_IF_EQUAL( Quaternionf::unit_j().norm(), 1.0f );
329 CHECK_IF_EQUAL( Quaternionf::unit_k().norm(), 1.0f );
330}
331
333{
334 std::cout << __func__ << std::endl;
335 {
336 Quaternionf a(1.0f, 2.0f, 3.0f, 4.0f);
337 Quaternionf a_div = a / 2.0f;
338 Quaternionf b(1.0f / 2.0f, 2.0f / 2.0f, 3.0f / 2.0f, 4.0f / 2.0f);
339
340 CHECK_IF_EQUAL( a_div, b );
341 }
342 {
343 Quaternionf a(1.0f, 2.0f, 3.0f, 4.0f);
344 Quaternionf a_div = a / 3.0f;
345 Quaternionf b(1.0f / 3.0f, 2.0f / 3.0f, 3.0f / 3.0f, 4.0f / 3.0f);
346
347 CHECK_IF_EQUAL( a_div, b );
348 }
349}
350
352{
353 {
354 Quaternionf a(1.0f, 2.0f, 3.0f, 4.0f);
355 Quaternionf a_mul = a * 2.0f;
356 Quaternionf b(1.0f * 2.0f, 2.0f * 2.0f, 3.0f * 2.0f, 4.0f * 2.0f);
357
358 CHECK_IF_EQUAL( a_mul, b );
359 }
360 {
361 Quaternionf a(1.0f, 2.0f, 3.0f, 4.0f);
362 Quaternionf a_mul = a * 3.0f;
363 Quaternionf b(1.0f * 3.0f, 2.0f * 3.0f, 3.0f * 3.0f, 4.0f * 3.0f);
364
365 CHECK_IF_EQUAL( a_mul, b );
366 }
367}
368
370{
371 std::cout << __func__ << std::endl;
372
373 Quaternionf q1{ 6.3f, 2.2f, 1.1f, 0.0f };
374 Quaternionf q1_inverse = q1.inverse();
375 Quaternionf q1_product = q1_inverse * q1;
376 Quaternionf q1_product_reversed = q1 * q1_inverse;
377
378 CHECK_IF_EQUAL( q1_product, Quaternionf::identity() );
379 CHECK_IF_EQUAL( q1_product_reversed, Quaternionf::identity() );
380 CHECK_IF_EQUAL( q1_product_reversed, q1_product );
381}
382
384{
385 std::cout << __func__ << std::endl;
386
387 CHECK_IF_EQUAL(Quaternionf::unit_real().inverse(), Quaternionf::unit_real().conjugate());
388 CHECK_IF_EQUAL(Quaternionf::unit_i().inverse(), Quaternionf::unit_i().conjugate());
389 CHECK_IF_EQUAL(Quaternionf::unit_j().inverse(), Quaternionf::unit_j().conjugate());
390 CHECK_IF_EQUAL(Quaternionf::unit_k().inverse(), Quaternionf::unit_k().conjugate());
391}
392
394{
395 std::cout << __func__ << std::endl;
396
397 assert( Quaternionf::identity().isUnit() );
398 CHECK_IF_EQUAL( Quaternionf::identity().norm(), 1.0f );
399}
400
402{
403 std::cout << __func__ << std::endl;
404
405 CHECK_IF_EQUAL( Quaternionf::make_pure( { 1.0f, 2.0f, 3.0f } ).real(), 0.0f );
406}
407
409{
410 std::cout << __func__ << std::endl;
411
412 Quaternionf pure_q = Quaternionf::make_pure( {1.0f, 2.0f, 3.0f} );
413
414 CHECK_IF_EQUAL( pure_q.i(), 1.0f );
415 CHECK_IF_EQUAL( pure_q.j(), 2.0f );
416 CHECK_IF_EQUAL( pure_q.k(), 3.0f );
417}
418
420{
421 std::cout << __func__ << std::endl;
422
423 Quaternionf pure_q = Quaternionf::make_pure( {1.0f, 2.0f, 3.0f} );
424
425 CHECK_IF_EQUAL( pure_q.imaginary().x, 1.0f );
426 CHECK_IF_EQUAL( pure_q.imaginary().y, 2.0f );
427 CHECK_IF_EQUAL( pure_q.imaginary().z, 3.0f );
428}
429
431{
432 std::cout << __func__ << std::endl;
433
434 Quaternionf q1{ 1.0f, 2.0f, 3.0f, 4.0f };
435 Quaternionf q2{ 9.0f, 10.0f, 11.0f, 12.0f };
436
437 CHECK_IF_EQUAL( dot( q1, q2 ), 110.0f );
438}
439
441{
442 std::cout << __func__ << std::endl;
443
444 Quaternionf q{ 3.5f, -45.668f, 113.443f, 6.332f};
445 Quaternionf product = q * q.conjugate();
446
447 CHECK_IF_EQUAL( product.i(), 0.0f );
448 CHECK_IF_EQUAL( product.j(), 0.0f );
449 CHECK_IF_EQUAL( product.k(), 0.0f );
450}
451
453{
454 std::cout << __func__ << std::endl;
455
456 Quaternionf q{ 3.5f, -45.668f, 113.443f, 6.332f};
457 Quaternionf product = q * q.conjugate();
458 float m_squared = q.magnitudeSquared();
459
460 CHECK_IF_EQUAL( m_squared, std::abs(product.real()) );
461}
462
464{
465 std::cout << __func__ << std::endl;
466
467 Quaternionf q{ 9.0f, 10.0f, 11.0f, 12.0f };
468 Quaternionf q2{ 3.5f, -45.668f, 113.443f, 6.332f};
469 Quaternionf q_dividedby_q2 = q / q2;
470 Quaternionf q_times_inverse_of_q2 = q * q2.inverse();
471
472 CHECK_IF_EQUAL( q_dividedby_q2, q_times_inverse_of_q2 );
473}
474
476{
477 std::cout << __func__ << std::endl;
478
479 // 90 deg rotation around X axis
480 {
481 float degrees_of_rotation = 90.0f;
482 float half_angle = degrees_of_rotation / 2.0f;
483 Quaternionf rotation = Quaternionf::make_rotation( Degreef(degrees_of_rotation), 1.0f, 0.0f, 0.0f );
484
485 CHECK_IF_EQUAL( rotation.norm(), 1.0f );
486 CHECK_IF_EQUAL( rotation.w(), std::cos( DegreesToRadians(half_angle) ) );
487 CHECK_IF_EQUAL( rotation.i(), std::sin( DegreesToRadians(half_angle) ) );
488 CHECK_IF_EQUAL( rotation.j(), 0.0f );
489 CHECK_IF_EQUAL( rotation.k(), 0.0f );
490 }
491
492 // 60 deg rotation around X axis
493 {
494 float degrees_of_rotation = 60.0f;
495 float half_angle = degrees_of_rotation / 2.0f;
496 Quaternionf rotation = Quaternionf::make_rotation( Degreef(degrees_of_rotation), 1.0f, 0.0f, 0.0f );
497
498 CHECK_IF_EQUAL( rotation.norm(), 1.0f );
499 CHECK_IF_EQUAL( rotation.w(), std::cos( DegreesToRadians(half_angle) ) );
500 CHECK_IF_EQUAL( rotation.i(), std::sin( DegreesToRadians(half_angle) ) );
501 CHECK_IF_EQUAL( rotation.j(), 0.0f );
502 CHECK_IF_EQUAL( rotation.k(), 0.0f );
503 }
504}
505
507{
508 std::cout << __func__ << std::endl;
509
510 // Rotate 90 deg around X axis.
511 // A unit in Y becomes a unit in Z.
512 {
513 Quaternionf rotation = Quaternionf::make_rotation( Degreef(90.0f), 1.0f, 0.0f, 0.0f );
514 Quaternionf encoded_point = Quaternionf::encode_point(0.0f, 1.0f, 0.0f);
515 Quaternionf transformed_point = rotation * encoded_point * rotation.conjugate();
516
517 CHECK_IF_EQUAL( transformed_point.w(), 0.0f );
518 CHECK_IF_EQUAL( transformed_point.i(), 0.0f );
519 CHECK_IF_EQUAL( transformed_point.j(), 0.0f );
520 CHECK_IF_EQUAL( transformed_point.k(), 1.0f );
521 }
522
523 // Rotate 90 deg around Y axis.
524 // A unit in X becomes a unit in -Z.
525 {
526 Quaternionf rotation = Quaternionf::make_rotation( Degreef(90.0f), 0.0f, 1.0f, 0.0f );
527 Quaternionf encoded_point = Quaternionf::encode_point(1.0f, 0.0f, 0.0f);
528 Quaternionf transformed_point = rotation * encoded_point * rotation.conjugate();
529
530 CHECK_IF_EQUAL( transformed_point.w(), 0.0f );
531 CHECK_IF_EQUAL( transformed_point.i(), 0.0f );
532 CHECK_IF_EQUAL( transformed_point.j(), 0.0f );
533 CHECK_IF_EQUAL( transformed_point.k(), -1.0f );
534 }
535}
536
538{
539 std::cout << __func__ << std::endl;
540
541 {
542 Quaternionf rotation_90_x = Quaternionf::make_rotation( Degreef(90.0f), 1.0f, 0.0f, 0.0f );
543 Quaternionf rotation_90_y = Quaternionf::make_rotation( Degreef(90.0f), 0.0f, 1.0f, 0.0f );
544 Quaternionf encoded_point = Quaternionf::encode_point(0.0f, 1.0f, 0.0f);
545 Quaternionf transformed_point = passively_rotate_encoded_point(rotation_90_x, encoded_point);
546
547 transformed_point = passively_rotate_encoded_point(rotation_90_y, transformed_point);
548
549 CHECK_IF_EQUAL( transformed_point.w(), 0.0f );
550 CHECK_IF_EQUAL( transformed_point.i(), 1.0f );
551 CHECK_IF_EQUAL( transformed_point.j(), 0.0f );
552 CHECK_IF_EQUAL( transformed_point.k(), 0.0f );
553 }
554
555 // Same thing, but compose the rotations first
556 {
557 Quaternionf rotation_90_x = Quaternionf::make_rotation( Degreef(90.0f), 1.0f, 0.0f, 0.0f );
558 Quaternionf rotation_90_y = Quaternionf::make_rotation( Degreef(90.0f), 0.0f, 1.0f, 0.0f );
559 Quaternionf composed_rotation = compose_rotations( rotation_90_x, rotation_90_y );
560 Quaternionf encoded_point = Quaternionf::encode_point(0.0f, 1.0f, 0.0f);
561 Quaternionf transformed_point = passively_rotate_encoded_point(composed_rotation, encoded_point);
562
563 CHECK_IF_EQUAL( transformed_point.w(), 0.0f );
564 CHECK_IF_EQUAL( transformed_point.i(), 1.0f );
565 CHECK_IF_EQUAL( transformed_point.j(), 0.0f );
566 CHECK_IF_EQUAL( transformed_point.k(), 0.0f );
567 }
568}
569
571{
572 std::cout << __func__ << std::endl;
573
574 auto angle = 90.0_deg_f;
575 Quaternionf rotation = Quaternionf::make_rotation( angle, Vector3Df::unit_z() );
576 Quaternionf exp0 = rotation.pow(0.0f);
577 Quaternionf exp_0_5 = rotation.pow(0.5f);
578 Quaternionf exp1 = rotation.pow(1.0f);
579 Quaternionf exp_2_0 = rotation.pow(2.0f);
580 Quaternionf exp_3_0 = rotation.pow(3.0f);
581 Quaternionf two_rotations_multiplied{ rotation * rotation };
582 Quaternionf three_rotations_multiplied{ rotation * rotation * rotation };
583
584 CHECK_IF_EQUAL( exp0, Quaternionf::identity() );
585 CHECK_IF_EQUAL( exp_0_5, Quaternionf::make_rotation( angle * 0.5f, Vector3Df::unit_z()) );
586 CHECK_IF_EQUAL( exp1, rotation );
587 CHECK_IF_EQUAL( exp_2_0, Quaternionf::make_rotation(angle * 2.0f, Vector3Df::unit_z()) );
588
589 // Check that a quaternion squared via pow() is identical to multiplying by itself
590 CHECK_IF_EQUAL( exp_2_0, two_rotations_multiplied );
591
592 CHECK_IF_EQUAL( exp_3_0, three_rotations_multiplied );
593}
594
596{
597 std::cout << __func__ << std::endl;
598
599 CHECK_IF_EQUAL( Quaternionf{1.0f}.exp().w(), std::exp(1.0f) );
600 CHECK_IF_EQUAL( Quaternionf{1.0f}.exp().imaginary(), Vector3Df::zero() );
601
602 CHECK_IF_EQUAL( Quaternionf{2.0f}.exp().w(), std::exp(2.0f) );
603 CHECK_IF_EQUAL( Quaternionf{2.0f}.exp().imaginary(), Vector3Df::zero() );
604
605 CHECK_IF_EQUAL( Quaternionf{3.2f}.exp().w(), std::exp(3.2f) );
606 CHECK_IF_EQUAL( Quaternionf{3.2f}.exp().imaginary(), Vector3Df::zero() );
607}
608
610{
611 std::cout << __func__ << std::endl;
612
613 auto a{ Quaternionf::identity() };
614 auto b{ Quaternionf::make_rotation(36.3_deg_f, Vector3Df::unit_y()) };
615 auto c{ Quaternionf::make_rotation(90.0_deg_f, Vector3Df{1.0f, 1.0f, 1.0f}) };
616
617 CHECK_IF_EQUAL( log( exp(a) ), a );
618 CHECK_IF_EQUAL( exp( log(a) ), a );
619
620 CHECK_IF_EQUAL( log( exp(b) ), b );
621 CHECK_IF_EQUAL( exp( log(b) ), b );
622
623 CHECK_IF_EQUAL( log( exp(c) ), c );
624 CHECK_IF_EQUAL( exp( log(c) ), c );
625}
626
628{
629 std::cout << __func__ << std::endl;
630
631 Vector3Df z{ Vector3Df::unit_z() };
632 Quaternionf begin = Quaternionf::identity();
633 Quaternionf end = Quaternionf::make_rotation( 90.0_deg_f, z );
634
635 // with only the endpoints
636 {
637 Quaternionf slerp_begin = slerp(begin, end, 0.0f);
638 Quaternionf slerp_end = slerp(begin, end, 1.0f);
639
640 CHECK_IF_EQUAL( slerp_begin, begin );
641 CHECK_IF_EQUAL( slerp_end, end );
642 }
643
644 // 0 to 90 in 10 deg increments
645 TestRotationAtRegularIntervals(begin, 90.0_deg_f, z, 9);
646
647 // 0 to 180 in 10 deg increments
648 TestRotationAtRegularIntervals(begin, 180.0_deg_f, z, 18);
649}
650
652{
653 std::cout << __func__ << std::endl;
654
655 assert( Quaternionf(NAN).isNaN() );
656 assert( Quaternionf(NAN, 0.0f, 0.0f, 0.0f).isNaN() );
657 assert( Quaternionf(3.2f, NAN, 0.0f, 0.0f).isNaN() );
658 assert( Quaternionf(3.2f, 0.0f, NAN, 0.0f).isNaN() );
659 assert( Quaternionf(3.2f, 0.0f, 0.0f, NAN).isNaN() );
660 assert( !Quaternionf(3.2f, 4.6f, 0.0f, 1.1f).isNaN() );
661}
662
664{
665 std::cout << __func__ << std::endl;
666
667 assert( Quaternionf(INFINITY).isInf() );
668 assert( Quaternionf(INFINITY, 0.0f, 0.0f, 0.0f).isInf() );
669 assert( Quaternionf(3.2f, INFINITY, 0.0f, 0.0f).isInf() );
670 assert( Quaternionf(3.2f, 0.0f, INFINITY, 0.0f).isInf() );
671 assert( Quaternionf(3.2f, 0.0f, 0.0f, INFINITY).isInf() );
672 assert( !Quaternionf(3.2f, 4.6f, 0.0f, 1.1f).isInf() );
673}
674
676{
677 std::cout << __func__ << std::endl;
678
679 Quaternionf result{ Quaternionf::identity() / 0.0f };
680
681 assert( result.isInf() );
682}
684
688void Run()
689{
690 std::cout << "Running Quaternion Tests..." << std::endl;
691
706 IJEqualsK();
708 JKEqualsI();
710 KIEqualsJ();
730 TestPow();
731 TestExp();
733 TestSlerp();
737
738 std::cout << "PASSED!" << std::endl;
739}
740
741}
743
744int main(void)
745{
747 return EXIT_SUCCESS;
748}
int main(void)
void CHECK_IF_NOT_EQUAL(float input, float near_to, float tolerance=0.0002f)
Definition Checks.hpp:158
void CHECK_IF_EQUAL(float input, float near_to, float tolerance=0.0002f)
Definition Checks.hpp:127
constexpr T DegreesToRadians(T degrees)
Convert degrees to radians.
Definition Angle.hpp:16
void MultiplyingAQuaternionByItsConjugateProducesAPureRealNumber()
void DividingByAScalarDividesEachComponent()
void MakePureQuaternionSetsImaginaryVectorToInputParameters()
void QuaternionIsConstructedAsExpected()
void NormIsEquivalentToDistance()
void ConjugateInvertsTheImaginaryComponents()
void QuaternionAddsPerComponent()
void ExpAndLogAreInversesOfEachOther()
void UnitQuaternionHasNormOfOne()
void ARotationIsStoredAsTheHalfAngle()
void DotProductMultiplesCorrespondingElementsAndThenSumsTheResultingValues()
void RotatingA3DPointByUnitRotationLeavesPointUnchanged()
void MakePureQuaternionSetsRealComponentToZero()
void InverseOfAUnitQuaternionIsItsConjugate()
void IJKUnitQuaternionsAreDefined()
void DivisionIsJustMultiplyingByTheInverse()
void OperatorPlusAndMinusAreInverses()
void ZeroQuaternionIsAsExpected()
void PerformTwoConsecutiveRotations()
void IsInfIsTrueWhenAtLeastOneMemberIsInf()
void OperatorEqualsComparesMatchingComponents()
void MultiplyingByItsOwnInverseProducesUnity()
void MultiplyingByAScalarMultipliesEachComponent()
void OperatorNotEqualsIsOppositeOfEquals()
void ConjugateIsItsOwnInverse()
void MagnitudeSquaredIsValueOfRealPartOfProductOfAQuaternionAndItsConjugate()
void TestRotationAtRegularIntervals(Quaternionf begin, Degreef amount_of_rotation, Vector3Df rotation_axis, int num_equal_steps)
void IsNaNIsTrueWhenAtLeastOneMemberIsNaN()
void UnitQuaternionIsAsExpected()
void CopyOperatorIsImplemented()
void MakingARotationIsAccurate()