11 #ifndef TurtleBrains_Quaternion_hpp
12 #define TurtleBrains_Quaternion_hpp
14 #include <turtle_brains/math/tb_math.hpp>
15 #include <turtle_brains/core/tb_configuration.hpp>
16 #include <turtle_brains/core/tb_error.hpp>
17 #include <turtle_brains/core/tb_defines.hpp>
18 #include <turtle_brains/math/tb_vector.hpp>
31 Vector3 MultiplyVector3Quaternion(
const Vector3& left,
const Quaternion& right);
32 Quaternion* QuaternionMultiply(Quaternion* result,
const Quaternion* left,
const Quaternion* right);
50 #if defined(tb_visual_cpp)
52 #pragma warning(disable: 4201)
53 struct {
float x, y, z, w; };
56 struct {
float x, y, z, w; };
90 inline Quaternion(
const float valueX,
const float valueY,
const float valueZ,
const float valueW) :
110 tb_error(
"Probably useful to explicitly convert (not copy value) see HAXE: from_angle_axis function");
119 x(componentArray[0]),
120 y(componentArray[1]),
121 z(componentArray[2]),
172 return (
true ==
IsEqual(x, other.x) &&
true ==
IsEqual(y, other.y) &&
173 true ==
IsEqual(z, other.z) &&
true ==
IsEqual(w, other.w)) ?
true :
false;
182 return (
true ==
operator==(other)) ?
false :
true;
188 inline operator const float*(void)
const {
return mComponents; }
194 inline operator float*(void) {
return mComponents; }
199 inline const float&
operator[](
const int index)
const {
return mComponents[index]; }
205 inline float&
operator[](
const int index) {
return mComponents[index]; }
207 #if defined(tb_with_math_operators)
212 inline Quaternion operator+(
const Quaternion& rightSide)
const {
return Quaternion(x + rightSide.x, y + rightSide.y, z + rightSide.z, w + rightSide.w); }
218 inline Quaternion& operator+=(
const Quaternion& rightSide) { x += rightSide.x; y += rightSide.y; z += rightSide.z; w += rightSide.w;
return *
this; }
223 inline Quaternion operator-(
const Quaternion& rightSide)
const {
return Quaternion(x - rightSide.x, y - rightSide.y, z - rightSide.z, w - rightSide.w); }
228 inline Quaternion& operator-=(
const Quaternion& rightSide) { x -= rightSide.x; y -= rightSide.y; z -= rightSide.z; w -= rightSide.w;
return *
this; }
235 Quaternion result(SkipInitialization::kSkipInitialization);
236 QuaternionMultiply(&result,
this, &rightSide);
246 Quaternion result(SkipInitialization::kSkipInitialization);
247 QuaternionMultiply(&result,
this, &rightSide);
255 inline Quaternion operator*(
float scalar)
const {
return Quaternion(x * scalar, y * scalar, z * scalar, w * scalar); }
261 friend Quaternion operator*(
float scalar,
const Quaternion& rightSide) {
return Quaternion(scalar * rightSide.x, scalar * rightSide.y, scalar * rightSide.z, scalar * rightSide.w); }
267 inline Quaternion& operator*=(
float scalar) { x *= scalar; y *= scalar; z *= scalar; w *= scalar;
return *
this; }
272 inline Quaternion operator/(
float scalar)
const {
return Quaternion(x / scalar, y / scalar, z / scalar, w / scalar); }
278 inline Quaternion& operator/=(
float scalar) { x /= scalar; y /= scalar; z /= scalar; w /= scalar;
return *
this; }
290 inline float Magnitude(
void)
const {
return sqrt((x * x) + (y * y) + (z * z) + (w * w)); }
296 inline float MagnitudeSquared(
void)
const {
return (x * x) + (y * y) + (z * z) + (w * w); }
306 return Quaternion(x / magnitude, y / magnitude, z / magnitude, w / magnitude);
317 if (
true ==
IsZero(magnitude))
339 return MultiplyVector3Quaternion(forward, *
this);
348 atan2f(2 * mComponents[1] * mComponents[3] - 2 * mComponents[0] * mComponents[2], 1 - 2 * powf(mComponents[1], 2) - 2 * powf(mComponents[2], 2)),
349 asinf(2 * mComponents[0] * mComponents[1] + 2 * mComponents[2] * mComponents[3]),
350 atan2f(2 * mComponents[0] * mComponents[3] - 2 * mComponents[1] * mComponents[2], 1 - 2 * powf(mComponents[0], 2) - 2 * powf(mComponents[2], 2))
361 const float s = sqrtf(1.0f - normalizedSelf.w * normalizedSelf.w);
363 axis = (s < 0.995f) ?
Vector3(normalizedSelf.x, normalizedSelf.y, normalizedSelf.z) :
364 Vector3(normalizedSelf.x / s, normalizedSelf.y / s, normalizedSelf.z / s);
372 const float s = sinf(angle.
AsRadians() * 0.5f);
373 const float c = cosf(angle.
AsRadians() * 0.5f);
374 return Quaternion(axis[0] * s, axis[1] * s, axis[2] * s, c);
386 Vector3 axis(SkipInitialization::kSkipInitialization);
396 const float halfHeading = euler.x * 0.5f;
397 const float halfPitch = euler.y * 0.5f;
398 const float halfRoll = euler.z * 0.5f;
400 const float c1 = cosf(halfHeading);
401 const float s1 = sinf(halfHeading);
402 const float c2 = cosf(halfPitch);
403 const float s2 = sinf(halfPitch);
404 const float c3 = cosf(halfRoll);
405 const float s3 = sinf(halfRoll);
406 const float c1c2 = c1*c2;
407 const float s1s2 = s1*s2;
436 inline Quaternion* QuaternionAdd(Quaternion* result,
const Quaternion* left,
const Quaternion* right)
438 tb_error_if(
nullptr == left,
"tbExternalError: Invalid parameter for left, expected valid pointer.");
439 tb_error_if(
nullptr == right,
"tbExternalError: Invalid parameter for right, expected valid pointer.");
440 tb_error_if(
nullptr == result,
"tbExternalError: Invalid parameter for result, expected valid pointer.");
442 result->x = left->x + right->x;
443 result->y = left->y + right->y;
444 result->z = left->z + right->z;
445 result->w = left->w + right->w;
459 inline Quaternion* QuaternionSubtract(Quaternion* result,
const Quaternion* left,
const Quaternion* right)
461 tb_error_if(
nullptr == left,
"tbExternalError: Invalid parameter for left, expected valid pointer.");
462 tb_error_if(
nullptr == right,
"tbExternalError: Invalid parameter for right, expected valid pointer.");
463 tb_error_if(
nullptr == result,
"tbExternalError: Invalid parameter for result, expected valid pointer.");
465 result->x = left->x - right->x;
466 result->y = left->y - right->y;
467 result->z = left->z - right->z;
468 result->w = left->w - right->w;
481 inline Quaternion* QuaternionMultiply(Quaternion* result,
const Quaternion* left,
const Quaternion* right)
483 tb_error_if(
nullptr == left,
"tbExternalError: Invalid parameter for left, expected valid pointer.");
484 tb_error_if(
nullptr == right,
"tbExternalError: Invalid parameter for right, expected valid pointer.");
485 tb_error_if(
nullptr == result,
"tbExternalError: Invalid parameter for result, expected valid pointer.");
486 tb_error_if(result == left || result == right,
"tbExternalError: Invalid parameter for result, expected different location than left or right.")
488 const Quaternion& a(*left);
489 const Quaternion& b(*right);
495 result->x = a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y;
496 result->y = a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z;
497 result->z = a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x;
498 result->w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
511 inline Quaternion* QuaternionScale(Quaternion* result, const Quaternion* input, const
float scalar)
513 tb_error_if(
nullptr == result,
"tbExternalError: Invalid parameter for result, expected valid pointer.");
514 tb_error_if(
nullptr == input,
"tbExternalError: Invalid parameter for input, expected valid pointer.");
516 result->x = input->x * scalar;
517 result->y = input->y * scalar;
518 result->z = input->z * scalar;
519 result->w = input->w * scalar;
532 inline Quaternion* QuaternionScaleDivide(Quaternion* result,
const Quaternion* input,
const float scalar)
534 tb_error_if(
nullptr == result,
"tbExternalError: Invalid parameter for result, expected valid pointer.");
535 tb_error_if(
nullptr == input,
"tbExternalError: Invalid parameter for input, expected valid pointer.");
537 result->x = input->x / scalar;
538 result->y = input->y / scalar;
539 result->z = input->z / scalar;
540 result->w = input->w / scalar;
553 inline Quaternion* QuaternionNegate(Quaternion* result,
const Quaternion* input)
555 tb_error_if(
nullptr == input,
"tbExternalError: Invalid parameter for input, expected valid pointer.");
556 tb_error_if(
nullptr == result,
"tbExternalError: Invalid parameter for result, expected valid pointer.");
558 result->x = -input->x;
559 result->y = -input->y;
560 result->z = -input->z;
561 result->w = -input->w;
568 inline float QuaternionMagnitude(
const Quaternion* input)
570 return sqrtf((input->x * input->x) + (input->y * input->y) + (input->z * input->z) + (input->w * input->w));
577 inline float QuaternionMagnitudeSquared(
const Quaternion* input)
579 return (input->x * input->x) + (input->y * input->y) + (input->z * input->z) + (input->w * input->w);
590 inline Quaternion* QuaternionNormalize(Quaternion* result,
const Quaternion* input)
592 tb_error_if(
nullptr == result,
"tbExternalError: Invalid parameter for result, expected valid pointer.");
593 tb_error_if(
nullptr == input,
"tbExternalError: Invalid parameter for input, expected valid pointer.");
595 const float magnitude = QuaternionMagnitude(input);
596 if (
true ==
IsZero(magnitude))
605 result->x = input->x / magnitude;
606 result->y = input->y / magnitude;
607 result->z = input->z / magnitude;
608 result->w = input->w / magnitude;
624 inline Quaternion* QuaternionNormalizeMagnitude(Quaternion* result,
const Quaternion* input,
float &magnitude)
626 tb_error_if(
nullptr == result,
"tbExternalError: Invalid parameter for result, expected valid pointer.");
627 tb_error_if(
nullptr == input,
"tbExternalError: Invalid parameter for input, expected valid pointer.");
629 magnitude = QuaternionMagnitude(input);
630 if (
true ==
IsZero(magnitude))
639 result->x = input->x / magnitude;
640 result->y = input->y / magnitude;
641 result->z = input->z / magnitude;
642 result->w = input->w / magnitude;
656 inline Quaternion* QuaternionInverse(Quaternion* result,
const Quaternion* input)
658 tb_error_if(
nullptr == input,
"tbExternalError: Invalid parameter for input, expected valid pointer.");
659 tb_error_if(
nullptr == result,
"tbExternalError: Invalid parameter for result, expected valid pointer.");
661 result->x = -input->x;
662 result->y = -input->y;
663 result->z = -input->z;
664 result->w = input->w;
668 inline float QuaternionDotProduct(
const Quaternion* leftSide,
const Quaternion* rightSide)
670 tb_error_if(
nullptr == leftSide,
"tbExternalError: Invalid parameter for leftSide, expected valid pointer.");
671 tb_error_if(
nullptr == rightSide,
"tbExternalError: Invalid parameter for rightSide, expected valid pointer.");
672 return (leftSide->x * rightSide->x) + (leftSide->y * rightSide->y) + (leftSide->z * rightSide->z) + (leftSide->w * rightSide->w);
676 inline Quaternion* QuaternionLerp(Quaternion* result,
const Quaternion* start,
const Quaternion*
final,
const float time)
678 tb_error_if(
nullptr == start,
"tbExternalError: Invalid parameter for start, expected valid pointer.");
679 tb_error_if(
nullptr ==
final,
"tbExternalError: Invalid parameter for final, expected valid pointer.");
680 tb_error_if(
nullptr == result,
"tbExternalError: Invalid parameter for result, expected valid pointer.");
681 tb_error_if(result == start || result ==
final,
"tbExternalError: Invalid parameter for result, expected different location than start or final.")
684 QuaternionSubtract(result, final, start);
685 QuaternionScale(result, result, time);
686 QuaternionAdd(result, start, result);
692 inline Quaternion QuaternionSlerp(const Quaternion& start, const Quaternion& final, const
float time)
696 float dot = QuaternionDotProduct(&start, &
final);
701 QuaternionNegate(&a, &start);
708 QuaternionLerp(&result, &start, &
final, time);
715 Quaternion temporary;
716 QuaternionScale(&temporary, &a, dot);
717 QuaternionSubtract(&temporary, &
final, &temporary);
718 temporary.Normalize();
720 const float theta = acosf(dot) * time;
721 QuaternionScale(&temporary, &temporary, sinf(theta));
722 QuaternionScale(&a, &a, cosf(theta));
725 Quaternion result(SkipInitialization::kSkipInitialization);
726 QuaternionAdd(&result, &a, &temporary);
730 inline Vector3 MultiplyVector3Quaternion(
const Vector3& left,
const Quaternion& right)
732 Vector3 uv(SkipInitialization::kSkipInitialization);
733 Vector3 uuv(SkipInitialization::kSkipInitialization);
736 return left + ((uv * right.w) + uuv) * 2.0f;
static Quaternion FromEuler(const Vector3 &euler)
Definition: tb_quaternion.hpp:394
AngleType< float > Angle
Definition: tb_angle.hpp:154
bool operator!=(const Quaternion &other) const
Definition: tb_quaternion.hpp:180
Quaternion(const float *componentArray)
Definition: tb_quaternion.hpp:118
Type AsRadians(void) const
Definition: tb_angle.hpp:79
Contains objects and functions for dealing with Vector and Matrix math.
static Quaternion Identity(void)
Definition: tb_quaternion.hpp:44
bool operator==(const Quaternion &other) const
Definition: tb_quaternion.hpp:170
#define tb_error(message,...)
Definition: tb_error.hpp:23
static Quaternion FromForward(const Vector3 &forward, const Vector3 *up=nullptr)
Definition: tb_quaternion.hpp:380
Quaternion(const SkipInitialization &fastAndStupid)
Definition: tb_quaternion.hpp:66
Definition: tb_vector.hpp:317
Vector3 ToEuler(void) const
Definition: tb_quaternion.hpp:345
Definition: tb_matrix.hpp:111
Vector3 ApplyForward(const Vector3 &forward) const
Definition: tb_quaternion.hpp:337
float Magnitude(void) const
Definition: tb_quaternion.hpp:290
bool IsZero(const Type &value)
Definition: tb_math.hpp:53
Quaternion & operator=(const Quaternion &other)
Definition: tb_quaternion.hpp:152
Definition: tb_quaternion.hpp:38
Quaternion(const Quaternion &other)
Definition: tb_quaternion.hpp:132
Here is some information about the primary namespace.
Definition: tb_application_dialog.hpp:21
#define tb_unused(parameter)
Definition: tb_defines.hpp:25
constexpr const T & Clamp(const T &value, const T &minimumValue, const T &maximumValue) noexcept
Definition: tb_math.hpp:106
Quaternion GetNormalized(void) const
Definition: tb_quaternion.hpp:302
Definition: tb_matrix.hpp:527
SkipInitialization
Definition: tb_vector.hpp:30
static Quaternion FromAngleAxis(const Angle angle, const Vector3 &axis)
Definition: tb_quaternion.hpp:370
bool IsEqual(const Type &leftValue, const Type &rightValue)
Definition: tb_math.hpp:30
Specifies the angle input value is in units of Radians.
float MagnitudeSquared(void) const
Definition: tb_quaternion.hpp:296
float & operator[](const int index)
Definition: tb_quaternion.hpp:205
const float & operator[](const int index) const
Definition: tb_quaternion.hpp:199
Quaternion(const float valueX, const float valueY, const float valueZ, const float valueW)
Definition: tb_quaternion.hpp:90
float Vector3DotProduct(const Vector3 *leftSide, const Vector3 *rightSide)
Definition: tb_vector.hpp:1204
~Quaternion(void)
Definition: tb_quaternion.hpp:143
Vector3 * Vector3CrossProduct(Vector3 *result, const Vector3 *leftSide, const Vector3 *rightSide)
Definition: tb_vector.hpp:1234
Quaternion(const Vector3 &other, const float valueW)
Definition: tb_quaternion.hpp:104
Definition: tb_angle.hpp:34
float Normalize(void)
Definition: tb_quaternion.hpp:314
void ToAngleAxis(Angle &angle, Vector3 &axis) const
Definition: tb_quaternion.hpp:357
#define tb_error_if(errorTest, message,...)
Definition: tb_error.hpp:42
Quaternion(void)
Definition: tb_quaternion.hpp:74