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