Allolib  1.0
C++ Components For Interactive Multimedia
al_Quat.hpp
1 #ifndef INCLUDE_AL_QUAT_HPP
2 #define INCLUDE_AL_QUAT_HPP
3 
4 /* Allocore --
5  Multimedia / virtual environment application class library
6 
7  Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology, UCSB.
8  Copyright (C) 2012. The Regents of the University of California.
9  All rights reserved.
10 
11  Redistribution and use in source and binary forms, with or without
12  modification, are permitted provided that the following conditions are met:
13 
14  Redistributions of source code must retain the above copyright notice,
15  this list of conditions and the following disclaimer.
16 
17  Redistributions in binary form must reproduce the above copyright
18  notice, this list of conditions and the following disclaimer in the
19  documentation and/or other materials provided with the distribution.
20 
21  Neither the name of the University of California nor the names of its
22  contributors may be used to endorse or promote products derived from
23  this software without specific prior written permission.
24 
25  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
29  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  POSSIBILITY OF SUCH DAMAGE.
36 
37 
38  File description:
39  A quaternion including many different conversion routines to matrices, etc.
40 
41  File author(s):
42  Lance Putnam, 2010, putnam.lance@gmail.com
43  Wesley Smith, 2010, wesley.hoke@gmail.com
44  Graham Wakefield, 2010, grrrwaaa@gmail.com
45 */
46 
47 #include "al/math/al_Constants.hpp"
48 #include "al/math/al_Mat.hpp"
49 #include "al/math/al_Vec.hpp"
50 
51 namespace al {
52 
53 template <class T>
54 class Quat;
55 
56 typedef Quat<float> Quatf;
58 
62 template <typename T = double>
63 class Quat {
64  public:
65  union {
66  struct {
67  T w;
68  T x;
69  T y;
70  T z;
71  };
72  T components[4];
73  };
74 
76  Quat(const T& w = T(1), const T& x = T(0), const T& y = T(0),
77  const T& z = T(0))
78  : w(w), x(x), y(y), z(z) {}
79 
81  template <class U>
82  Quat(const Quat<U>& v) : w(v.w), x(v.x), y(v.y), z(v.z) {}
83 
85 
88  template <class U>
89  Quat(const Vec<3, U>& xyz) : w(T(0)), x(xyz[0]), y(xyz[1]), z(xyz[2]) {}
90 
92 
95  template <class U>
96  Quat(const T& w, const Vec<3, U>& xyz)
97  : w(w), x(xyz[0]), y(xyz[1]), z(xyz[2]) {}
98 
99  // Factories
100 
103 
116  static Quat getRotationTo(const Vec<3, T>& usrc, const Vec<3, T>& udst);
117 
127  // Code sourced from Unity forum post about this functionality:
128  // http://answers.unity3d.com/questions/467614/what-is-the-source-code-of-quaternionlookrotation.html
129  static Quat getBillboardRotation(const Vec<3, T>& forward,
130  const Vec<3, T>& up);
131 
133  static Quat identity() { return Quat(1, 0, 0, 0); }
134 
136 
139  static Quat rotor(const Vec<3, T>& v1, const Vec<3, T>& v2);
140 
142 
147  static Quat slerp(const Quat& from, const Quat& to, T amt);
148 
150  static void slerpBuffer(const Quat& from, const Quat& to, Quat<T>* buffer,
151  int numFrames);
152 
154  T& operator[](int i) { return components[i]; }
155 
157  const T& operator[](int i) const { return components[i]; }
158 
160  bool operator==(const Quat& v) const {
161  return (w == v.w) && (x == v.x) && (y == v.y) && (z == v.z);
162  }
163 
165  bool operator!=(const Quat& v) const { return !(*this == v); }
166 
167  Quat operator-() const { return Quat(-w, -x, -y, -z); }
168  Quat operator+(const Quat& v) const { return Quat(*this) += v; }
169  Quat operator+(const T& v) const { return Quat(*this) += v; }
170  Quat operator-(const Quat& v) const { return Quat(*this) -= v; }
171  Quat operator-(const T& v) const { return Quat(*this) -= v; }
172  Quat operator/(const Quat& v) const { return Quat(*this) /= v; }
173  Quat operator/(const T& v) const { return Quat(*this) /= v; }
174  Quat operator*(const Quat& v) const { return Quat(*this) *= v; }
175  Quat operator*(const T& v) const { return Quat(*this) *= v; }
176 
177  template <class U>
178  Quat& operator=(const Quat<U>& v) {
179  return set(v);
180  }
181  Quat& operator=(const T& v) { return set(v); }
182  Quat& operator+=(const Quat& v) {
183  w += v.w;
184  x += v.x;
185  y += v.y;
186  z += v.z;
187  return *this;
188  }
189  Quat& operator+=(const T& v) {
190  w += v;
191  x += v;
192  y += v;
193  z += v;
194  return *this;
195  }
196  Quat& operator-=(const Quat& v) {
197  w -= v.w;
198  x -= v.x;
199  y -= v.y;
200  z -= v.z;
201  return *this;
202  }
203  Quat& operator-=(const T& v) {
204  w -= v;
205  x -= v;
206  y -= v;
207  z -= v;
208  return *this;
209  }
210  Quat& operator*=(const Quat& v) { return set(multiply(v)); }
211  Quat& operator*=(const T& v) {
212  w *= v;
213  x *= v;
214  y *= v;
215  z *= v;
216  return *this;
217  }
218  Quat& operator/=(const Quat& v) { return (*this) *= v.recip(); }
219  Quat& operator/=(const T& v) {
220  w /= v;
221  x /= v;
222  y /= v;
223  z /= v;
224  return *this;
225  }
226 
228  Quat conj() const { return Quat(w, -x, -y, -z); }
229 
231  T dot(const Quat& v) const { return w * v.w + x * v.x + y * v.y + z * v.z; }
232 
234  Quat inverse() const { return sgn().conj(); }
235 
237  T mag() const { return (T)sqrt(magSqr()); }
238 
240  T magSqr() const { return dot(*this); }
241 
243  Quat pow(T v) const;
244 
246  Quat recip() const { return conj() / magSqr(); }
247 
249  Quat sgn() const { return Quat(*this).normalize(); }
250 
251  // assumes both are already normalized!
252  Quat multiply(const Quat& q2) const;
253  Quat reverseMultiply(const Quat& q2) const;
254 
257 
259  Quat& set(const T& w, const T& x, const T& y, const T& z) {
260  this->w = w;
261  this->x = x;
262  this->y = y;
263  this->z = z;
264  return *this;
265  }
266 
268  template <class U>
269  Quat& set(const Quat<U>& q) {
270  return set(q.w, q.x, q.y, q.z);
271  }
272 
274  Quat& setIdentity() { return (*this) = Quat::identity(); }
275 
277  Quat& fromAxisAngle(const T& angle, const T& ux, const T& uy, const T& uz);
278 
280  Quat& fromAxisAngle(const T& angle, const Vec<3, T>& axis);
281 
283  Quat& fromAxisX(const T& angle) {
284  T t2 = angle * 0.5;
285  return set(cos(t2), sin(t2), T(0), T(0));
286  }
287 
289  Quat& fromAxisY(const T& angle) {
290  T t2 = angle * 0.5;
291  return set(cos(t2), T(0), sin(t2), T(0));
292  }
293 
295  Quat& fromAxisZ(const T& angle) {
296  T t2 = angle * 0.5;
297  return set(cos(t2), T(0), T(0), sin(t2));
298  }
299 
301  Quat& fromEuler(const Vec<3, T>& aeb) {
302  return fromEuler(aeb[0], aeb[1], aeb[2]);
303  }
304 
306  Quat& fromEuler(const T& az, const T& el, const T& ba);
307 
310  Quat& fromMatrix(const T* matrix);
311 
314  Quat& fromMatrix(const Mat<4, T>& v) { return fromMatrix(&v[0]); }
315 
317  Quat& fromMatrixTransposed(const T* matrix);
318 
321  return fromMatrixTransposed(&v[0]);
322  }
323 
325  void toCoordinateFrame(Vec<3, T>& ux, Vec<3, T>& uy, Vec<3, T>& uz) const;
326 
328  template <typename T2>
329  void toMatrix(T2* matrix) const;
330 
332  template <typename T2>
333  void toMatrixTransposed(T2* matrix) const;
334 
336  void toAxisAngle(T& angle, T& ax, T& ay, T& az) const;
337 
338  void toAxisAngle(T& angle, Vec<3, T>& axis) const {
339  toAxisAngle(angle, axis[0], axis[1], axis[2]);
340  }
341 
343  void toEuler(T& az, T& el, T& ba) const;
344 
346  void toEuler(T* aeb) const { toEuler(aeb[0], aeb[1], aeb[2]); }
347 
349  void toEuler(Vec<3, T>& aeb) const { toEuler(aeb[0], aeb[1], aeb[2]); }
350 
352  template <typename T2>
353  void toVectorX(T2& ax, T2& ay, T2& az) const;
354  template <typename T2>
355  void toVectorX(Vec<3, T2>& v) const {
356  toVectorX(v[0], v[1], v[2]);
357  }
358  template <typename T2 = T>
359  Vec<3, T2> toVectorX() const {
360  Vec<3, T2> v;
361  toVectorX(v);
362  return v;
363  }
364 
366  template <typename T2>
367  void toVectorY(T2& ax, T2& ay, T2& az) const;
368  template <typename T2>
369  void toVectorY(Vec<3, T2>& v) const {
370  toVectorY(v[0], v[1], v[2]);
371  }
372  template <typename T2 = T>
373  Vec<3, T2> toVectorY() const {
374  Vec<3, T2> v;
375  toVectorY(v);
376  return v;
377  }
378 
380  template <typename T2>
381  void toVectorZ(T2& ax, T2& ay, T2& az) const;
382  template <typename T2>
383  void toVectorZ(Vec<3, T2>& v) const {
384  toVectorZ(v[0], v[1], v[2]);
385  }
386  template <typename T2 = T>
387  Vec<3, T2> toVectorZ() const {
388  Vec<3, T2> v;
389  toVectorZ(v);
390  return v;
391  }
392 
395  Vec<3, T> rotate(const Vec<3, T>& v) const;
396 
399 
401  Quat slerp(const Quat& target, T amt) const {
402  return slerp(*this, target, amt);
403  }
404 
406  void slerpTo(const Quat& target, T amt) { set(slerp(*this, target, amt)); }
407 
409  void towardPoint(const Vec<3, T>& pos, const Quat<T>& q, const Vec<3, T>& v,
410  float amt);
411 
413  void print(std::ostream& stream) const;
414 
415  static T accuracyMax() { return 1.000001; }
416  static T accuracyMin() { return 0.999999; }
417  static T eps() { return 0.0000001; }
418 
419  private:
420  static T abs(T v) { return v > T(0) ? v : -v; }
421 };
422 
423 template <class T>
424 Quat<T> operator+(T r, const Quat<T>& q) {
425  return q + r;
426 }
427 template <class T>
428 Quat<T> operator-(T r, const Quat<T>& q) {
429  return -q + r;
430 }
431 template <class T>
432 Quat<T> operator*(T r, const Quat<T>& q) {
433  return q * r;
434 }
435 template <class T>
436 Quat<T> operator/(T r, const Quat<T>& q) {
437  return q.conjugate() * (r / q.magSqr());
438 }
439 
441 
442 template <typename T>
444  T unit = magSqr();
445  if (unit * unit < eps()) {
446  // unit too close to epsilon, set to default transform
447  setIdentity();
448  } else if (unit > accuracyMax() || unit < accuracyMin()) {
449  (*this) *= 1. / sqrt(unit);
450  }
451  return *this;
452 }
453 
454 // assumes both are already normalized!
455 template <typename T>
456 inline Quat<T> Quat<T>::multiply(const Quat<T>& q) const {
457  return Quat(w * q.w - x * q.x - y * q.y - z * q.z,
458  w * q.x + x * q.w + y * q.z - z * q.y,
459  w * q.y + y * q.w + z * q.x - x * q.z,
460  w * q.z + z * q.w + x * q.y - y * q.x);
461 }
462 
463 template <typename T>
464 inline Quat<T> Quat<T>::reverseMultiply(const Quat<T>& q) const {
465  return q * (*this);
466 }
467 
468 namespace {
469 // Values determined with help from:
470 // http://babbage.cs.qc.cuny.edu/IEEE-754.old/Decimal.html
471 template <class T>
472 inline T justUnder1();
473 template <>
474 float inline justUnder1() {
475  return 0.9999999f;
476 }
477 template <>
478 double inline justUnder1() {
479  return 0.999999999999999;
480 }
481 } // namespace
482 
483 template <typename T>
484 Quat<T> Quat<T>::pow(T expo) const {
485  T m = mag();
486  T w_m = w / m;
487 
488  // Is q/|q| close to (±1,0,0,0)?
489  // If so, then quaternion cannot be "rotated", so just scale w component.
490  if (w_m > justUnder1<T>() || w_m < -justUnder1<T>()) {
491  return Quat<T>((w >= T(0) ? T(1) : T(-1)) * ::pow(m, expo), 0, 0, 0);
492  }
493 
494  T theta = ::acos(w_m);
495  Vec<3, T> imag = Vec<3, T>(x, y, z) / (m * ::sin(theta));
496  imag *= ::sin(expo * theta);
497  return Quat(::cos(expo * theta), imag) * ::pow(m, expo);
498 }
499 
500 template <typename T>
501 inline Quat<T>& Quat<T>::fromAxisAngle(const T& angle, const Vec<3, T>& axis) {
502  return fromAxisAngle(angle, axis[0], axis[1], axis[2]);
503 }
504 
505 template <typename T>
506 Quat<T>& Quat<T>::fromAxisAngle(const T& angle, const T& ux, const T& uy,
507  const T& uz) {
508  T t2 = angle * T(0.5);
509  T sinft2 = sin(t2);
510  w = cos(t2);
511  x = ux * sinft2;
512  y = uy * sinft2;
513  z = uz * sinft2;
514  return *this;
515 }
516 
517 template <typename T>
518 Quat<T>& Quat<T>::fromEuler(const T& az, const T& el, const T& ba) {
519  /*http://vered.rose.utoronto.ca/people/david_dir/GEMS/GEMS.html
520  Converting from Euler angles to a quaternion is slightly more tricky, as the
521  order of operations must be correct. Since you can convert the Euler angles
522  to three independent quaternions by setting the arbitrary axis to the
523  coordinate axes, you can then multiply the three quaternions together to
524  obtain the final quaternion.
525 
526  So if you have three Euler angles (a, e, b), then you can form three
527  independent quaternions
528 
529  Qx = [ cos(e/2), (sin(e/2), 0, 0)]
530  Qy = [ cos(a/2), (0, sin(a/2), 0)]
531  Qz = [ cos(b/2), (0, 0, sin(b/2))]
532 
533  and the final quaternion, using YXZ ordering, is obtained by (Qy * Qx) * Qz.
534  */
535 
536  T c1 = cos(az * T(0.5));
537  T c2 = cos(el * T(0.5));
538  T c3 = cos(ba * T(0.5));
539  T s1 = sin(az * T(0.5));
540  T s2 = sin(el * T(0.5));
541  T s3 = sin(ba * T(0.5));
542 
543  /*
544  (w,x,y,z) (a,b,c,d)
545  w*a - x*b - y*c - z*d,
546  w*b + x*a + y*d - z*c,
547  w*c + y*a + z*b - x*d,
548  w*d + z*a + x*c - y*b
549 
550  (c1, 0,s1,0) (c2, s2,0,0)
551  c1*c2 - 0 - 0 - 0
552  c1*s2 + 0 + 0 + 0
553  0 + s1*c2 + 0 + 0
554  0 + 0 + 0 - s1*s2
555 
556  (tw, tx, ty, tz) (c3, 0,0,s3)
557  tw*c3 - 0 - 0 - tz*s3
558  0 + tx*c3 + ty*s3 + 0
559  0 + ty*c3 + 0 - tx*s3
560  tw*s3 + tz*c3 + 0 - 0
561  */
562  // equiv Q1 = Qy * Qx; // since many terms are zero
563  T tw = c1 * c2;
564  T tx = c1 * s2;
565  T ty = s1 * c2;
566  T tz = -s1 * s2;
567 
568  // equiv Q2 = Q1 * Qz; // since many terms are zero
569  w = tw * c3 - tz * s3;
570  x = tx * c3 + ty * s3;
571  y = ty * c3 - tx * s3;
572  z = tw * s3 + tz * c3;
573 
574  // return normalize();
575  return *this;
576 }
577 
578 template <typename T>
580  T trace = m[0] + m[5] + m[10];
581  w = sqrt(1. + trace) * 0.5;
582 
583  if (trace > 0.) {
584  x = (m[9] - m[6]) / (4. * w);
585  y = (m[2] - m[8]) / (4. * w);
586  z = (m[4] - m[1]) / (4. * w);
587  } else {
588  if (m[0] > m[5] && m[0] > m[10]) {
589  // m[0] is greatest
590  x = sqrt(1. + m[0] - m[5] - m[10]) * 0.5;
591  w = (m[9] - m[6]) / (4. * x);
592  y = (m[4] + m[1]) / (4. * x);
593  z = (m[8] + m[2]) / (4. * x);
594  } else if (m[5] > m[0] && m[5] > m[10]) {
595  // m[1] is greatest
596  y = sqrt(1. + m[5] - m[0] - m[10]) * 0.5;
597  w = (m[2] - m[8]) / (4. * y);
598  x = (m[4] + m[1]) / (4. * y);
599  z = (m[9] + m[6]) / (4. * y);
600  } else { // if(m[10] > m[0] && m[10] > m[5]) {
601  // m[2] is greatest
602  z = sqrt(1. + m[10] - m[0] - m[5]) * 0.5;
603  w = (m[4] - m[1]) / (4. * z);
604  x = (m[8] + m[2]) / (4. * z);
605  y = (m[9] + m[6]) / (4. * z);
606  }
607  }
608  return *this;
609 }
610 
611 template <typename T>
613  T trace = m[0] + m[5] + m[10];
614  w = sqrt(1. + trace) * 0.5;
615 
616  if (trace > 0.) {
617  x = (m[6] - m[9]) / (4. * w);
618  y = (m[8] - m[2]) / (4. * w);
619  z = (m[1] - m[4]) / (4. * w);
620  } else {
621  if (m[0] > m[5] && m[0] > m[10]) {
622  // m[0] is greatest
623  x = sqrt(1. + m[0] - m[5] - m[10]) * 0.5;
624  w = (m[6] - m[9]) / (4. * x);
625  y = (m[1] + m[4]) / (4. * x);
626  z = (m[2] + m[8]) / (4. * x);
627  } else if (m[5] > m[0] && m[5] > m[10]) {
628  // m[1] is greatest
629  y = sqrt(1. + m[5] - m[0] - m[10]) * 0.5;
630  w = (m[8] - m[2]) / (4. * y);
631  x = (m[1] + m[4]) / (4. * y);
632  z = (m[6] + m[9]) / (4. * y);
633  } else { // if(m[10] > m[0] && m[10] > m[5]) {
634  // m[2] is greatest
635  z = sqrt(1. + m[10] - m[0] - m[5]) * 0.5;
636  w = (m[1] - m[4]) / (4. * z);
637  x = (m[2] + m[8]) / (4. * z);
638  y = (m[6] + m[9]) / (4. * z);
639  }
640  }
641  return *this;
642 }
643 
644 template <typename T>
645 void Quat<T>::toAxisAngle(T& aa, T& ax, T& ay, T& az) const {
646  T unit = w * w; // cos^2(theta/2)
647  if (unit <
648  accuracyMin()) { // |cos x| must always be less than or equal to 1!
649  T invSinAngle = 1. / sqrt(1. - unit); // = 1/sqrt(1 - cos^2(theta/2))
650 
651  aa = ::acos(w) * T(2);
652  ax = x * invSinAngle;
653  ay = y * invSinAngle;
654  az = z * invSinAngle;
655  } else {
656  aa = 0;
657  if (x == T(0) && y == T(0) && z == T(0)) {
658  // axes are 0,0,0, change to a default:
659  ax = T(1);
660  ay = T(0);
661  az = T(0);
662  } else {
663  // for small angles, axis is roughly equal to i,j,k components
664  // axes are close to zero, should be normalized:
665  Vec<3, T> v(x, y, z);
666  v.normalize();
667  ax = v[0];
668  ay = v[1];
669  az = v[2];
670  }
671  }
672 }
673 
674 template <typename T>
675 inline void Quat<T>::toEuler(T& az, T& el, T& ba) const {
676  /* Adapted from M. Baker:
677  http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/Quaternions.pdf
678  To make these equations work, 'e' had to be flipped in sign. */
679 
680  // T a=w, b=x, c=y, d=z, e= 1; // XYZ
681  // T a=w, b=x, c=z, d=y, e=-1; // XZY
682  // T a=w, b=y, c=z, d=x, e= 1; // YZX
683  T a = w, b = y, c = x, d = z, e = -1; // YXZ
684  // T a=w, b=z, c=x, d=y, e= 1; // ZXY
685  // T a=w, b=z, c=y, d=x, e=-1; // ZYX
686 
687  // Here we test if our second rotation will result in gimbal lock
688  T test = a * c + e * b * d;
689  if (test > 0.49999) { // singularity at north pole
690  az = atan2(b, a);
691  el = M_PI / 2;
692  ba = 0;
693  return;
694  }
695  if (test < -0.49999) { // singularity at south pole
696  az = atan2(b, a);
697  el = -M_PI / 2;
698  ba = 0;
699  return;
700  }
701 
702  T bsq = b * b;
703  T csq = c * c;
704  T dsq = d * d;
705 
706  az = ::atan2(2 * (a * b - e * c * d), 1 - 2 * (bsq + csq));
707  el = ::asin(2 * test);
708  ba = ::atan2(2 * (a * d - e * b * c), 1 - 2 * (csq + dsq));
709 
710  // This version gives imprecise results:
711  // http://www.mathworks.com/access/helpdesk/help/toolbox/aeroblks/quaternionstoeulerangles.html
712  /*
713  T sqw = w*w;
714  T sqx = x*x;
715  T sqy = y*y;
716  T sqz = z*z;
717  az = asin (-2.0 * (x*z - w*y));
718  el = atan2( 2.0 * (y*z + w*x), (sqw - sqx - sqy + sqz));
719  ba = atan2( 2.0 * (x*y + w*z), (sqw + sqx - sqy - sqz));
720  //*/
721 }
722 
723 template <typename T>
725  Vec<3, T>& uz) const {
726  static const T _2 = T(2);
727  static const T _1 = T(1);
728  T _2w = _2 * w, _2x = _2 * x, _2y = _2 * y;
729  T wx = _2w * x, wy = _2w * y, wz = _2w * z, xx = _2x * x, xy = _2x * y,
730  xz = _2x * z, yy = _2y * y, yz = _2y * z, zz = _2 * z * z;
731 
732  ux[0] = -zz - yy + _1;
733  ux[1] = wz + xy;
734  ux[2] = xz - wy;
735 
736  uy[0] = xy - wz;
737  uy[1] = -zz - xx + _1;
738  uy[2] = wx + yz;
739 
740  uz[0] = wy + xz;
741  uz[1] = yz - wx;
742  uz[2] = -yy - xx + _1;
743 }
744 
745 /*
746 Quat to matrix:
747 RHCS
748  [ 1 - 2y - 2z 2xy + 2wz 2xz - 2wy ]
749  [ ]
750  [ 2xy - 2wz 1 - 2x - 2z 2yz + 2wx ]
751  [ ]
752  [ 2xz + 2wy 2yz - 2wx 1 - 2x - 2y ]
753 
754 LHCS
755  [ 1 - 2y - 2z 2xy - 2wz 2xz + 2wy ]
756  [ ]
757  [ 2xy + 2wz 1 - 2x - 2z 2yz - 2wx ]
758  [ ]
759  [ 2xz - 2wy 2yz + 2wx 1 - 2x - 2y ]
760 */
761 
762 template <typename T>
763 template <typename T2>
764 void Quat<T>::toMatrix(T2* m) const {
765  Vec<3, T> ux, uy, uz;
766  toCoordinateFrame(ux, uy, uz);
767 
768  m[0] = ux[0];
769  m[4] = uy[0];
770  m[8] = uz[0];
771  m[12] = 0;
772  m[1] = ux[1];
773  m[5] = uy[1];
774  m[9] = uz[1];
775  m[13] = 0;
776  m[2] = ux[2];
777  m[6] = uy[2];
778  m[10] = uz[2];
779  m[14] = 0;
780  m[3] = 0;
781  m[7] = 0;
782  m[11] = 0;
783  m[15] = 1;
784 }
785 
786 // Note: same as toMatrix, but with matrix indices transposed
787 template <typename T>
788 template <typename T2>
789 void Quat<T>::toMatrixTransposed(T2* m) const {
790  Vec<3, T> ux, uy, uz;
791  toCoordinateFrame(ux, uy, uz);
792 
793  m[0] = ux[0];
794  m[1] = uy[0];
795  m[2] = uz[0];
796  m[3] = 0;
797  m[4] = ux[1];
798  m[5] = uy[1];
799  m[6] = uz[1];
800  m[7] = 0;
801  m[8] = ux[2];
802  m[9] = uy[2];
803  m[10] = uz[2];
804  m[11] = 0;
805  m[12] = 0;
806  m[13] = 0;
807  m[14] = 0;
808  m[15] = 1;
809 }
810 
811 template <typename T>
812 template <typename T2>
813 inline void Quat<T>::toVectorX(T2& ax, T2& ay, T2& az) const {
814  ax = 1.0 - 2.0 * y * y - 2.0 * z * z;
815  ay = 2.0 * x * y + 2.0 * z * w;
816  az = 2.0 * x * z - 2.0 * y * w;
817 }
818 
819 template <typename T>
820 template <typename T2>
821 inline void Quat<T>::toVectorY(T2& ax, T2& ay, T2& az) const {
822  ax = 2.0 * x * y - 2.0 * z * w;
823  ay = 1.0 - 2.0 * x * x - 2.0 * z * z;
824  az = 2.0 * y * z + 2.0 * x * w;
825 }
826 
827 template <typename T>
828 template <typename T2>
829 inline void Quat<T>::toVectorZ(T2& ax, T2& ay, T2& az) const {
830  ax = 2.0 * x * z + 2.0 * y * w;
831  ay = 2.0 * y * z - 2.0 * x * w;
832  az = 1.0 - 2.0 * x * x - 2.0 * y * y;
833 }
834 
835 /*
836  Rotating a vector is simple:
837  v1 = q * qv * q^-1
838  Where v is a 'pure quaternion' derived from the vector, i.e. w = 0.
839 */
840 template <typename T>
841 inline Vec<3, T> Quat<T>::rotate(const Vec<3, T>& v) const {
842  // dst = ((q * quat(v)) * q^-1)
843  // faster & simpler:
844  // we know quat(v).w == 0
845  Quat p(-x * v.x - y * v.y - z * v.z, w * v.x + y * v.z - z * v.y,
846  w * v.y - x * v.z + z * v.x, w * v.z + x * v.y - y * v.x);
847  // faster & simpler:
848  // we don't care about the w component
849  // and we know that conj() is simply (w, -x, -y, -z):
850  return Vec<3, T>(p.x * w - p.w * x + p.z * y - p.y * z,
851  p.y * w - p.w * y + p.x * z - p.z * x,
852  p.z * w - p.w * z + p.y * x - p.x * y);
853  // p *= conj(); // p * q^-1
854  // return Vec<3,T>(p.x, p.y, p.z);
855 }
856 
857 template <typename T>
859  return Quat(*this).conj().rotate(v);
860 }
861 
862 template <typename T>
863 Quat<T> Quat<T>::slerp(const Quat& input, const Quat& target, T amt) {
864  Quat<T> result;
865 
866  if (amt == T(0)) {
867  return input;
868  } else if (amt == T(1)) {
869  return target;
870  }
871 
872  int bflip = 0;
873  T dot_prod = input.dot(target);
874  T a, b;
875 
876  // clamp
877  dot_prod = (dot_prod < -1) ? -1 : ((dot_prod > 1) ? 1 : dot_prod);
878 
879  // if B is on opposite hemisphere from A, use -B instead
880  if (dot_prod < 0.0) {
881  dot_prod = -dot_prod;
882  bflip = 1;
883  }
884 
885  T cos_angle = acos(dot_prod);
886  if (Quat::abs(cos_angle) > eps()) {
887  T sine = sin(cos_angle);
888  T inv_sine = 1. / sine;
889 
890  a = sin(cos_angle * (1. - amt)) * inv_sine;
891  b = sin(cos_angle * amt) * inv_sine;
892 
893  if (bflip) {
894  b = -b;
895  }
896  } else {
897  // nearly the same;
898  // approximate without trigonometry
899  a = amt;
900  b = 1. - amt;
901  }
902 
903  result.w = a * input.w + b * target.w;
904  result.x = a * input.x + b * target.x;
905  result.y = a * input.y + b * target.y;
906  result.z = a * input.z + b * target.z;
907 
908  result.normalize();
909  return result;
910 }
911 
912 template <typename T>
913 void Quat<T>::slerpBuffer(const Quat& input, const Quat& target,
914  Quat<T>* buffer, int numFrames) {
916  struct RSin {
918  RSin(const T& frq = T(0), const T& phs = T(0), const T& amp = T(1))
919  : val2(0), mul(0) {
920  T f = frq, p = phs;
921  mul = (T)2 * (T)cos(f);
922  val2 = (T)sin(p - f * T(2)) * amp;
923  val = (T)sin(p - f) * amp;
924  }
925 
927  T operator()() const {
928  T v0 = mul * val - val2;
929  val2 = val;
930  return val = v0;
931  }
932 
933  mutable T val;
934  mutable T val2;
935  T mul;
936  };
937 
938  int bflip = 1;
939  T dot_prod = input.dot(target);
940 
941  // clamp
942  dot_prod = (dot_prod < -1) ? -1 : ((dot_prod > 1) ? 1 : dot_prod);
943 
944  // if B is on opposite hemisphere from A, use -B instead
945  if (dot_prod < 0.0) {
946  dot_prod = -dot_prod;
947  bflip = -1;
948  }
949 
950  const T cos_angle = acos(dot_prod);
951  const T inv_frames = 1. / ((T)numFrames);
952 
953  if (Quat::abs(cos_angle) > eps()) {
954  const T sine = sin(cos_angle);
955  const T inv_sine = 1. / sine;
956  RSin sinA(-cos_angle * inv_frames, cos_angle, inv_sine);
957  RSin sinB(cos_angle * inv_frames, 0, inv_sine * bflip);
958 
959  for (int i = 0; i < numFrames; i++) {
960  // T amt = i*inv_frames;
961  T a = sinA();
962  T b = sinB();
963 
964  buffer[i].w = a * input.w + b * target.w;
965  buffer[i].x = a * input.x + b * target.x;
966  buffer[i].y = a * input.y + b * target.y;
967  buffer[i].z = a * input.z + b * target.z;
968  buffer[i].normalize();
969  }
970  } else {
971  for (int i = 0; i < numFrames; i++) {
972  T a = i * inv_frames;
973  T b = 1. - a;
974 
975  buffer[i].w = a * input.w + b * target.w;
976  buffer[i].x = a * input.x + b * target.x;
977  buffer[i].y = a * input.y + b * target.y;
978  buffer[i].z = a * input.z + b * target.z;
979  buffer[i].normalize();
980  }
981  }
982 }
983 
984 template <typename T>
986  // a . b = |a| |b| cos t
987  // Since |a| = |b| = 1, then
988  // a . b = cos t
989  T d = src.dot(dst);
990 
991  // vectors are the same
992  if (d >= 1.) {
993  return Quat<T>::identity();
994  }
995 
996  Quat<T> q;
997 
998  // vectors are nearly opposing
999  if (d < -0.999999999) {
1000  // pick an axis to rotate around
1001  Vec<3, T> axis = cross(Vec<3, T>(0, 1, 0), src);
1002  // if colinear, pick another:
1003  if (axis.magSqr() < 0.00000000001) {
1004  axis = cross(Vec<3, T>(0, 0, 1), src);
1005  }
1006  // axis.normalize();
1007  q.fromAxisAngle(M_PI, axis);
1008  } else {
1009  /* Derive quaternion from a rotation axis and angle.
1010 
1011  The code used here is an optimization of fromAxisAngle:
1012  T t2 = angle * T(0.5);
1013  T sinft2 = sin(t2);
1014  w = cos(t2);
1015  x = ux * sinft2;
1016  y = uy * sinft2;
1017  z = uz * sinft2;
1018  */
1019  T s = sqrt((d + 1.) * 2);
1020  T invs = 1. / s;
1021  Vec<3, T> c = cross(src, dst);
1022  q.w = s * 0.5;
1023  q.x = c[0] * invs;
1024  q.y = c[1] * invs;
1025  q.z = c[2] * invs;
1026  }
1027  return q.normalize();
1028 }
1029 
1030 template <typename T>
1032  const Vec<3, T>& up) {
1033  Vec<3, T> vector = forward;
1034  Vec<3, T> vector2 = Vec<3, T>(cross(up, vector)).normalize();
1035  Vec<3, T> vector3 = cross(vector, vector2);
1036  T m00 = vector2.x;
1037  T m01 = vector2.y;
1038  T m02 = vector2.z;
1039  T m10 = vector3.x;
1040  T m11 = vector3.y;
1041  T m12 = vector3.z;
1042  T m20 = vector.x;
1043  T m21 = vector.y;
1044  T m22 = vector.z;
1045 
1046  T num8 = (m00 + m11) + m22;
1047  Quat<T> q;
1048  if (num8 > 0) {
1049  T num = sqrt(num8 + 1);
1050  q.w = num * 0.5;
1051  num = 0.5 / num;
1052  q.x = (m12 - m21) * num;
1053  q.y = (m20 - m02) * num;
1054  q.z = (m01 - m10) * num;
1055  return q;
1056  }
1057  if ((m00 >= m11) && (m00 >= m22)) {
1058  T num7 = sqrt(((1 + m00) - m11) - m22);
1059  T num4 = 0.5 / num7;
1060  q.x = 0.5 * num7;
1061  q.y = (m01 + m10) * num4;
1062  q.z = (m02 + m20) * num4;
1063  q.w = (m12 - m21) * num4;
1064  return q;
1065  }
1066  if (m11 > m22) {
1067  T num6 = sqrt(((1 + m11) - m00) - m22);
1068  T num3 = 0.5 / num6;
1069  q.x = (m10 + m01) * num3;
1070  q.y = 0.5 * num6;
1071  q.z = (m21 + m12) * num3;
1072  q.w = (m20 - m02) * num3;
1073  return q;
1074  }
1075  T num5 = sqrt(((1 + m22) - m00) - m11);
1076  T num2 = 0.5 / num5;
1077  q.x = (m20 + m02) * num2;
1078  q.y = (m21 + m12) * num2;
1079  q.z = 0.5 * num5;
1080  q.w = (m01 - m10) * num2;
1081  return q;
1082 }
1083 
1087 template <typename T>
1088 void Quat<T>::towardPoint(const Vec<3, T>& pos, const Quat<T>& q,
1089  const Vec<3, T>& v, float amt) {
1090  Vec<3, T> diff, axis;
1091  diff = v - pos;
1092  diff.normalize();
1093 
1094  if (amt < 0) {
1095  diff = diff * -1.;
1096  }
1097 
1098  Vec<3, T> zaxis;
1099  q.toVectorZ(zaxis);
1100  // axis = zaxis.cross(diff);
1101  cross(axis, zaxis, diff);
1102  // Vec<3,T>::cross(axis, zaxis, diff);
1103  axis.normalize();
1104 
1105  float axis_mag_sqr = axis.dot(axis);
1106  float along = zaxis.dot(diff); // Vec<3,T>::dot(zaxis, diff);
1107 
1108  if (axis_mag_sqr < 0.001 && along < 0) {
1109  // Vec<3,T>::cross(axis, zaxis, Vec<3,T>(0., 0., 1.));
1110  cross(axis, zaxis, Vec<3, T>(0, 0, 1));
1111  axis.normalize();
1112 
1113  if (axis_mag_sqr < 0.001) {
1114  // Vec<3,T>::cross(axis, zaxis, Vec<3,T>(0., 1., 0.));
1115  cross(axis, zaxis, Vec<3, T>(0, 1, 0));
1116  axis.normalize();
1117  }
1118 
1119  axis_mag_sqr = axis.dot(axis); // Vec<3,T>::dot(axis, axis);
1120  }
1121 
1122  if (along < 0.9995 && axis_mag_sqr > 0.001) {
1123  float theta = Quat::abs(amt) * acos(along);
1124  // printf("theta: %f amt: %f\n", theta, amt);
1125  fromAxisAngle(theta, axis[0], axis[1], axis[2]);
1126  } else {
1127  setIdentity();
1128  }
1129 }
1130 
1131 // v1 and v2 must be normalized
1132 // alternatively expressed as Q = (1+gp(v1, v2))/sqrt(2*(1+dot(b, a)))
1133 template <typename T>
1135  // get the normal to the plane (i.e. the unit bivector containing the v1 and
1136  // v2)
1137  Vec<3, T> n;
1138  cross(n, v1, v2);
1139  n.normalize(); // normalize because the cross product can get slightly
1140  // denormalized
1141 
1142  // calculate half the angle between v1 and v2
1143  T dotmag = v1.dot(v2);
1144  T theta = acos(dotmag) * 0.5;
1145 
1146  // calculate the scaled actual bivector generaed by v1 and v2
1147  Vec<3, T> bivec = n * sin(theta);
1148  Quat<T> q(cos(theta), bivec[0], bivec[1], bivec[2]);
1149 
1150  return q;
1151 }
1152 
1153 template <typename T>
1154 void Quat<T>::print(std::ostream& stream) const {
1155  stream << "Quat(" << w << ", " << x << ", " << y << ", " << z << ")"
1156  << std::endl;
1157 }
1158 
1159 } // namespace al
1160 
1161 #endif /* include guard */
Fixed-size n-by-n square matrix.
Definition: al_Mat.hpp:78
Quat & set(const T &w, const T &x, const T &y, const T &z)
Set components.
Definition: al_Quat.hpp:259
T magSqr() const
Get magnitude squared.
Definition: al_Quat.hpp:240
static Quat getBillboardRotation(const Vec< 3, T > &forward, const Vec< 3, T > &up)
Definition: al_Quat.hpp:1031
Quat slerp(const Quat &target, T amt) const
Spherical interpolation.
Definition: al_Quat.hpp:401
Quat & fromAxisAngle(const T &angle, const Vec< 3, T > &axis)
Set as versor rotated by angle, in radians, around unit vector.
Definition: al_Quat.hpp:501
bool operator==(const Quat &v) const
Returns true if all components are equal.
Definition: al_Quat.hpp:160
Quat & setIdentity()
Set to identity.
Definition: al_Quat.hpp:274
static Quat rotor(const Vec< 3, T > &v1, const Vec< 3, T > &v2)
Get rotor from two unit vectors.
Definition: al_Quat.hpp:1134
Quat & fromMatrix(const Mat< 4, T > &v)
Definition: al_Quat.hpp:314
Quat & set(const Quat< U > &q)
Set from other quaternion.
Definition: al_Quat.hpp:269
void slerpTo(const Quat &target, T amt)
In-place spherical interpolation.
Definition: al_Quat.hpp:406
void toEuler(T &az, T &el, T &ba) const
Convert to YXZ Euler angles (azimuth, elevation, bank), in radians.
Definition: al_Quat.hpp:675
Quat & fromMatrixTransposed(const Mat< 4, T > &v)
Set as versor from row-major 4-by-4 projective space transformation matrix.
Definition: al_Quat.hpp:320
Vec< 3, T > rotate(const Vec< 3, T > &v) const
Definition: al_Quat.hpp:841
Quat & fromAxisZ(const T &angle)
Set as versor rotated by angle, in radians, around z-axis.
Definition: al_Quat.hpp:295
Quat & fromMatrix(const T *matrix)
Definition: al_Quat.hpp:579
Quat pow(T v) const
Return quaternion raised to a power.
Definition: al_Quat.hpp:484
void print(std::ostream &stream) const
utility for debug printing:
Definition: al_Quat.hpp:1154
Quat inverse() const
Returns inverse (same as conjugate if normalized as q^-1 = q_conj/q_mag^2)
Definition: al_Quat.hpp:234
Quat sgn() const
Returns signum, q/|q|, the closest point on unit 3-sphere.
Definition: al_Quat.hpp:249
Quat(const Vec< 3, U > &xyz)
Construct 'pure imaginary' quaternion.
Definition: al_Quat.hpp:89
Quat conj() const
Returns the conjugate.
Definition: al_Quat.hpp:228
void toMatrix(T2 *matrix) const
Convert to column-major 4-by-4 projective space transformation matrix.
Definition: al_Quat.hpp:764
void toEuler(Vec< 3, T > &aeb) const
Convert to YXZ Euler angle vector (azimuth, elevation, bank), in radians.
Definition: al_Quat.hpp:349
T w
w component
Definition: al_Quat.hpp:67
Quat(const T &w, const Vec< 3, U > &xyz)
Construct quaternion from real and imaginary parts.
Definition: al_Quat.hpp:96
void toCoordinateFrame(Vec< 3, T > &ux, Vec< 3, T > &uy, Vec< 3, T > &uz) const
Convert to coordinate frame unit vectors.
Definition: al_Quat.hpp:724
void toMatrixTransposed(T2 *matrix) const
Convert to row-major 4-by-4 projective space transformation matrix.
Definition: al_Quat.hpp:789
Quat & fromMatrixTransposed(const T *matrix)
Set as versor from row-major 4-by-4 projective space transformation matrix.
Definition: al_Quat.hpp:612
void towardPoint(const Vec< 3, T > &pos, const Quat< T > &q, const Vec< 3, T > &v, float amt)
Get the quaternion from a given point and quaterion toward another point.
Definition: al_Quat.hpp:1088
T components[4]
component vector
Definition: al_Quat.hpp:72
Quat recip() const
Returns multiplicative inverse.
Definition: al_Quat.hpp:246
Quat & fromEuler(const Vec< 3, T > &aeb)
Set as versor rotated by YXZ Euler angles, in radians.
Definition: al_Quat.hpp:301
T mag() const
Get magnitude.
Definition: al_Quat.hpp:237
void toAxisAngle(T &angle, T &ax, T &ay, T &az) const
Convert to axis-angle form, in radians.
Definition: al_Quat.hpp:645
Quat & fromAxisY(const T &angle)
Set as versor rotated by angle, in radians, around y-axis.
Definition: al_Quat.hpp:289
T x
x component
Definition: al_Quat.hpp:68
Vec< 3, T > rotateTransposed(const Vec< 3, T > &v) const
This is rotation by the quaternion's conjugate.
Definition: al_Quat.hpp:858
static Quat getRotationTo(const Vec< 3, T > &usrc, const Vec< 3, T > &udst)
Definition: al_Quat.hpp:985
void toEuler(T *aeb) const
Convert to YXZ Euler angle vector (azimuth, elevation, bank), in radians.
Definition: al_Quat.hpp:346
T & operator[](int i)
Set component with index.
Definition: al_Quat.hpp:154
Quat & normalize()
Normalize magnitude to one.
Definition: al_Quat.hpp:443
static void slerpBuffer(const Quat &from, const Quat &to, Quat< T > *buffer, int numFrames)
Fill an array of Quats with a full spherical interpolation.
Definition: al_Quat.hpp:913
T y
y component
Definition: al_Quat.hpp:69
static Quat slerp(const Quat &from, const Quat &to, T amt)
Spherical linear interpolation of a quaternion.
Definition: al_Quat.hpp:863
Quat & fromAxisAngle(const T &angle, const T &ux, const T &uy, const T &uz)
Set as versor rotated by angle, in radians, around unit vector (ux,uy,uz)
Definition: al_Quat.hpp:506
Quat & fromEuler(const T &az, const T &el, const T &ba)
Set as versor rotated by YXZ Euler angles, in radians.
Definition: al_Quat.hpp:518
void toVectorX(T2 &ax, T2 &ay, T2 &az) const
Get local x unit vector (1,0,0) in absolute coordinates.
Definition: al_Quat.hpp:813
static Quat identity()
Returns identity.
Definition: al_Quat.hpp:133
Quat & fromAxisX(const T &angle)
Set as versor rotated by angle, in radians, around x-axis.
Definition: al_Quat.hpp:283
Quat(const T &w=T(1), const T &x=T(0), const T &y=T(0), const T &z=T(0))
Default constructor creates an identity quaternion.
Definition: al_Quat.hpp:76
Quat(const Quat< U > &v)
Definition: al_Quat.hpp:82
const T & operator[](int i) const
Get component with index.
Definition: al_Quat.hpp:157
void toVectorZ(T2 &ax, T2 &ay, T2 &az) const
Get local z unit vector (0,0,1) in absolute coordinates.
Definition: al_Quat.hpp:829
T z
z component
Definition: al_Quat.hpp:70
bool operator!=(const Quat &v) const
Returns true if any components are not equal.
Definition: al_Quat.hpp:165
void toVectorY(T2 &ax, T2 &ay, T2 &az) const
Get local y unit vector (0,1,0) in absolute coordinates.
Definition: al_Quat.hpp:821
T dot(const Quat &v) const
Returns dot product with another quaternion.
Definition: al_Quat.hpp:231
Fixed-size n-vector.
Definition: al_Vec.hpp:117
Vec & normalize(T scale=T(1))
Set magnitude to one without changing direction.
Definition: al_Vec.hpp:729
T magSqr() const
Returns magnitude squared.
Definition: al_Vec.hpp:418
T dot(const Vec< N, U > &v) const
Returns dot (inner) product between vectors.
Definition: al_Vec.hpp:406
Definition: al_App.hpp:23
T angle(const Vec< N, T > &a, const Vec< N, T > &b)
Returns angle, in interval [0, pi], between two vectors.
Definition: al_Vec.hpp:634
Quat< double > Quatd
Double-precision quaternion.
Definition: al_Quat.hpp:57
Quat< float > Quatf
Single-precision quaternion.
Definition: al_Quat.hpp:54
void cross(Vec< 3, T > &r, const Vec< 3, T > &a, const Vec< 3, T > &b)
Sets r to cross product, a x b.
Definition: al_Vec.hpp:574