MathLib
Loading...
Searching...
No Matches
DualQuaternion.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <Math/math/Dual.hpp>
7#include <cassert>
8#include <concepts>
9
17namespace Math
18{
19
30template <class T>
32{
33public:
37 using value_type = T;
39
44
55 :
56 _frame_of_reference{rotation, translation}
57 {
58 }
59
65 T translation_x,
66 T translation_y,
67 T translation_z)
68 :
69 _frame_of_reference{ rotation,
70 T{0.5} * BasicQuaternion<T>::encode_point(translation_x, translation_y, translation_z) * rotation }
71 {
72 assert( real().isUnit() );
73 }
76 :
77 _frame_of_reference{ rotation,
79 {
80 assert( real().isUnit() );
81 }
82
87 explicit constexpr BasicDualQuaternion(const BasicDual<BasicQuaternion<T>> &underlying_representation)
88 :
89 _frame_of_reference(underlying_representation)
90 {
91 }
93
103 {
104 return { BasicQuaternion<T>(1.0),
106 }
107
110 constexpr static BasicDualQuaternion<T> zero()
111 {
113 }
115
130 {
131 // A pure rotation has the dual part set to zero.
133 }
134
146 constexpr static BasicDualQuaternion<T> make_translation(T translation_x, T translation_y, T translation_z)
147 {
148 // No need to make the translation "0.5 * t * r" because "r" is an identity Quaterion,
149 // so we just use "0.5 * t".
151 T{0.5} * BasicQuaternion<T>::encode_point(translation_x, translation_y, translation_z)
152 };
153 }
154
165 {
166 // No need to make the translation "0.5 * t * r" because "r" is an identity Quaterion,
167 // so we just use "0.5 * t".
170 };
171 }
172
187 T translation_x,
188 T translation_y,
189 T translation_z)
190 {
191 assert( rotation.isUnit() );
192
193 return BasicDualQuaternion<T>{ rotation, translation_x, translation_y, translation_z };
194 }
195
197 {
199 }
201
202 constexpr static BasicVector3D<T> decode_point(const BasicDualQuaternion<T>& encoded_point)
203 {
204 return encoded_point.translation();
205 }
206
217 {
218 return BasicDualQuaternion<T>{ real().conjugate(), dual().conjugate() };
219 }
220
227 constexpr BasicDual<T> normsquared() const
228 {
230
231 // We should have a dual scalar now
232 // Make that assumption clear
233 assert( approximately_equal_to(normsquared.real().i(), T{0.0}) );
234 assert( approximately_equal_to(normsquared.real().j(), T{0.0}) );
235 assert( approximately_equal_to(normsquared.real().k(), T{0.0}) );
236
237#if 0
238 assert( approximately_equal_to(normsquared.dual().i(), T{0}) );
239 assert( approximately_equal_to(normsquared.dual().j(), T{0}) );
240 assert( approximately_equal_to(normsquared.dual().k(), T{0}) );
241#endif
242
243 return BasicDual<T>{ normsquared.real().real(), normsquared.dual().real() };
244 }
245
252 constexpr BasicDual<T> norm() const
253 {
254 return dualscalar_sqrt( normsquared() );
255 }
256
263 constexpr BasicDual<T> magnitude() const { return norm(); }
264
268 const BasicQuaternion<T> &real() const { return _frame_of_reference.real; }
269 const BasicQuaternion<T> &dual() const { return _frame_of_reference.dual; }
271
272 const BasicQuaternion<T> &rotation() const { return real(); }
274 {
275 return BasicQuaternion<T>(T{2.0} * dual() * rotation().conjugate()).imaginary();
276 }
277
285 {
286 return *this / norm();
287 }
288
295 constexpr bool rotation_magnitude_is_one() const
296 {
297 return approximately_equal_to( dot(real(), real()), T{1.0} );
298 }
299
307 {
308 return approximately_equal_to( dot(real(), dual()), T{0.0} );
309 }
310
315 constexpr bool is_unit() const
316 {
318 }
319
323 bool isNaN() const { return _frame_of_reference.real.isNaN() || _frame_of_reference.dual.isNaN(); }
324 bool isInf() const { return _frame_of_reference.real.isInf() || _frame_of_reference.dual.isInf(); }
326
327private:
328 BasicDual<BasicQuaternion<T>> _frame_of_reference{ BasicQuaternion<T>::identity(), BasicQuaternion<T>::zero() }; // The default value is an identity transformation
329
344 friend constexpr bool operator ==(const BasicDualQuaternion<T> &left,
345 const BasicDualQuaternion<T> &right)
346 {
347 return approximately_equal_to(left, right);
348 }
349
360 //template <std::floating_point OT = float>
361 friend constexpr bool approximately_equal_to(const BasicDualQuaternion<T> &value_to_test,
362 const BasicDualQuaternion<T> &value_it_should_be,
363 T tolerance = T{0.0002})
364 {
365 // Just use the underlying BasicDual number's version of the same function...
366 return approximately_equal_to( value_to_test._frame_of_reference, value_it_should_be._frame_of_reference, tolerance );
367 }
369
381 const BasicDualQuaternion<T> &right_side)
382 {
383 return BasicDualQuaternion<T>{ left_side._frame_of_reference + right_side._frame_of_reference };
384 }
385
393 friend constexpr BasicDualQuaternion<T> operator *(T scalar, const BasicDualQuaternion<T> &dual_quaternion)
394 {
395 return BasicDualQuaternion<T>{ scalar * dual_quaternion._frame_of_reference };
396 }
397
405 friend constexpr BasicDualQuaternion<T> operator *(const BasicDualQuaternion<T> &dual_quaternion, T scalar)
406 {
407 return BasicDualQuaternion<T>{ dual_quaternion._frame_of_reference * scalar };
408 }
409
417 friend constexpr BasicDualQuaternion<T> operator *(const BasicDualQuaternion<T> &dual_quaternion,
418 const BasicDual<T> &dual_scalar)
419 {
420 return dual_quaternion * BasicDualQuaternion<T>( BasicQuaternion<T>(dual_scalar.real),
421 BasicQuaternion<T>(dual_scalar.dual) );
422 }
423
429 const BasicDualQuaternion<T> &right_side)
430 {
431 return BasicDualQuaternion<T>( left_side._frame_of_reference * right_side._frame_of_reference );
432 }
433
441 friend constexpr BasicDualQuaternion<T> operator /(const BasicDualQuaternion<T> &dual_quaternion,
442 const BasicDual<T> &dual_scalar)
443 {
444 return BasicDualQuaternion<T>( BasicDualQuaternion<T>(dual_quaternion *
445 dual_scalar.conjugate())._frame_of_reference /
446 dualscalar_normsquared(dual_scalar) );
447 }
450
468 template <std::floating_point OT = float>
469 friend bool check_if_equal(const BasicDualQuaternion<T> &input,
470 const BasicDualQuaternion<T> &near_to,
471 OT tolerance = OT{0.0002})
472 {
473 if (!approximately_equal_to(input, near_to, tolerance))
474 {
475 auto diff{ near_to - input };
476
477 std::cout << std::format("input: {} is not equal to near_to: {} within tolerance: {}. Difference is {} .",
478 format(input),
479 format(near_to),
480 tolerance,
481 format(near_to - input))
482 << std::endl;
483 return false;
484 }
485 return true;
486 }
487
496 template <std::floating_point OT = float>
498 const BasicDualQuaternion<T> &near_to,
499 OT tolerance = OT{0.0002})
500 {
501 if (approximately_equal_to(input, near_to, tolerance))
502 {
503 auto diff{ near_to - input };
504
505 std::cout << std::format("input: {} is equal to near_to: {} within tolerance: {}. Difference is {} .",
506 format(input),
507 format(near_to),
508 tolerance,
509 format(near_to - input))
510 << std::endl;
511 return false;
512 }
513 return true;
514 }
517
535 template <std::floating_point OT = float>
536 friend void CHECK_IF_EQUAL(const BasicDualQuaternion<T> &input,
537 const BasicDualQuaternion<T> &near_to,
538 OT tolerance = OT{0.0002})
539 {
540 assert( check_if_equal(input, near_to, tolerance) );
541 }
542
551 template <std::floating_point OT = float>
553 const BasicDualQuaternion<T> &near_to,
554 OT tolerance = OT{0.0002})
555 {
556 assert( check_if_not_equal(input, near_to, tolerance) );
557 }
558
566 template <std::floating_point OT = float>
567 friend void CHECK_IF_ZERO(const BasicDualQuaternion<T> &input, OT tolerance = OT{0.0002})
568 {
569 assert( check_if_equal(input, BasicDualQuaternion<T>::zero(), tolerance));
570 }
573
587 {
588 return input.normalized();
589 }
590
597 template <std::floating_point OT = float>
598 friend constexpr BasicDualQuaternion<T> blend(const BasicDualQuaternion<T> &beginning,
599 const BasicDualQuaternion<T> &end,
600 OT percentage)
601 {
602 auto blended = beginning + (end - beginning) * percentage;
603
604 return blended.normalized();
605 }
606
612 {
613 return input.conjugate();
614 }
615
616 friend std::string format(const BasicDualQuaternion<T> &input)
617 {
618 return std::format("[real: {}, dual: {}]", input.real(), input.dual());
619 }
621};
622
623
642
643}
constexpr bool rotation_magnitude_is_one() const
friend constexpr BasicDualQuaternion< T > conjugate(const BasicDualQuaternion< T > &input)
static constexpr BasicDualQuaternion< T > zero()
friend constexpr bool operator==(const BasicDualQuaternion< T > &left, const BasicDualQuaternion< T > &right)
friend constexpr BasicDualQuaternion< T > blend(const BasicDualQuaternion< T > &beginning, const BasicDualQuaternion< T > &end, OT percentage)
constexpr BasicDualQuaternion(const BasicQuaternion< T > &rotation, T translation_x, T translation_y, T translation_z)
friend constexpr BasicDualQuaternion< T > normalized(const BasicDualQuaternion< T > &input)
static constexpr BasicDualQuaternion< T > make_translation(const BasicVector3D< T > &translation)
constexpr BasicDual< T > norm() const
constexpr BasicDual< T > magnitude() const
constexpr BasicDualQuaternion(const BasicQuaternion< T > &rotation, const BasicQuaternion< T > &translation)
friend std::string format(const BasicDualQuaternion< T > &input)
static constexpr BasicDualQuaternion< T > identity()
static constexpr BasicDualQuaternion< T > encode_point(const BasicVector3D< T > &point)
constexpr BasicDual< T > normsquared() const
static constexpr BasicVector3D< T > decode_point(const BasicDualQuaternion< T > &encoded_point)
static constexpr BasicDualQuaternion< T > make_coordinate_system(const BasicQuaternion< T > &rotation, T translation_x, T translation_y, T translation_z)
const BasicQuaternion< T > & rotation() const
constexpr BasicDualQuaternion< T > normalized() const
BasicVector3D< T > translation() const
friend constexpr bool approximately_equal_to(const BasicDualQuaternion< T > &value_to_test, const BasicDualQuaternion< T > &value_it_should_be, T tolerance=T{0.0002})
constexpr BasicDualQuaternion(const BasicDual< BasicQuaternion< T > > &underlying_representation)
static constexpr BasicDualQuaternion< T > make_translation(T translation_x, T translation_y, T translation_z)
constexpr bool rotation_and_translation_are_orthogonal() const
const BasicQuaternion< T > & real() const
constexpr BasicDualQuaternion< T > conjugate() const
constexpr BasicDualQuaternion(const BasicQuaternion< T > &rotation, const BasicVector3D< T > &translation)
constexpr bool is_unit() const
const BasicQuaternion< T > & dual() const
T value_type
The underlying implementation type.
static constexpr BasicDualQuaternion< T > make_rotation(const BasicQuaternion< T > &rotation)
constexpr BasicDual< T > conjugate() const
Definition Dual.hpp:58
static constexpr BasicQuaternion< T > encode_point(T x, T y, T z)
static constexpr BasicQuaternion< T > identity()
BasicQuaternion representation of the real number 1.
static constexpr BasicQuaternion< T > zero()
BasicQuaternion representation of the real number 0.
friend void CHECK_IF_ZERO(const BasicDualQuaternion< T > &input, OT tolerance=OT{0.0002})
friend void CHECK_IF_EQUAL(const BasicDualQuaternion< T > &input, const BasicDualQuaternion< T > &near_to, OT tolerance=OT{0.0002})
friend void CHECK_IF_NOT_EQUAL(const BasicDualQuaternion< T > &input, const BasicDualQuaternion< T > &near_to, OT tolerance=OT{0.0002})
friend bool check_if_not_equal(const BasicDualQuaternion< T > &input, const BasicDualQuaternion< T > &near_to, OT tolerance=OT{0.0002})
friend bool check_if_equal(const BasicDualQuaternion< T > &input, const BasicDualQuaternion< T > &near_to, OT tolerance=OT{0.0002})
friend constexpr BasicDualQuaternion< T > operator+(const BasicDualQuaternion< T > &left_side, const BasicDualQuaternion< T > &right_side)
friend constexpr BasicDualQuaternion< T > operator/(const BasicDualQuaternion< T > &dual_quaternion, const BasicDual< T > &dual_scalar)
friend constexpr BasicDualQuaternion< T > operator*(T scalar, const BasicDualQuaternion< T > &dual_quaternion)
Definition Angle.hpp:16