TurtleBrains  0.3.5
High quality, portable, C++ framework for rapid 2D game development.
tb_quaternion.hpp
1 
11 #ifndef TurtleBrains_Quaternion_hpp
12 #define TurtleBrains_Quaternion_hpp
13 
14 #include <turtle_brains/math/tb_math.hpp>
15 #include <turtle_brains/math/tb_interpolation.hpp>
16 #include <turtle_brains/core/tb_configuration.hpp>
17 #include <turtle_brains/core/tb_error.hpp>
18 #include <turtle_brains/core/tb_defines.hpp> //For tb_unsused
19 #include <turtle_brains/math/tb_vector.hpp> //For SkipInitialization
20 #include <turtle_brains/math/tb_angle.hpp>
21 
22 namespace TurtleBrains
23 {
24  namespace Math
25  {
26  template<typename Type> class TypedMatrix3;
27  template<typename Type> class TypedMatrix4;
28  template<typename Type> class TypedQuaternion;
29 
30  typedef TypedQuaternion<float> Quaternion;
31 
32  template<typename Type> TypedVector3<Type> MultiplyVector3Quaternion(const TypedVector3<Type>& left, const TypedQuaternion<Type>& right);
33  template<typename Type> TypedQuaternion<Type>* QuaternionMultiply(TypedQuaternion<Type>* result,
34  const TypedQuaternion<Type>* left, const TypedQuaternion<Type>* right);
35 
40  template<typename Type> class TypedQuaternion
41  {
42  public:
46  static TypedQuaternion Identity(void) { return TypedQuaternion(Type(0), Type(0), Type(0), Type(1)); }
47 
48  union
49  {
50  Type mComponents[4];
51 
52 #if defined(tb_visual_cpp)
53 #pragma warning(push)
54 #pragma warning(disable: 4201)
55  struct { Type x, y, z, w; };
56 #pragma warning(pop)
57 #else
58  struct { Type x, y, z, w; };
59 #endif
60  };
61 
68  inline explicit TypedQuaternion(const SkipInitialization& fastAndStupid)
69  {
70  tb_unused(fastAndStupid);
71  }
72 
76  inline TypedQuaternion(void) :
77  x(Type(0)),
78  y(Type(0)),
79  z(Type(0)),
80  w(Type(1))
81  {
82  }
83 
92  inline TypedQuaternion(const Type valueX, const Type valueY, const Type valueZ, const Type valueW) :
93  x(valueX),
94  y(valueY),
95  z(valueZ),
96  w(valueW)
97  {
98  }
99 
106  inline explicit TypedQuaternion(const TypedVector3<Type>& other, const Type valueW) :
107  x(other.x),
108  y(other.y),
109  z(other.z),
110  w(valueW)
111  {
112  tb_error("Probably useful to explicitly convert (not copy value) see HAXE: from_angle_axis function");
113  }
114 
120  inline explicit TypedQuaternion(const Type* componentArray) :
121  x(componentArray[0]),
122  y(componentArray[1]),
123  z(componentArray[2]),
124  w(componentArray[3])
125  {
126  }
127 
134  inline TypedQuaternion(const TypedQuaternion& other) :
135  x(other.x),
136  y(other.y),
137  z(other.z),
138  w(other.w)
139  {
140  }
141 
146  {
147  }
148 
155  {
156  x = other.x;
157  y = other.y;
158  z = other.z;
159  w = other.w;
160  return *this;
161  }
162 
172  inline bool operator==(const TypedQuaternion& other) const
173  {
174  return (true == IsEqual(x, other.x) && true == IsEqual(y, other.y) &&
175  true == IsEqual(z, other.z) && true == IsEqual(w, other.w)) ? true : false;
176  }
177 
182  inline bool operator!=(const TypedQuaternion& other) const
183  {
184  return (true == operator==(other)) ? false : true;
185  }
186 
190  inline operator const Type*(void) const
191  {
192  return mComponents;
193  }
194 
199  inline operator Type*(void)
200  {
201  return mComponents;
202  }
203 
207  template<typename ToType> explicit operator TypedQuaternion<ToType>(void) const
208  {
209  return TypedQuaternion<ToType>(static_cast<ToType>(x), static_cast<ToType>(y),
210  static_cast<ToType>(z), static_cast<ToType>(w));
211  }
212 
216  inline const Type& operator[](const int index) const
217  {
218  return mComponents[index];
219  }
220 
225  inline Type& operator[](const int index)
226  {
227  return mComponents[index];
228  }
229 
230 #if defined(tb_with_math_operators)
231 
235  inline TypedQuaternion operator+(const TypedQuaternion& rightSide) const
236  {
237  return TypedQuaternion(x + rightSide.x, y + rightSide.y, z + rightSide.z, w + rightSide.w);
238  }
239 
244  inline TypedQuaternion& operator+=(const TypedQuaternion& rightSide)
245  {
246  x += rightSide.x; y += rightSide.y; z += rightSide.z; w += rightSide.w;
247  return *this;
248  }
249 
253  inline TypedQuaternion operator-(const TypedQuaternion& rightSide) const
254  {
255  return TypedQuaternion(x - rightSide.x, y - rightSide.y, z - rightSide.z, w - rightSide.w);
256  }
257 
261  inline TypedQuaternion& operator-=(const TypedQuaternion& rightSide)
262  {
263  x -= rightSide.x; y -= rightSide.y; z -= rightSide.z; w -= rightSide.w;
264  return *this;
265  }
266 
270  inline TypedQuaternion operator*(const TypedQuaternion& rightSide) const
271  {
272  TypedQuaternion result(SkipInitialization::kSkipInitialization);
273  QuaternionMultiply(&result, this, &rightSide);
274  return result;
275  }
276 
281  inline TypedQuaternion operator*=(const TypedQuaternion& rightSide)
282  {
283  TypedQuaternion result(SkipInitialization::kSkipInitialization);
284  QuaternionMultiply(&result, this, &rightSide);
285  *this = result;
286  return *this;
287  }
288 
292  inline TypedQuaternion operator*(Type scalar) const
293  {
294  return TypedQuaternion(x * scalar, y * scalar, z * scalar, w * scalar);
295  }
296 
301  friend TypedQuaternion operator*(Type scalar, const TypedQuaternion& rightSide)
302  {
303  return TypedQuaternion(scalar * rightSide.x, scalar * rightSide.y, scalar * rightSide.z, scalar * rightSide.w);
304  }
305 
310  inline TypedQuaternion& operator*=(Type scalar)
311  {
312  x *= scalar; y *= scalar; z *= scalar; w *= scalar;
313  return *this;
314  }
315 
319  inline TypedQuaternion operator/(Type scalar) const
320  {
321  return TypedQuaternion(x / scalar, y / scalar, z / scalar, w / scalar);
322  }
323 
328  inline TypedQuaternion& operator/=(Type scalar)
329  {
330  x /= scalar;
331  y /= scalar;
332  z /= scalar;
333  w /= scalar;
334  return *this;
335  }
336 
340  inline TypedQuaternion operator-(void) const
341  {
342  return TypedQuaternion(-x, -y, -z, -w);
343  }
344 
345 #endif /* tb_math_with_operators */
346 
351  inline Type Magnitude(void) const
352  {
353  return sqrt((x * x) + (y * y) + (z * z) + (w * w));
354  }
355 
360  inline Type MagnitudeSquared(void) const
361  {
362  return (x * x) + (y * y) + (z * z) + (w * w);
363  }
364 
369  inline TypedQuaternion GetNormalized(void) const
370  {
371  const Type magnitude(Magnitude());
372  if (true == IsZero(magnitude)) { return Identity(); }
373  return TypedQuaternion(x / magnitude, y / magnitude, z / magnitude, w / magnitude);
374  }
375 
380  inline Type Normalize(void)
381  {
382  const Type magnitude(Magnitude());
383  if (true == IsZero(magnitude))
384  {
385  *this = Identity();
386  }
387  else
388  {
389  x /= magnitude;
390  y /= magnitude;
391  z /= magnitude;
392  w /= magnitude;
393  }
394  return magnitude;
395  }
396 
401  {
402  return MultiplyVector3Quaternion(forward, *this);
403  }
404 
413  inline TypedVector3<Type> ToEuler(const AngleUnit& angleUnits) const
414  {
415  //return TypedVector3<Type>(
416  // TypedAngle<Type>(std::atan2(Type(2) * mComponents[1] * mComponents[3] - Type(2) * mComponents[0] * mComponents[2],
417  // Type(1) - Type(2) * std::pow(mComponents[1], Type(2)) - Type(2) * std::pow(mComponents[2], Type(2))),
418  // AngleUnit::Radians).As(angleUnits), // heading
419 
420  // TypedAngle<Type>(std::asin(Type(2) * mComponents[0] * mComponents[1] + 2 * mComponents[2] * mComponents[3]),
421  // AngleUnit::Radians).As(angleUnits), // attitude
422 
423  // TypedAngle<Type>(std::atan2(Type(2) * mComponents[0] * mComponents[3] - Type(2) * mComponents[1] * mComponents[2],
424  // Type(1) - Type(2) * std::pow(mComponents[0], Type(2)) - Type(2) * std::pow(mComponents[2], Type(2))),
425  // AngleUnit::Radians).As(angleUnits) // bank
426  //);
427 
428  //return TypedVector3<Type>(
429  // TypedAngle<Type>(std::asin(Type(2) * mComponents[0] * mComponents[1] + 2 * mComponents[2] * mComponents[3]),
430  // AngleUnit::Radians).As(angleUnits), // attitude
431 
432  // TypedAngle<Type>(std::atan2(Type(2) * mComponents[1] * mComponents[3] - Type(2) * mComponents[0] * mComponents[2],
433  // Type(1) - Type(2) * std::pow(mComponents[1], Type(2)) - Type(2) * std::pow(mComponents[2], Type(2))),
434  // AngleUnit::Radians).As(angleUnits), // heading
435 
436  // TypedAngle<Type>(std::atan2(Type(2) * mComponents[0] * mComponents[3] - Type(2) * mComponents[1] * mComponents[2],
437  // Type(1) - Type(2) * std::pow(mComponents[0], Type(2)) - Type(2) * std::pow(mComponents[2], Type(2))),
438  // AngleUnit::Radians).As(angleUnits) // bank
439  //);
440 
441  return TypedVector3<Type>(
442  TypedAngle<Type>(std::atan2(Type(2) * mComponents[0] * mComponents[3] - Type(2) * mComponents[1] * mComponents[2],
443  Type(1) - Type(2) * std::pow(mComponents[0], Type(2)) - Type(2) * std::pow(mComponents[2], Type(2))),
444  AngleUnit::Radians).As(angleUnits), // bank
445 
446  TypedAngle<Type>(std::atan2(Type(2) * mComponents[1] * mComponents[3] - Type(2) * mComponents[0] * mComponents[2],
447  Type(1) - Type(2) * std::pow(mComponents[1], Type(2)) - Type(2) * std::pow(mComponents[2], Type(2))),
448  AngleUnit::Radians).As(angleUnits), // heading
449 
450  TypedAngle<Type>(std::asin(Type(2) * mComponents[0] * mComponents[1] + 2 * mComponents[2] * mComponents[3]),
451  AngleUnit::Radians).As(angleUnits) // attitude
452  );
453  }
454 
458  inline void ToAngleAxis(TypedAngle<Type>& angle, TypedVector3<Type>& axis) const
459  {
460  const TypedQuaternion normalizedSelf((w > Type(1.0) || w < Type(-1.0)) ? GetNormalized() : *this);
461 
462  const Type s = std::sqrt(Type(1.0) - normalizedSelf.w * normalizedSelf.w); //var s = Math.sqrt(1 - a[3] * a[3]);
463  angle = TypedAngle<Type>(Type(2.0) * std::acos(normalizedSelf.w), AngleUnit::Radians);
464  axis = (s < Type(0.995)) ? Vector3(normalizedSelf.x, normalizedSelf.y, normalizedSelf.z) :
465  Vector3(normalizedSelf.x / s, normalizedSelf.y / s, normalizedSelf.z / s);
466  }
467 
471  inline static TypedQuaternion FromAngleAxis(const TypedAngle<Type> angle, const TypedVector3<Type>& axis)
472  {
473  const Type s = std::sin(angle.AsRadians() * Type(0.5));
474  const Type c = std::cos(angle.AsRadians() * Type(0.5));
475  return TypedQuaternion(axis[0] * s, axis[1] * s, axis[2] * s, c);
476  }
477 
481  inline static TypedQuaternion FromForward(const TypedVector3<Type>& forward, const TypedVector3<Type>* up = nullptr)
482  {
483  const TypedVector3<Type> unitForward = forward.GetNormalized();
484  const TypedVector3<Type> unitUp = ((nullptr == up) ? TypedVector3<Type>(Type(0.0), Type(1.0), Type(0.0)) : up->GetNormalized());
485 
486  const Type dot = Vector3DotProduct(&unitUp, &unitForward);
487  Vector3 axis(SkipInitialization::kSkipInitialization);
488  Vector3CrossProduct(&axis, &unitUp, &unitForward);
489  return TypedQuaternion(axis, dot + Type(1.0));
490  }
491 
495  inline static TypedQuaternion FromEuler(const TypedVector3<Type>& euler, const tbMath::AngleUnit& angleUnits)
496  {
497  const Type halfHeading = TypedAngle<Type>(euler.x * Type(0.5), angleUnits).AsRadians();
498  const Type halfPitch = TypedAngle<Type>(euler.y * Type(0.5), angleUnits).AsRadians();
499  const Type halfRoll = TypedAngle<Type>(euler.z * Type(0.5), angleUnits).AsRadians();
500 
501  const Type c1 = std::cos(halfHeading);
502  const Type s1 = std::sin(halfHeading);
503  const Type c2 = std::cos(halfPitch);
504  const Type s2 = std::sin(halfPitch);
505  const Type c3 = std::cos(halfRoll);
506  const Type s3 = std::sin(halfRoll);
507  const Type c1c2 = c1*c2;
508  const Type s1s2 = s1*s2;
509  return TypedQuaternion(
510  c1c2*s3 + s1s2*c3,
511  s1*c2*c3 + c1*s2*s3,
512  c1*s2*c3 - s1*c2*s3,
513  c1c2*c3 - s1s2*s3
514  );
515  }
516 
517  //These are defined in tb_matrix_quaternion.hpp
518  static TypedQuaternion FromMatrix(const TypedMatrix3<Type>& matrix);
519  static TypedQuaternion FromMatrix(const TypedMatrix4<Type>& matrix);
520 
521  };
522 
523 //--------------------------------------------------------------------------------------------------------------------//
524 //--------------------------------------------------------------------------------------------------------------------//
525 //--------------------------------------------------------------------------------------------------------------------//
526 
538  const TypedQuaternion<Type>* left, const TypedQuaternion<Type>* right)
539  {
540  tb_error_if(nullptr == left, "tbExternalError: Invalid parameter for left, expected valid pointer.");
541  tb_error_if(nullptr == right, "tbExternalError: Invalid parameter for right, expected valid pointer.");
542  tb_error_if(nullptr == result, "tbExternalError: Invalid parameter for result, expected valid pointer.");
543 
544  result->x = left->x + right->x;
545  result->y = left->y + right->y;
546  result->z = left->z + right->z;
547  result->w = left->w + right->w;
548  return result;
549  }
550 
562  const TypedQuaternion<Type>* left, const TypedQuaternion<Type>* right)
563  {
564  tb_error_if(nullptr == left, "tbExternalError: Invalid parameter for left, expected valid pointer.");
565  tb_error_if(nullptr == right, "tbExternalError: Invalid parameter for right, expected valid pointer.");
566  tb_error_if(nullptr == result, "tbExternalError: Invalid parameter for result, expected valid pointer.");
567 
568  result->x = left->x - right->x;
569  result->y = left->y - right->y;
570  result->z = left->z - right->z;
571  result->w = left->w - right->w;
572  return result;
573  }
574 
585  const TypedQuaternion<Type>* left, const TypedQuaternion<Type>* right)
586  {
587  tb_error_if(nullptr == left, "tbExternalError: Invalid parameter for left, expected valid pointer.");
588  tb_error_if(nullptr == right, "tbExternalError: Invalid parameter for right, expected valid pointer.");
589  tb_error_if(nullptr == result, "tbExternalError: Invalid parameter for result, expected valid pointer.");
590  tb_error_if(result == left || result == right, "tbExternalError: Invalid parameter for result, expected different location than left or right.")
591 
592  const TypedQuaternion<Type>& a(*left);
593  const TypedQuaternion<Type>& b(*right);
594  //(*result)[0] = a[0] * b[3] + a[3] * b[0] + a[1] * b[2] - a[2] * b[1];
595  //(*result)[1] = a[1] * b[3] + a[3] * b[1] + a[2] * b[0] - a[0] * b[2];
596  //(*result)[2] = a[2] * b[3] + a[3] * b[2] + a[0] * b[1] - a[1] * b[0];
597  //(*result)[3] = a[3] * b[3] - a[0] * b[0] - a[1] * b[1] - a[2] * b[2];
598 
599  result->x = a.x * b.w + a.w * b.x + a.y * b.z - a.z * b.y;
600  result->y = a.y * b.w + a.w * b.y + a.z * b.x - a.x * b.z;
601  result->z = a.z * b.w + a.w * b.z + a.x * b.y - a.y * b.x;
602  result->w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z;
603  return result;
604  }
605 
616  const TypedQuaternion<Type>* input, const Type scalar)
617  {
618  tb_error_if(nullptr == result, "tbExternalError: Invalid parameter for result, expected valid pointer.");
619  tb_error_if(nullptr == input, "tbExternalError: Invalid parameter for input, expected valid pointer.");
620 
621  result->x = input->x * scalar;
622  result->y = input->y * scalar;
623  result->z = input->z * scalar;
624  result->w = input->w * scalar;
625  return result;
626  }
627 
638  const TypedQuaternion<Type>* input, const Type scalar)
639  {
640  tb_error_if(nullptr == result, "tbExternalError: Invalid parameter for result, expected valid pointer.");
641  tb_error_if(nullptr == input, "tbExternalError: Invalid parameter for input, expected valid pointer.");
642 
643  result->x = input->x / scalar;
644  result->y = input->y / scalar;
645  result->z = input->z / scalar;
646  result->w = input->w / scalar;
647  return result;
648  }
649 
660  {
661  tb_error_if(nullptr == input, "tbExternalError: Invalid parameter for input, expected valid pointer.");
662  tb_error_if(nullptr == result, "tbExternalError: Invalid parameter for result, expected valid pointer.");
663 
664  result->x = -input->x;
665  result->y = -input->y;
666  result->z = -input->z;
667  result->w = -input->w;
668  return result;
669  }
670 
674  template<typename Type> Type QuaternionMagnitude(const TypedQuaternion<Type>* input)
675  {
676  return std::sqrt((input->x * input->x) + (input->y * input->y) + (input->z * input->z) + (input->w * input->w));
677  }
678 
683  template<typename Type> Type QuaternionMagnitudeSquared(const TypedQuaternion<Type>* input)
684  {
685  return (input->x * input->x) + (input->y * input->y) + (input->z * input->z) + (input->w * input->w);
686  }
687 
697  {
698  tb_error_if(nullptr == result, "tbExternalError: Invalid parameter for result, expected valid pointer.");
699  tb_error_if(nullptr == input, "tbExternalError: Invalid parameter for input, expected valid pointer.");
700 
701  const Type magnitude = QuaternionMagnitude(input);
702  if (true == IsZero(magnitude))
703  {
704  result->x = Type(0.0);
705  result->y = Type(0.0);
706  result->z = Type(0.0);
707  result->w = Type(1.0);
708  }
709  else
710  {
711  result->x = input->x / magnitude;
712  result->y = input->y / magnitude;
713  result->z = input->z / magnitude;
714  result->w = input->w / magnitude;
715  }
716  return result;
717  }
718 
731  const TypedQuaternion<Type>* input, Type& magnitude)
732  {
733  tb_error_if(nullptr == result, "tbExternalError: Invalid parameter for result, expected valid pointer.");
734  tb_error_if(nullptr == input, "tbExternalError: Invalid parameter for input, expected valid pointer.");
735 
736  magnitude = QuaternionMagnitude(input);
737  if (true == IsZero(magnitude))
738  {
739  result->x = 0.0f;
740  result->y = 0.0f;
741  result->z = 0.0f;
742  result->w = 1.0f;
743  }
744  else
745  {
746  result->x = input->x / magnitude;
747  result->y = input->y / magnitude;
748  result->z = input->z / magnitude;
749  result->w = input->w / magnitude;
750  }
751  return result;
752  }
753 
764  {
765  tb_error_if(nullptr == input, "tbExternalError: Invalid parameter for input, expected valid pointer.");
766  tb_error_if(nullptr == result, "tbExternalError: Invalid parameter for result, expected valid pointer.");
767 
768  result->x = -input->x;
769  result->y = -input->y;
770  result->z = -input->z;
771  result->w = input->w;
772  return result;
773  }
774 
775  template<typename Type> Type QuaternionDotProduct(const TypedQuaternion<Type>* leftSide, const TypedQuaternion<Type>* rightSide)
776  {
777  tb_error_if(nullptr == leftSide, "tbExternalError: Invalid parameter for leftSide, expected valid pointer.");
778  tb_error_if(nullptr == rightSide, "tbExternalError: Invalid parameter for rightSide, expected valid pointer.");
779  return (leftSide->x * rightSide->x) + (leftSide->y * rightSide->y) + (leftSide->z * rightSide->z) + (leftSide->w * rightSide->w);
780  }
781 
782  //Linear Interpolation
783  template<typename Type> TypedQuaternion<Type>* QuaternionLerp(TypedQuaternion<Type>* result,
784  const TypedQuaternion<Type>* start, const TypedQuaternion<Type>* final, const Type time)
785  {
786  tb_error_if(nullptr == start, "tbExternalError: Invalid parameter for start, expected valid pointer.");
787  tb_error_if(nullptr == final, "tbExternalError: Invalid parameter for final, expected valid pointer.");
788  tb_error_if(nullptr == result, "tbExternalError: Invalid parameter for result, expected valid pointer.");
789  tb_error_if(result == start || result == final, "tbExternalError: Invalid parameter for result, expected different location than start or final.")
790 
791 
792  //QuaternionSubtract(result, final, start); // b - a
793  //QuaternionScale(result, result, time); //(b - a) * t
794  //QuaternionAdd(result, start, result); //result = a + (b - a) * t;
795  //return QuaternionNormalize(result, result);
796 
797  //result = a * (1 - t) + b * t; (this fixes an f32 numerical bug shakesoda fought)
798  TypedQuaternion<Type> resultB;
799  QuaternionScale(result, start, Type(1.0) - time); //a * (1 - t)
800  QuaternionScale(&resultB, final, time); //b * t
801  QuaternionAdd(result, result, &resultB); // +
802  return QuaternionNormalize(result, result);
803  }
804 
805  //Spherical Interpolation
806  template<typename Type> TypedQuaternion<Type> QuaternionSlerp(const TypedQuaternion<Type>& start,
807  const TypedQuaternion<Type>& final, const Type time)
808  {
811 
812  //TypedQuaternion<Type> z = final;
813 
814  //Type cosTheta = QuaternionDotProduct(&start, &final);
815 
818  //if (cosTheta < Type(0.0))
819  //{
820  // z = -final;
821  // cosTheta = -cosTheta;
822  //}
823 
825  //if (cosTheta > Type(1.0) - Type(0.00001))
826  //{
827  // // Linear interpolation
828  // return TypedQuaternion<Type>(
829  // tbMath::Interpolation::Linear(start.x, z.x, time),
830  // tbMath::Interpolation::Linear(start.y, z.y, time),
831  // tbMath::Interpolation::Linear(start.z, z.z, time),
832  // tbMath::Interpolation::Linear(start.w, z.w, time));
833  //}
834  //else
835  //{
836  // // Essential Mathematics, page 467
837  // Type angle = acos(cosTheta);
838  // return (sin((static_cast<Type>(1.0) - time) * angle) * start + sin(time * angle) * z) / sin(angle);
839  //}
840 
841 
842 
843 
844 
845  //a = start, b = final
846  Type dot = QuaternionDotProduct(&start, &final);
847 
848  TypedQuaternion<Type> a(start);
849  if (dot < Type(0.0))
850  {
851  QuaternionNegate(&a, &start);
852  dot = -dot;
853  }
854 
855  if (dot > Type(0.995))
856  { //Too close to bother with.
857  TypedQuaternion<Type> result;
858  QuaternionLerp(&result, &start, &final, time);
859  return result;
860  }
861 
862  //If inputs are already normalized, this winds up doing nothing.
863  dot = tbMath::Clamp(dot, Type(-1.0), Type(1.0));
864 
865  TypedQuaternion<Type> temporary; //= b - a * d;
866  QuaternionScale(&temporary, &a, dot); //a * dot
867  QuaternionSubtract(&temporary, &final, &temporary); //b - (a * dot)
868  temporary.Normalize();
869 
870  const Type theta = std::acos(dot) * time;
871  QuaternionScale(&temporary, &temporary, sinf(theta));
872  QuaternionScale(&a, &a, std::cos(theta));
873 
874  //return a * Math.cos(theta) + c * Math.sin(theta);
875  TypedQuaternion<Type> result(SkipInitialization::kSkipInitialization);
876  QuaternionAdd(&result, &a, &temporary);
877  return result;
878  }
879 
880  template<typename Type> TypedVector3<Type> MultiplyVector3Quaternion(const TypedVector3<Type>& left,
881  const TypedQuaternion<Type>& right)
882  {
883  TypedVector3<Type> uv(SkipInitialization::kSkipInitialization);
884  TypedVector3<Type> uuv(SkipInitialization::kSkipInitialization);
885  TypedVector3<Type> quat3(right[0], right[1], right[2]);
886 
887  Vector3CrossProduct(&uv, &quat3, &left);
888  Vector3CrossProduct(&uuv, &quat3, &uv);
889  return left + ((uv * right.w) + uuv) * Type(2.0);
890  }
891 
892  template<typename Type> std::ostream& operator<<(std::ostream& output, const tbMath::TypedQuaternion<Type>& data)
893  {
894  output << "{ " << data.x << ", " << data.y << ", " << data.z << ", " << data.w << " }";
895  return output;
896  }
897 
898  }; /* namespace Math */
899 }; /* namespace TurtleBrains */
900 
901 namespace tbMath = TurtleBrains::Math;
902 
903 #endif /* TurtleBrains_Quaternion_hpp */
Definition: tb_angle.hpp:38
Type AsRadians(void) const
Definition: tb_angle.hpp:87
Definition: tb_matrix.hpp:156
Definition: tb_matrix.hpp:596
Definition: tb_quaternion.hpp:41
const Type & operator[](const int index) const
Definition: tb_quaternion.hpp:216
static TypedQuaternion FromEuler(const TypedVector3< Type > &euler, const tbMath::AngleUnit &angleUnits)
Definition: tb_quaternion.hpp:495
Type & operator[](const int index)
Definition: tb_quaternion.hpp:225
static TypedQuaternion Identity(void)
Definition: tb_quaternion.hpp:46
TypedQuaternion(const Type *componentArray)
Definition: tb_quaternion.hpp:120
TypedVector3< Type > ApplyForward(const TypedVector3< Type > &forward) const
Definition: tb_quaternion.hpp:400
TypedQuaternion(void)
Definition: tb_quaternion.hpp:76
Type Magnitude(void) const
Definition: tb_quaternion.hpp:351
void ToAngleAxis(TypedAngle< Type > &angle, TypedVector3< Type > &axis) const
Definition: tb_quaternion.hpp:458
Type MagnitudeSquared(void) const
Definition: tb_quaternion.hpp:360
~TypedQuaternion(void)
Definition: tb_quaternion.hpp:145
TypedQuaternion(const SkipInitialization &fastAndStupid)
Definition: tb_quaternion.hpp:68
Type Normalize(void)
Definition: tb_quaternion.hpp:380
bool operator==(const TypedQuaternion &other) const
Definition: tb_quaternion.hpp:172
TypedQuaternion(const TypedVector3< Type > &other, const Type valueW)
Definition: tb_quaternion.hpp:106
bool operator!=(const TypedQuaternion &other) const
Definition: tb_quaternion.hpp:182
TypedQuaternion & operator=(const TypedQuaternion &other)
Definition: tb_quaternion.hpp:154
TypedVector3< Type > ToEuler(const AngleUnit &angleUnits) const
Definition: tb_quaternion.hpp:413
TypedQuaternion(const Type valueX, const Type valueY, const Type valueZ, const Type valueW)
Definition: tb_quaternion.hpp:92
TypedQuaternion GetNormalized(void) const
Definition: tb_quaternion.hpp:369
static TypedQuaternion FromForward(const TypedVector3< Type > &forward, const TypedVector3< Type > *up=nullptr)
Definition: tb_quaternion.hpp:481
TypedQuaternion(const TypedQuaternion &other)
Definition: tb_quaternion.hpp:134
static TypedQuaternion FromAngleAxis(const TypedAngle< Type > angle, const TypedVector3< Type > &axis)
Definition: tb_quaternion.hpp:471
Definition: tb_vector.hpp:472
#define tb_unused(parameter)
Definition: tb_defines.hpp:25
#define tb_error(message,...)
Definition: tb_error.hpp:23
#define tb_error_if(errorTest, message,...)
Definition: tb_error.hpp:42
Contains objects and functions for dealing with Vector and Matrix math.
TypedQuaternion< Type > * QuaternionMultiply(TypedQuaternion< Type > *result, const TypedQuaternion< Type > *left, const TypedQuaternion< Type > *right)
Definition: tb_quaternion.hpp:584
Type Vector3DotProduct(const TypedVector3< Type > *leftSide, const TypedVector3< Type > *rightSide)
Definition: tb_vector.hpp:1618
Type QuaternionMagnitudeSquared(const TypedQuaternion< Type > *input)
Definition: tb_quaternion.hpp:683
TypedQuaternion< Type > * QuaternionNormalize(TypedQuaternion< Type > *result, const TypedQuaternion< Type > *input)
Definition: tb_quaternion.hpp:696
std::ostream & operator<<(std::ostream &output, const tbMath::TypedAngle< Type > &angle)
Definition: tb_angle.hpp:203
bool IsZero(const Type &value, const Type tolerance=tbMath::kTolerance)
Definition: tb_math.hpp:74
bool IsEqual(const Type &leftValue, const Type &rightValue, const Type tolerance=tbMath::kTolerance)
Definition: tb_math.hpp:56
TypedQuaternion< Type > * QuaternionNormalizeMagnitude(TypedQuaternion< Type > *result, const TypedQuaternion< Type > *input, Type &magnitude)
Definition: tb_quaternion.hpp:730
TypedQuaternion< Type > * QuaternionInverse(TypedQuaternion< Type > *result, const TypedQuaternion< Type > *input)
Definition: tb_quaternion.hpp:763
TypedQuaternion< Type > * QuaternionSubtract(TypedQuaternion< Type > *result, const TypedQuaternion< Type > *left, const TypedQuaternion< Type > *right)
Definition: tb_quaternion.hpp:561
TypedQuaternion< Type > * QuaternionAdd(TypedQuaternion< Type > *result, const TypedQuaternion< Type > *left, const TypedQuaternion< Type > *right)
Definition: tb_quaternion.hpp:537
SkipInitialization
Definition: tb_vector.hpp:80
Type QuaternionMagnitude(const TypedQuaternion< Type > *input)
Definition: tb_quaternion.hpp:674
AngleUnit
Definition: tb_angle.hpp:27
@ Radians
Specifies the angle input value is in units of Radians.
TypedQuaternion< Type > * QuaternionScaleDivide(TypedQuaternion< Type > *result, const TypedQuaternion< Type > *input, const Type scalar)
Definition: tb_quaternion.hpp:637
TypedQuaternion< Type > * QuaternionScale(TypedQuaternion< Type > *result, const TypedQuaternion< Type > *input, const Type scalar)
Definition: tb_quaternion.hpp:615
TypedVector3< Type > * Vector3CrossProduct(TypedVector3< Type > *result, const TypedVector3< Type > *leftSide, const TypedVector3< Type > *rightSide)
Definition: tb_vector.hpp:1648
TypedQuaternion< Type > * QuaternionNegate(TypedQuaternion< Type > *result, const TypedQuaternion< Type > *input)
Definition: tb_quaternion.hpp:659
constexpr const Type & Clamp(const Type &value, const Type &minimumValue, const Type &maximumValue) noexcept
Definition: tb_math.hpp:91
Here is some information about the primary namespace.
Definition: tb_application_dialog.hpp:22