GL Studio API
gls_quaternion.h
Go to the documentation of this file.
1 /*! \file
2  \brief The disti::GlsQuaternion class.
3 
4  \par Copyright Information
5 
6  Copyright (c) 2015 by The DiSTI Corporation.<br>
7  11301 Corporate Blvd., Suite 100<br>
8  Orlando, Florida 32817<br>
9  USA<br>
10  <br>
11  All rights reserved.<br>
12 
13  This Software contains proprietary trade secrets of DiSTI and may not be
14 reproduced, in whole or part, in any form, or by any means of electronic,
15 mechanical, or otherwise, without the written permission of DiSTI. Said
16 permission may be derived through the purchase of applicable DiSTI product
17 licenses which detail the distribution rights of this content and any
18 Derivative Works based on this or other copyrighted DiSTI Software.
19 
20  NO WARRANTY. THE SOFTWARE IS PROVIDED "AS-IS," WITHOUT WARRANTY OF ANY KIND,
21 AND ANY USE OF THIS SOFTWARE PRODUCT IS AT YOUR OWN RISK. TO THE MAXIMUM EXTENT
22 PERMITTED BY APPLICABLE LAW, DISTI AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES
23 AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
24 IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY AND/OR FITNESS FOR A
25 PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT, WITH REGARD TO THE SOFTWARE.
26 
27  LIMITATION OF LIABILITY. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW,
28 IN NO EVENT SHALL DISTI OR ITS SUPPLIERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
29 INDIRECT, OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION,
30 DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS
31 INFORMATION, OR ANY OTHER PECUNIARY LOSS) ARISING OUT OF THE USE OF OR
32 INABILITY TO USE THE SOFTWARE, EVEN IF DISTI HAS BEEN ADVISED OF THE POSSIBILITY
33 OF SUCH DAMAGES. DISTI'S ENTIRE LIABILITY AND YOUR EXCLUSIVE REMEDY SHALL NOT
34 EXCEED FIVE DOLLARS (US$5.00).
35 
36  The aforementioned terms and restrictions are governed by the laws of the
37 State of Florida and the United States of America.
38 
39 */
40 
41 #ifndef GLS_QUATERNION_H
42 #define GLS_QUATERNION_H
43 
44 namespace disti {
45 
46 namespace
47 {
48  // Circular dependancies prevent us from using VeryCloseToZero in util.h
49  bool IsVeryCloseToZero( double value ) { return fabs(value) < 0.0001; }
50 }
51 
52 template <class Type>
53 class GlsMatrixAffine;
54 
55 /** The GlsQuaternion class */
56 template <class Type>
58 public:
59 
60  //------------------------------------------------------------------------
61  /**
62  * Default constructor. This will initialize the quaternion to zero.
63  */
64  //------------------------------------------------------------------------
65  inline GlsQuaternion() { _v[0]=0; _v[1]=0; _v[2]=0; _v[3]=0; }
66 
67  //------------------------------------------------------------------------
68  /**
69  * Constructor. Sets quaternion from 4 constants.
70  * \param x Initial X value
71  * \param y Initial Y value
72  * \param z Initial Z value
73  * \param w Initial W value
74  */
75  //------------------------------------------------------------------------
76  inline GlsQuaternion(Type x, Type y, Type z, Type w)
77  {
78  _v[0]=x; _v[1]=y; _v[2]=z; _v[3]=w;
79  }
80 
81  //------------------------------------------------------------------------
82  /**
83  * Constructor. Sets quaternion from angle about an arbitrary axis
84  * \param angle Rotation angle in radians
85  * \param axis Unit vector representing arbitrary axis
86  */
87  //------------------------------------------------------------------------
88  inline GlsQuaternion(Type angle, const Vector& axis)
89  {
90  SetFromAngleAxis(angle,axis);
91  }
92 
93  //------------------------------------------------------------------------
94  /**
95  * Constructor. Sets quaternion from 3 angles about 3 axes
96  * \param angle1 Rotation angle about first axis in radians
97  * \param axis1 Unit vector representing first arbitrary axis
98  * \param angle2 Rotation angle about second axis in radians
99  * \param axis2 Unit vector representing second arbitrary axis
100  * \param angle3 Rotation angle about third axis in radians
101  * \param axis3 Unit vector representing third arbitrary axis
102  */
103  //------------------------------------------------------------------------
104  inline GlsQuaternion(Type angle1, const Vector& axis1,
105  Type angle2, const Vector& axis2,
106  Type angle3, const Vector& axis3)
107  {
108  SetFromAngleAxis(angle1,axis1,angle2,axis2,angle3,axis3);
109  }
110 
111  //------------------------------------------------------------------------
112  /**
113  * Constructor. Sets quaternion from 3 angles (Euler Angles)
114  * \param angleX Rotation angle about X axis in radians
115  * \param angleY Rotation angle about Y axis in radians
116  * \param angleZ Rotation angle about Z axis in radians
117  */
118  //------------------------------------------------------------------------
119  inline GlsQuaternion(Type angleX, Type angleY, Type angleZ)
120  {
121  SetFromEulerAngles(angleX,angleY,angleZ);
122  }
123 
124  //------------------------------------------------------------------------
125  /**
126  * Constructor. Sets quaternion from 3 angles (Euler Angles)
127  * \param anglesVec A vector where each component of the vector is an
128  * Euler angle component in radians.
129  */
130  //------------------------------------------------------------------------
131  inline GlsQuaternion(const Vector& anglesVec)
132  {
133  SetFromEulerAngles(anglesVec.x,anglesVec.y,anglesVec.z);
134  }
135 
136  //------------------------------------------------------------------------
137  /**
138  * Constructor. Sets quaternion from a rotation matrix
139  * \param matrix An affine matrix representing a rotation matrix
140  */
141  //------------------------------------------------------------------------
142  inline GlsQuaternion(const GlsMatrixAffine<Type>& matrix)
143  {
144  SetFromRotationMatrix(matrix);
145  }
146 
147  //------------------------------------------------------------------------
148  /**
149  * Accessor method providing access to quaternion data.
150  * \return A pointer to the quaternion data.
151  */
152  //------------------------------------------------------------------------
153  inline Type* Data()
154  { return _v; }
155 
156  //------------------------------------------------------------------------
157  /**
158  * Accessor method providing access to quaternion data.
159  * \return A pointer to the quaternion data.
160  */
161  //------------------------------------------------------------------------
162  inline const Type* Data() const
163  { return _v; }
164 
165  //------------------------------------------------------------------------
166  /**
167  * Boolean equivalence operator
168  * \param q Quaternion to compare against
169  * \return True if the two quaternions are exactly equal
170  */
171  //------------------------------------------------------------------------
172  inline bool operator == (const GlsQuaternion& q) const
173  { return _v[0]==q._v[0] && _v[1]==q._v[1] && _v[2]==q._v[2] && _v[3]==q._v[3]; }
174 
175  //------------------------------------------------------------------------
176  /**
177  * Boolean non-equivalence operator
178  * \param q Quaternion to compare against
179  * \return True if the two quaternions are not exactly equal
180  */
181  //------------------------------------------------------------------------
182  inline bool operator != (const GlsQuaternion& q) const
183  { return _v[0]!=q._v[0] || _v[1]!=q._v[1] || _v[2]!=q._v[2] || _v[3]!=q._v[3]; }
184 
185  //------------------------------------------------------------------------
186  /**
187  * Boolean less than operator
188  * \param q Quaternion to compare against
189  * \return True if the this quaternion is less than the provided one
190  */
191  //------------------------------------------------------------------------
192  inline bool operator < (const GlsQuaternion& q) const
193  {
194  if (_v[0]<q._v[0]) return true;
195  else if (_v[0]>q._v[0]) return false;
196  else if (_v[1]<q._v[1]) return true;
197  else if (_v[1]>q._v[1]) return false;
198  else if (_v[2]<q._v[2]) return true;
199  else if (_v[2]>q._v[2]) return false;
200  else return (_v[3]<q._v[3]);
201  }
202 
203  //------------------------------------------------------------------------
204  /**
205  * Scalar multiplication operator
206  * \param s A scalar to multiply against
207  * \return This quaternion multiplied by the scalar
208  */
209  //------------------------------------------------------------------------
210  inline const GlsQuaternion operator * (Type s) const
211  {
212  return GlsQuaternion(_v[0]*s, _v[1]*s, _v[2]*s, _v[3]*s);
213  }
214 
215  //------------------------------------------------------------------------
216  /**
217  * Scalar multiplication operator and assignment operator
218  * \param s A scalar to multiply against
219  * \return This quaternion multiplied by the scalar
220  */
221  //------------------------------------------------------------------------
222  inline GlsQuaternion& operator *= (Type s)
223  {
224  _v[0]*=s;
225  _v[1]*=s;
226  _v[2]*=s;
227  _v[3]*=s;
228  return *this; // enable nesting
229  }
230 
231  //------------------------------------------------------------------------
232  /**
233  * Quaternion multiplication operator
234  * \param q A quaternion to multiply against
235  * \return This quaternion multiplied by the quaternion
236  */
237  //------------------------------------------------------------------------
238  inline const GlsQuaternion operator*(const GlsQuaternion& q) const
239  {
240  return GlsQuaternion( q._v[3]*_v[0] + q._v[0]*_v[3] + q._v[1]*_v[2] - q._v[2]*_v[1],
241  q._v[3]*_v[1] - q._v[0]*_v[2] + q._v[1]*_v[3] + q._v[2]*_v[0],
242  q._v[3]*_v[2] + q._v[0]*_v[1] - q._v[1]*_v[0] + q._v[2]*_v[3],
243  q._v[3]*_v[3] - q._v[0]*_v[0] - q._v[1]*_v[1] - q._v[2]*_v[2] );
244  }
245 
246  //------------------------------------------------------------------------
247  /**
248  * Quaternion multiplication operator
249  * \param q A quaternion to multiply against
250  * \return This quaternion multiplied by the quaternion
251  */
252  //------------------------------------------------------------------------
254  {
255  Type x = q._v[3]*_v[0] + q._v[0]*_v[3] + q._v[1]*_v[2] - q._v[2]*_v[1];
256  Type y = q._v[3]*_v[1] - q._v[0]*_v[2] + q._v[1]*_v[3] + q._v[2]*_v[0];
257  Type z = q._v[3]*_v[2] + q._v[0]*_v[1] - q._v[1]*_v[0] + q._v[2]*_v[3];
258  _v[3] = q._v[3]*_v[3] - q._v[0]*_v[0] - q._v[1]*_v[1] - q._v[2]*_v[2];
259 
260  _v[2] = z;
261  _v[1] = y;
262  _v[0] = x;
263 
264  return (*this); // enable nesting
265  }
266 
267  //------------------------------------------------------------------------
268  /**
269  * Scalar division operator
270  * \param s A scalar to divide
271  * \return This quaternion divided by the scalar
272  */
273  //------------------------------------------------------------------------
274  inline GlsQuaternion operator / (Type s) const
275  {
276  Type div = 1.0/s;
277  return GlsQuaternion(_v[0]*div, _v[1]*div, _v[2]*div, _v[3]*div);
278  }
279 
280  //------------------------------------------------------------------------
281  /**
282  * Scalar division and assignment operator
283  * \param s A scalar to divide
284  * \return This quaternion divided by the scalar
285  */
286  //------------------------------------------------------------------------
287  inline GlsQuaternion& operator /= (Type s)
288  {
289  Type div = 1/s;
290  _v[0]*=div;
291  _v[1]*=div;
292  _v[2]*=div;
293  _v[3]*=div;
294  return *this;
295  }
296 
297  //------------------------------------------------------------------------
298  /**
299  * Quaternion division operator
300  * \param q A quaternion to division by
301  * \return This quaternion divided by the quaternion
302  */
303  //------------------------------------------------------------------------
304  inline const GlsQuaternion operator/(const GlsQuaternion& q) const
305  {
306  return ( (*this) * q.Inverse() );
307  }
308 
309  //------------------------------------------------------------------------
310  /**
311  * Quaternion division operator
312  * \param q A quaternion to division by
313  * \return This quaternion divided by the quaternion
314  */
315  //------------------------------------------------------------------------
317  {
318  (*this) = (*this) * q.Inverse();
319  return (*this); // enable nesting
320  }
321 
322  //------------------------------------------------------------------------
323  /**
324  * Quaternion addition operator
325  * \param q A quaternion to add
326  * \return This quaternion plus the supplied quaternion
327  */
328  //------------------------------------------------------------------------
329  inline const GlsQuaternion operator + (const GlsQuaternion& q) const
330  {
331  return GlsQuaternion(_v[0]+q._v[0], _v[1]+q._v[1],
332  _v[2]+q._v[2], _v[3]+q._v[3]);
333  }
334 
335  //------------------------------------------------------------------------
336  /**
337  * Quaternion addition and assignment operator
338  * \param q A quaternion to add
339  * \return This quaternion plus the supplied quaternion
340  */
341  //------------------------------------------------------------------------
343  {
344  _v[0] += q._v[0];
345  _v[1] += q._v[1];
346  _v[2] += q._v[2];
347  _v[3] += q._v[3];
348  return *this; // enable nesting
349  }
350 
351  //------------------------------------------------------------------------
352  /**
353  * Quaternion subtrtaction operator
354  * \param q A quaternion to subtract
355  * \return This quaternion minus the supplied quaternion
356  */
357  //------------------------------------------------------------------------
358  inline const GlsQuaternion operator - (const GlsQuaternion& q) const
359  {
360  return GlsQuaternion(_v[0]-q._v[0], _v[1]-q._v[1],
361  _v[2]-q._v[2], _v[3]-q._v[3] );
362  }
363 
364  //------------------------------------------------------------------------
365  /**
366  * Quaternion subtraction and assignment operator
367  * \param q A quaternion to subtract
368  * \return This quaternion minus the supplied quaternion
369  */
370  //------------------------------------------------------------------------
372  {
373  _v[0]-=q._v[0];
374  _v[1]-=q._v[1];
375  _v[2]-=q._v[2];
376  _v[3]-=q._v[3];
377  return *this; // enable nesting
378  }
379 
380  /** Negation operator - returns the negative of the quaternion.
381  Basically just calls operator - () on the Vec4 */
382  inline const GlsQuaternion operator - () const
383  {
384  return GlsQuaternion (-_v[0], -_v[1], -_v[2], -_v[3]);
385  }
386 
387  //------------------------------------------------------------------------
388  /**
389  * Returns the magnitude of the quaternion
390  * \return The magnitude of the quaternion
391  */
392  //------------------------------------------------------------------------
393  inline Type Magnitude() const
394  {
395  return sqrt( _v[0]*_v[0] + _v[1]*_v[1] + _v[2]*_v[2] + _v[3]*_v[3]);
396  }
397 
398  //------------------------------------------------------------------------
399  /**
400  * Returns the magnitude squared of the quaternion
401  * \return The magnitude squared of the quaternion
402  */
403  //------------------------------------------------------------------------
404  inline Type MagnitudeSquared() const
405  {
406  return _v[0]*_v[0] + _v[1]*_v[1] + _v[2]*_v[2] + _v[3]*_v[3];
407  }
408 
409  //------------------------------------------------------------------------
410  /**
411  * Returns the conjugate of the quaternion
412  * \return The conjugate of the quaternion
413  */
414  //------------------------------------------------------------------------
415  inline GlsQuaternion Conjugate() const
416  {
417  return GlsQuaternion( -_v[0], -_v[1], -_v[2], _v[3] );
418  }
419 
420  //------------------------------------------------------------------------
421  /**
422  * Returns the inverse of the quaternion
423  * \return The inverse of the quaternion
424  */
425  //------------------------------------------------------------------------
426  inline const GlsQuaternion Inverse() const
427  {
428  return Conjugate() / MagnitudeSquared();
429  }
430 
431  //------------------------------------------------------------------------
432  /**
433  * Returns the dot product of the quaternion and a supplied quaternion
434  * \param q A quaternion to multiply against this quaternion
435  * \return The dot product of the quaternion and a supplied quaternion
436  */
437  //------------------------------------------------------------------------
438  inline Type DotProduct(const GlsQuaternion& q) const
439  {
440  return ( (_v[0] * q._v[0]) +
441  (_v[1] * q._v[1]) +
442  (_v[2] * q._v[2]) +
443  (_v[3] * q._v[3]));
444  }
445 
446  //------------------------------------------------------------------------
447  /**
448  * Normalizes this quaternion
449  */
450  //------------------------------------------------------------------------
451  inline void Normalize()
452  {
453  *this /= Magnitude();
454  }
455 
456  //------------------------------------------------------------------------
457  /**
458  * Sets the component values for this quaternion
459  * \param x The X value
460  * \param y The Y value
461  * \param z The Z value
462  * \param w The W value
463  */
464  //------------------------------------------------------------------------
465  inline void Set(Type x, Type y, Type z, Type w)
466  {
467  _v[0]=x; _v[1]=y; _v[2]=z; _v[3]=w;
468  }
469 
470  //------------------------------------------------------------------------
471  /**
472  * Sets quaternion from angle about an arbitrary axis
473  * \param angle Rotation angle in radians
474  * \param axis Unit vector representing arbitrary axis
475  */
476  //------------------------------------------------------------------------
477  void SetFromAngleAxis( Type angle, const Vector& axis)
478  {
479  Type half_angle = angle * (Type)0.5;
480  Type sin_half_angle = sin( half_angle );
481 
482  _v[0] = sin_half_angle * axis.x;
483  _v[1] = sin_half_angle * axis.y;
484  _v[2] = sin_half_angle * axis.z;
485  _v[3] = cos( half_angle );
486  }
487 
488  //------------------------------------------------------------------------
489  /**
490  * Sets quaternion from three angle-axis pairs.
491  * \param angle1 Rotation angle in radians
492  * \param axis1 Unit vector representing arbitrary axis
493  * \param angle2 Rotation angle in radians
494  * \param axis2 Unit vector representing arbitrary axis
495  * \param angle3 Rotation angle in radians
496  * \param axis3 Unit vector representing arbitrary axis
497  */
498  //------------------------------------------------------------------------
499  void SetFromAngleAxis( Type angle1, const Vector& axis1,
500  Type angle2, const Vector& axis2,
501  Type angle3, const Vector& axis3)
502  {
503  GlsQuaternion q1(angle1, axis1);
504  GlsQuaternion q2(angle2, axis2);
505  SetFromAngleAxis(angle3, axis3);
506 
507  *this = q1 * q2 * *this;
508  }
509 
510  //------------------------------------------------------------------------
511  /**
512  * Sets quaternion from the Euler angles.
513  * \param angleX The X Euler angle in radians
514  * \param angleY The Y Euler angle in radians
515  * \param angleZ The Z Euler angle in radians
516  */
517  //------------------------------------------------------------------------
518  void SetFromEulerAngles( Type angleX, Type angleY, Type angleZ)
519  {
520  GlsQuaternion<Type> qx, qy, qz;
521 
522  // precompute half angles
523  Type xOver2 = angleX * (Type)0.5;
524  Type yOver2 = angleY * (Type)0.5;
525  Type zOver2 = angleZ * (Type)0.5;
526 
527  // set the pitch quat
528  qx._v[0] = sin( xOver2 );
529  qx._v[1] = (Type)0.0;
530  qx._v[2] = (Type)0.0;
531  qx._v[3] = cos( xOver2 );
532 
533  // set the yaw quat
534  qy._v[0] = (Type)0.0;
535  qy._v[1] = sin( yOver2 );
536  qy._v[2] = (Type)0.0;
537  qy._v[3] = cos( yOver2 );
538 
539  // set the roll quat
540  qz._v[0] = (Type)0.0;
541  qz._v[1] = (Type)0.0;
542  qz._v[2] = sin( zOver2 );
543  qz._v[3] = cos( zOver2 );
544 
545  // compose the three in x y z order...
546  *this = qx * qy * qz;
547 
548  this->Normalize();
549  }
550 
551  //------------------------------------------------------------------------
552  /**
553  * Sets this quaternion to a rotation that rotates 'to' into 'from'.
554  * \param to The rotation destination
555  * \param from The rotation start point
556  */
557  //------------------------------------------------------------------------
558  void SetFromVectors(const Vector& to, const Vector& from)
559  {
560  // dot product vec1*vec2
561  Type cosangle = from.DotProduct(to)/(from.Magnitude()*to.Magnitude());
562 
563  if ( IsVeryCloseToZero(cosangle - 1) )
564  {
565  // cosangle is close to 1, so the vectors are close to being coincident
566  // Need to generate an angle of zero with any vector we like
567  // We'll choose (1,0,0)
568  SetFromAngleAxis( 0.0, Vector(1.0,0.0,0.0) );
569  }
570  else
571  if ( IsVeryCloseToZero(cosangle + 1.0) )
572  {
573  // vectors are close to being opposite, so will need to find a
574  // vector orthongonal to from to rotate about.
575  Vector tmp;
576  if (fabs(from.x)<fabs(from.y))
577  if (fabs(from.x)<fabs(from.z)) tmp = Vector(1.0,0.0,0.0); // use x axis.
578  else tmp = Vector(0.0,0.0,1.0);
579  else if (fabs(from.y)<fabs(from.z)) tmp = Vector(0.0,1.0,0.0);
580  else tmp = Vector(0.0,0.0,1.0);
581 
582  // find orthogonal axis.
583  Vector axis(from.CrossProduct(tmp));
584  axis.Normalize();
585 
586  _v[0] = axis.x; // sin of half angle of PI is 1.0.
587  _v[1] = axis.y; // sin of half angle of PI is 1.0.
588  _v[2] = axis.z; // sin of half angle of PI is 1.0.
589  _v[3] = 0; // cos of half angle of PI is zero.
590 
591  }
592  else
593  {
594  // This is the usual situation - take a cross-product of vec1 and vec2
595  // and that is the axis around which to rotate.
596  Vector axis(from.CrossProduct(to));
597  axis.Normalize();
598  Type angle = acos( cosangle );
599  SetFromAngleAxis( angle, axis );
600  }
601  }
602 
603  //------------------------------------------------------------------------
604  /**
605  * Sets this quaternion from the specified rotation matrix.
606  * \param matrix The rotation matrix
607  */
608  //------------------------------------------------------------------------
610  {
611  Type tr, s;
612  Type tq[4];
613  int i, j, k;
614  const Type *mat = const_cast< GlsMatrixAffine<Type>& >(matrix).Data();
615 
616  int nxt[3] = {1, 2, 0};
617 
618  tr = mat[0*4+0] + mat[1*4+1] + mat[2*4+2];
619 
620  // check the diagonal
621  if (tr > 0.0)
622  {
623  s = (Type)sqrt (tr + 1.0);
624  _v[3] = s / 2.0f;
625  s = 0.5f / s;
626  _v[0] = (mat[1*4+2] - mat[2*4+1]) * s;
627  _v[1] = (mat[2*4+0] - mat[0*4+2]) * s;
628  _v[2] = (mat[0*4+1] - mat[1*4+0]) * s;
629  }
630  else
631  {
632  // diagonal is negative
633  i = 0;
634  if (mat[1*4+1] > mat[0*4+0])
635  i = 1;
636  if (mat[2*4+2] > mat[i*4+i])
637  i = 2;
638  j = nxt[i];
639  k = nxt[j];
640 
641  s = (Type)sqrt ((mat[i*4+i] - (mat[j*4+j] + mat[k*4+k])) + 1.0);
642 
643  tq[i] = s * 0.5f;
644 
645  if (s != 0.0f)
646  s = 0.5f / s;
647 
648  tq[3] = (mat[j*4+k] - mat[k*4+j]) * s;
649  tq[j] = (mat[i*4+j] + mat[j*4+i]) * s;
650  tq[k] = (mat[i*4+k] + mat[k*4+i]) * s;
651 
652  _v[0] = tq[0];
653  _v[1] = tq[1];
654  _v[2] = tq[2];
655  _v[3] = tq[3];
656  }
657  }
658 
659  /** Returns the rotation about the X axis
660  * \return The rotation about the X axis
661  */
662  Type GetRoll(void) const
663  {
664  return atan2(2*(_v[1]*_v[2] + _v[3]*_v[0]), _v[3]*_v[3] - _v[0]*_v[0] - _v[1]*_v[1] + _v[2]*_v[2]);
665  }
666 
667  /** Returns the rotation about the Y axis
668  * \return The rotation about the Y axis
669  */
670  Type GetPitch(void) const
671  {
672  Type tmp = -2*(_v[0]*_v[2] - _v[3]*_v[1]);
673 
674  if(tmp > 1.0) { tmp = 1.0; }
675  else if(tmp < -1.0) { tmp = -1.0; }
676 
677  return asin( tmp );
678  }
679  /** Returns the rotation about the Z axis
680  * \return The rotation about the Z axis
681  */
682  Type GetYaw(void) const
683  {
684  return atan2(2*(_v[0]*_v[1] + _v[3]*_v[2]), _v[3]*_v[3] + _v[0]*_v[0] - _v[1]*_v[1] - _v[2]*_v[2]);
685  }
686 
687  /** Returns the Euler Angles as a Vector (Warning: SLOW)
688  * \return The Euler Angles as a Vector
689  */
691  {
692  // This is slow
693  return Vector(float(GetRoll()), float(GetPitch()), float(GetYaw()));
694  }
695 
696  /** Gets the rotation angle (radians) and the axis about which the angle is rotated.
697  * \param angle Returns the angle of rotation of the quaternion
698  * \param axis Returns the axis of rotation of the quaternion
699  */
700  void GetAngleAxis(Type* angle, Vector* axis)
701  {
702  // set sure we don't get a NaN result from acos...
703  #ifdef _WIN32
704  if (abs( _v[3] ) > (Type)1.0)
705  #else
706  if (fabs( (double)_v[3] ) > 1.0)
707  #endif
708  {
709  this->Normalize();
710  }
711 
712  // set the angle - aCos is mathematically defined to be between 0 and PI
713  Type rad = acos( _v[3] ) * (Type)2.0;
714 
715  if(angle)
716  {
717  *angle = rad;
718  }
719 
720  // set the axis: (use sin(rad) instead of asin(w))
721  if(axis)
722  {
723  Type sin_half_angle = sin( rad * (Type)0.5 );
724  if (sin_half_angle >= (Type)0.0001) // because (PI >= rad >= 0)
725  {
726  Type sin_half_angle_inv = Type(1.0) / sin_half_angle;
727  axis->x = float(_v[0] * sin_half_angle_inv);
728  axis->y = float(_v[1] * sin_half_angle_inv);
729  axis->z = float(_v[2] * sin_half_angle_inv);
730  axis->Normalize();
731  }
732 
733  // avoid NAN
734  else
735  {
736  // one of the terms should be a 1,
737  // so we can maintain unit-ness
738  // in case w is 0 (which here w is 0)
739  axis->x = (float)1.0;
740  axis->y = (float)0.0;
741  axis->z = (float)0.0;
742  }
743  }
744 
745  }
746 
747  /** Returns a rotation matrix representation of the quaternion.
748  * \return The rotation matrix computed from the quaternion
749  */
751  {
752  Type wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;
753  Type mat[4][4];
754 
755  x2 = _v[0] + _v[0];
756  y2 = _v[1] + _v[1];
757  z2 = _v[2] + _v[2];
758 
759  xx = _v[0] * x2;
760  xy = _v[0] * y2;
761  xz = _v[0] * z2;
762 
763  yy = _v[1] * y2;
764  yz = _v[1] * z2;
765  zz = _v[2] * z2;
766 
767  wx = _v[3] * x2;
768  wy = _v[3] * y2;
769  wz = _v[3] * z2;
770 
771  mat[0][0] = 1.0f - (yy + zz);
772  mat[0][1] = xy - wz;
773  mat[0][2] = xz + wy;
774  mat[0][3] = 0.0f;
775 
776  mat[1][0] = xy + wz;
777  mat[1][1] = 1.0f - (xx + zz);
778  mat[1][2] = yz - wx;
779  mat[1][3] = 0.0f;
780 
781  mat[2][0] = xz - wy;
782  mat[2][1] = yz + wx;
783  mat[2][2] = 1.0f - (xx + yy);
784  mat[2][3] = 0.0f;
785 
786  mat[3][0] = 0;
787  mat[3][1] = 0;
788  mat[3][2] = 0;
789  mat[3][3] = 1;
790 
791  return GlsMatrixAffine<Type>(mat);
792  }
793 
794  /** Sets this quaternion to an interpolated rotation between the
795  * from and to vectors using spherical linear interpolation (slerp).
796  * \param t Percent of interpelation (0.0 -> 1.0)
797  * \param from The starting quaternion
798  * \param to The ending quaternion
799  * \param adjustSign Whether or not to negate the sign of the to quaternion
800  */
801  void SetFromSlerp(float t, const GlsQuaternion& from, const GlsQuaternion& to, bool adjustSign = true)
802  {
803  const GlsQuaternion& p = from;
804 
805  // calc cosine theta
806  Type cosom = from.DotProduct(to);
807 
808  // adjust signs (if necessary)
810  if (adjustSign && (cosom < (Type)0.0))
811  {
812  cosom = -cosom;
813  q._v[0] = -to._v[0]; // Reverse all signs
814  q._v[1] = -to._v[1];
815  q._v[2] = -to._v[2];
816  q._v[3] = -to._v[3];
817  }
818  else
819  {
820  q = to;
821  }
822 
823  // Calculate coefficients
824  Type sclp, sclq;
825  if (((Type)1.0 - cosom) > (Type)0.0001) // 0.0001 -> some epsillon
826  {
827  // Standard case (slerp)
828  Type omega, sinom;
829  omega = acos( cosom ); // extract theta from dot product's cos theta
830  sinom = sin( omega );
831  sclp = sin( ((Type)1.0 - t) * omega ) / sinom;
832  sclq = sin( t * omega ) / sinom;
833  }
834  else
835  {
836  // Very close, do linear interp (because it's faster)
837  sclp = (Type)1.0 - t;
838  sclq = t;
839  }
840 
841  _v[0] = sclp * p._v[0] + sclq * q._v[0];
842  _v[1] = sclp * p._v[1] + sclq * q._v[1];
843  _v[2] = sclp * p._v[2] + sclq * q._v[2];
844  _v[3] = sclp * p._v[3] + sclq * q._v[3];
845  }
846 
847 protected:
848  Type _v[4];
849 };
850 
851 typedef GlsQuaternion<float> GlsQuaternionF;
852 typedef GlsQuaternion<double> GlsQuaternionD;
853 
854 template <class Type>
855 inline std::ostream& operator<<(std::ostream& outstr, const GlsQuaternion<Type>& quat)
856 {
857  outstr.precision(10);
858 
859  outstr.width(1);
860  outstr << quat.Data()[0]<<" ";
861  outstr.width(8);
862  outstr << quat.Data()[1]<<" ";
863  outstr.width(8);
864  outstr << quat.Data()[2]<<" ";
865  outstr.width(8);
866  outstr << quat.Data()[3];
867 
868  return outstr;
869 }
870 
871 template <class Type>
872 inline std::istream& operator>>(std::istream& instr, GlsQuaternion<Type>& quat)
873 {
874  instr >> quat.Data()[0] >> quat.Data()[1] >> quat.Data()[2] >> quat.Data()[3];
875  return instr;
876 }
877 
878 } // end namespace disti
879 
880 #endif
881 
const Type * Data() const
Definition: gls_quaternion.h:162
GlsQuaternion(Type angle1, const Vector &axis1, Type angle2, const Vector &axis2, Type angle3, const Vector &axis3)
Definition: gls_quaternion.h:104
GlsQuaternion(Type angle, const Vector &axis)
Definition: gls_quaternion.h:88
const GlsQuaternion operator+(const GlsQuaternion &q) const
Definition: gls_quaternion.h:329
const GlsQuaternion operator-() const
Definition: gls_quaternion.h:382
bool operator!=(const GlsQuaternion &q) const
Definition: gls_quaternion.h:182
Vector GetEulerAngles()
Definition: gls_quaternion.h:690
void Normalize(void)
Definition: vertex.h:271
float DotProduct(const VertexNoColor &w) const
Definition: vertex.h:315
GlsQuaternion & operator-=(const GlsQuaternion &q)
Definition: gls_quaternion.h:371
bool operator<(const GlsQuaternion &q) const
Definition: gls_quaternion.h:192
void SetFromVectors(const Vector &to, const Vector &from)
Definition: gls_quaternion.h:558
const GlsQuaternion Inverse() const
Definition: gls_quaternion.h:426
Type GetRoll(void) const
Definition: gls_quaternion.h:662
Type DotProduct(const GlsQuaternion &q) const
Definition: gls_quaternion.h:438
void SetFromAngleAxis(Type angle, const Vector &axis)
Definition: gls_quaternion.h:477
void GetAngleAxis(Type *angle, Vector *axis)
Definition: gls_quaternion.h:700
Type Magnitude() const
Definition: gls_quaternion.h:393
GlsQuaternion(const Vector &anglesVec)
Definition: gls_quaternion.h:131
void SetFromAngleAxis(Type angle1, const Vector &axis1, Type angle2, const Vector &axis2, Type angle3, const Vector &axis3)
Definition: gls_quaternion.h:499
void SetFromEulerAngles(Type angleX, Type angleY, Type angleZ)
Definition: gls_quaternion.h:518
GlsQuaternion(const GlsMatrixAffine< Type > &matrix)
Definition: gls_quaternion.h:142
VertexNoColor Vector
Definition: gls_font_base.h:68
GlsQuaternion(Type angleX, Type angleY, Type angleZ)
Definition: gls_quaternion.h:119
GlsQuaternion Conjugate() const
Definition: gls_quaternion.h:415
GlsQuaternion & operator+=(const GlsQuaternion &q)
Definition: gls_quaternion.h:342
GlsQuaternion & operator/=(Type s)
Definition: gls_quaternion.h:287
VertexNoColor CrossProduct(const VertexNoColor &w) const
Definition: vertex.h:305
Type GetPitch(void) const
Definition: gls_quaternion.h:670
GlsQuaternion()
Definition: gls_quaternion.h:65
Type MagnitudeSquared() const
Definition: gls_quaternion.h:404
GlsQuaternion(Type x, Type y, Type z, Type w)
Definition: gls_quaternion.h:76
void Set(Type x, Type y, Type z, Type w)
Definition: gls_quaternion.h:465
const GlsQuaternion operator*(Type s) const
Definition: gls_quaternion.h:210
GlsQuaternion & operator/=(const GlsQuaternion &q)
Definition: gls_quaternion.h:316
Type * Data()
Definition: gls_quaternion.h:153
Type GetYaw(void) const
Definition: gls_quaternion.h:682
Definition: vertex.h:84
GlsQuaternion & operator*=(const GlsQuaternion &q)
Definition: gls_quaternion.h:253
const GlsQuaternion operator*(const GlsQuaternion &q) const
Definition: gls_quaternion.h:238
Definition: gls_quaternion.h:57
const GlsQuaternion operator/(const GlsQuaternion &q) const
Definition: gls_quaternion.h:304
bool operator==(const GlsQuaternion &q) const
Definition: gls_quaternion.h:172
float Magnitude() const
Definition: vertex.h:290
void SetFromSlerp(float t, const GlsQuaternion &from, const GlsQuaternion &to, bool adjustSign=true)
Definition: gls_quaternion.h:801
GlsMatrixAffine< Type > GetRotationMatrix()
Definition: gls_quaternion.h:750
GlsQuaternion & operator*=(Type s)
Definition: gls_quaternion.h:222
void SetFromRotationMatrix(const GlsMatrixAffine< Type > &matrix)
Definition: gls_quaternion.h:609
void Normalize()
Definition: gls_quaternion.h:451
Definition: bmpimage.h:46
GlsQuaternion operator/(Type s) const
Definition: gls_quaternion.h:274
Definition: gls_matrix_affine.h:61