34 Quaternionf end_rotation{ Quaternionf::make_rotation(amount_of_rotation, rotation_axis) };
35 float step_percentage = 1.0f / num_equal_steps;
37 for (
int iCurrentStep = 0; iCurrentStep < num_equal_steps; ++iCurrentStep)
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);
52 std::cout << __func__ << std::endl;
54 Quaternionf unit = Quaternionf::identity();
64 std::cout << __func__ << std::endl;
66 Quaternionf zero = Quaternionf::zero();
76 std::cout << __func__ << std::endl;
78 Quaternionf q{ 1.0, 2.0, 3.0, 4.0 };
88 std::cout << __func__ << std::endl;
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;
102 std::cout << __func__ << std::endl;
104 Quaternionf q_original{ 1.0, 2.0, 3.0, 4.0 };
105 Quaternionf q_tocompareagainst{ 1.0, 2.0, 3.0, 4.0 };
116 std::cout << __func__ << std::endl;
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 };
127 assert( (q_original != q_tocompareagainst) ==
false );
138 std::cout << __func__ << std::endl;
140 Quaternionf q_original{ 2.0, 4.0, 6.0, 8.0 };
141 Quaternionf q_copy{ q_original };
148 std::cout << __func__ << std::endl;
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 };
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 };
168 std::cout << __func__ << std::endl;
170 Quaternionf arbitrary_value1{ 6.0, 7.0, 8.0, 9.0 };
172 CHECK_IF_EQUAL(arbitrary_value1.conjugate().conjugate(), arbitrary_value1);
177 std::cout << __func__ << std::endl;
180 Quaternionf unit_rotation = Quaternionf::identity();
181 const float point[3] = { 1.0, 3.0, 7.0 };
184 Quaternionf value_to_rotate{ 0.0f, point[0], point[1], point[2] };
186 CHECK_IF_EQUAL((unit_rotation * value_to_rotate * unit_rotation.conjugate()), value_to_rotate);
191 std::cout << __func__ << std::endl;
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 } );
200 std::cout << __func__ << std::endl;
202 Quaternionf negative_1{ -1.0, 0.0, 0.0, 0.0 };
203 Quaternionf i = Quaternionf::unit_i();
210 std::cout << __func__ << std::endl;
212 Quaternionf negative_1{ -1.0, 0.0, 0.0, 0.0 };
213 Quaternionf j = Quaternionf::unit_j();
220 std::cout << __func__ << std::endl;
222 Quaternionf negative_1{ -1.0, 0.0, 0.0, 0.0 };
223 Quaternionf k = Quaternionf::unit_k();
230 std::cout << __func__ << std::endl;
232 Quaternionf negative_1{ -1.0, 0.0, 0.0, 0.0 };
234 CHECK_IF_EQUAL( Quaternionf::unit_i() * Quaternionf::unit_j() * Quaternionf::unit_k(), negative_1 );
239 std::cout << __func__ << std::endl;
241 CHECK_IF_EQUAL( Quaternionf::unit_i() * Quaternionf::unit_j(), Quaternionf::unit_k() );
246 std::cout << __func__ << std::endl;
248 Quaternionf negative_k{ 0.0, 0.0, 0.0, -1.0 };
250 CHECK_IF_EQUAL( Quaternionf::unit_j() * Quaternionf::unit_i(), negative_k );
254 std::cout << __func__ << std::endl;
256 CHECK_IF_EQUAL( Quaternionf::unit_j() * Quaternionf::unit_k(), Quaternionf::unit_i() );
261 std::cout << __func__ << std::endl;
263 Quaternionf negative_i{ 0.0, -1.0, 0.0, 0.0 };
265 CHECK_IF_EQUAL( Quaternionf::unit_k() * Quaternionf::unit_j(), negative_i );
270 std::cout << __func__ << std::endl;
272 CHECK_IF_EQUAL( Quaternionf::unit_k() * Quaternionf::unit_i(), Quaternionf::unit_j() );
277 std::cout << __func__ << std::endl;
279 Quaternionf negative_j{ 0.0, 0.0, -1.0, 0.0 };
281 CHECK_IF_EQUAL( Quaternionf::unit_i() * Quaternionf::unit_k(), negative_j );
286 std::cout << __func__ << std::endl;
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 } );
293 CHECK_IF_EQUAL( -Quaternionf(1.0f, -2.2f, 3.0f, -4.0f), Quaternionf(-1.0f, 2.2f, -3.0f, 4.0f) );
298 std::cout << __func__ << std::endl;
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;
311 std::cout << __func__ << std::endl;
319 CHECK_IF_EQUAL( Quaternionf{ 1.0, 2.0, 3.0, 4.0 }.norm(), std::sqrt(30.0f) );
324 std::cout << __func__ << std::endl;
334 std::cout << __func__ << std::endl;
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);
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);
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);
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);
371 std::cout << __func__ << std::endl;
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;
385 std::cout << __func__ << std::endl;
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());
395 std::cout << __func__ << std::endl;
397 assert( Quaternionf::identity().isUnit() );
403 std::cout << __func__ << std::endl;
405 CHECK_IF_EQUAL( Quaternionf::make_pure( { 1.0f, 2.0f, 3.0f } ).real(), 0.0f );
410 std::cout << __func__ << std::endl;
412 Quaternionf pure_q = Quaternionf::make_pure( {1.0f, 2.0f, 3.0f} );
421 std::cout << __func__ << std::endl;
423 Quaternionf pure_q = Quaternionf::make_pure( {1.0f, 2.0f, 3.0f} );
432 std::cout << __func__ << std::endl;
434 Quaternionf q1{ 1.0f, 2.0f, 3.0f, 4.0f };
435 Quaternionf q2{ 9.0f, 10.0f, 11.0f, 12.0f };
442 std::cout << __func__ << std::endl;
444 Quaternionf q{ 3.5f, -45.668f, 113.443f, 6.332f};
445 Quaternionf product = q * q.conjugate();
454 std::cout << __func__ << std::endl;
456 Quaternionf q{ 3.5f, -45.668f, 113.443f, 6.332f};
457 Quaternionf product = q * q.conjugate();
458 float m_squared = q.magnitudeSquared();
465 std::cout << __func__ << std::endl;
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();
477 std::cout << __func__ << std::endl;
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 );
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 );
508 std::cout << __func__ << std::endl;
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();
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();
539 std::cout << __func__ << std::endl;
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);
547 transformed_point = passively_rotate_encoded_point(rotation_90_y, transformed_point);
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);
572 std::cout << __func__ << std::endl;
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 };
585 CHECK_IF_EQUAL( exp_0_5, Quaternionf::make_rotation( angle * 0.5f, Vector3Df::unit_z()) );
587 CHECK_IF_EQUAL( exp_2_0, Quaternionf::make_rotation(angle * 2.0f, Vector3Df::unit_z()) );
597 std::cout << __func__ << std::endl;
600 CHECK_IF_EQUAL( Quaternionf{1.0f}.exp().imaginary(), Vector3Df::zero() );
603 CHECK_IF_EQUAL( Quaternionf{2.0f}.exp().imaginary(), Vector3Df::zero() );
606 CHECK_IF_EQUAL( Quaternionf{3.2f}.exp().imaginary(), Vector3Df::zero() );
611 std::cout << __func__ << std::endl;
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}) };
629 std::cout << __func__ << std::endl;
631 Vector3Df z{ Vector3Df::unit_z() };
632 Quaternionf begin = Quaternionf::identity();
633 Quaternionf end = Quaternionf::make_rotation( 90.0_deg_f, z );
637 Quaternionf slerp_begin = slerp(begin, end, 0.0f);
638 Quaternionf slerp_end = slerp(begin, end, 1.0f);
653 std::cout << __func__ << std::endl;
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() );
665 std::cout << __func__ << std::endl;
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() );
677 std::cout << __func__ << std::endl;
679 Quaternionf result{ Quaternionf::identity() / 0.0f };
681 assert( result.isInf() );
690 std::cout <<
"Running Quaternion Tests..." << std::endl;
738 std::cout <<
"PASSED!" << std::endl;
void CHECK_IF_NOT_EQUAL(float input, float near_to, float tolerance=0.0002f)
void CHECK_IF_EQUAL(float input, float near_to, float tolerance=0.0002f)
constexpr T DegreesToRadians(T degrees)
Convert degrees to radians.
void MultiplyingAQuaternionByItsConjugateProducesAPureRealNumber()
void ImaginaryReturnsIJK()
void DividingByAScalarDividesEachComponent()
void ISquaredIsNegativeOne()
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 UnitQuaternionIsNear1()
void IJKUnitQuaternionsAreDefined()
void KSquaredIsNegativeOne()
void DivisionIsJustMultiplyingByTheInverse()
void OperatorPlusAndMinusAreInverses()
void ZeroQuaternionIsAsExpected()
void PerformTwoConsecutiveRotations()
void IsInfIsTrueWhenAtLeastOneMemberIsInf()
void OperatorEqualsComparesMatchingComponents()
void MultiplyingByItsOwnInverseProducesUnity()
void MultiplyingByAScalarMultipliesEachComponent()
void OperatorNotEqualsIsOppositeOfEquals()
void JSquaredIsNegativeOne()
void ConjugateIsItsOwnInverse()
void MagnitudeSquaredIsValueOfRealPartOfProductOfAQuaternionAndItsConjugate()
void TestRotationAtRegularIntervals(Quaternionf begin, Degreef amount_of_rotation, Vector3Df rotation_axis, int num_equal_steps)
void IsNaNIsTrueWhenAtLeastOneMemberIsNaN()
void DivideByZeroProducesInf()
void UnitQuaternionIsAsExpected()
void CopyOperatorIsImplemented()
void MakingARotationIsAccurate()