CQuaternion.h
Go to the documentation of this file.
1 //==============================================================================
2 /*
3  Software License Agreement (BSD License)
4  Copyright (c) 2003-2016, CHAI3D.
5  (www.chai3d.org)
6 
7  All rights reserved.
8 
9  Redistribution and use in source and binary forms, with or without
10  modification, are permitted provided that the following conditions
11  are met:
12 
13  * Redistributions of source code must retain the above copyright
14  notice, this list of conditions and the following disclaimer.
15 
16  * Redistributions in binary form must reproduce the above
17  copyright notice, this list of conditions and the following
18  disclaimer in the documentation and/or other materials provided
19  with the distribution.
20 
21  * Neither the name of CHAI3D nor the names of its contributors may
22  be used to endorse or promote products derived from this software
23  without specific prior written permission.
24 
25  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  POSSIBILITY OF SUCH DAMAGE.
37 
38  \author <http://www.chai3d.org>
39  \author Phil Fong
40  \version 3.2.0 $Rev: 1869 $
41 */
42 //==============================================================================
43 
44 //------------------------------------------------------------------------------
45 #ifndef CQuaternionH
46 #define CQuaternionH
47 //------------------------------------------------------------------------------
48 #include "math/CMatrix3d.h"
49 #include "math/CVector3d.h"
50 //------------------------------------------------------------------------------
51 
52 //------------------------------------------------------------------------------
53 namespace chai3d {
54 //------------------------------------------------------------------------------
55 
56 //==============================================================================
64 //==============================================================================
65 
66 //==============================================================================
82 //==============================================================================
83 struct cQuaternion
84 {
85  //--------------------------------------------------------------------------
86  // MEMBERS:
87  //--------------------------------------------------------------------------
88 
89 public:
90 
92  double w;
93 
95  double x;
96 
98  double y;
99 
101  double z;
102 
103 
104  //--------------------------------------------------------------------------
105  // CONSTRUCTOR & DESTRUCTOR:
106  //--------------------------------------------------------------------------
107 
108 public:
109 
112 
114  cQuaternion(double a_w,
115  double a_x,
116  double a_y,
117  double a_z) : w(a_w), x(a_x), y(a_y), z(a_z) {}
118 
120  cQuaternion(double const* in) : w(in[0]), x(in[1]), y(in[2]), z(in[3]) {}
121 
122 
123  //--------------------------------------------------------------------------
124  // OPERATORS:
125  //--------------------------------------------------------------------------
126 
127 public:
128 
130  inline operator double*() {return &w;}
131 
133  inline operator double const*() const { return &w;}
134 
136  inline cQuaternion& operator*= (cQuaternion const& a_quaternion)
137  {
138  double neww = w*a_quaternion.w - x*a_quaternion.x - y*a_quaternion.y - z*a_quaternion.z;
139  double newx = w*a_quaternion.x + x*a_quaternion.w + y*a_quaternion.z - z*a_quaternion.y;
140  double newy = w*a_quaternion.y - x*a_quaternion.z + y*a_quaternion.w + z*a_quaternion.x;
141  double newz = w*a_quaternion.z + x*a_quaternion.y - y*a_quaternion.x + z*a_quaternion.w;
142  w = neww;
143  x = newx;
144  y = newy;
145  z = newz;
146 
147  return (*this);
148  }
149 
151  inline cQuaternion& operator*= (double a_scale)
152  {
153  w *= a_scale;
154  x *= a_scale;
155  y *= a_scale;
156  z *= a_scale;
157  return (*this);
158  }
159 
161  inline cQuaternion& operator+= (cQuaternion const& a_quaternion)
162  {
163  w+=a_quaternion.w;
164  x+=a_quaternion.x;
165  y+=a_quaternion.y;
166  z+=a_quaternion.z;
167  return (*this);
168  }
169 
171  inline cQuaternion& operator-= (cQuaternion const& a_quaternion)
172  {
173  w-=a_quaternion.w;
174  x-=a_quaternion.x;
175  y-=a_quaternion.y;
176  z-=a_quaternion.z;
177  return (*this);
178  }
179 
181  inline bool operator==(cQuaternion const& a_quaternion) const
182  {
183  return ( (w==a_quaternion.w) &&
184  (x==a_quaternion.x) &&
185  (y==a_quaternion.y) &&
186  (z==a_quaternion.z) );
187  }
188 
189 
190  //--------------------------------------------------------------------------
191  // PUBLIC METHODS:
192  //--------------------------------------------------------------------------
193 
194 public:
195 
197  inline void zero() { w=0.0; x=0.0; y=0.0; z=0.0; }
198 
200  inline void negate() { w=-w; x=-x; y=-y; z=-z; }
201 
203  inline double magsq() const { return (w*w) + (x*x) + (y*y) + (z*z); }
204 
206  inline double lengthsq() const { return magsq(); }
207 
209  inline double mag() const { return sqrt(magsq()); }
210 
212  inline double length() const { return mag(); }
213 
215  inline void normalize()
216  {
217  double m = mag();
218  w /= m;
219  x /= m;
220  y /= m;
221  z /= m;
222  }
223 
224 
225  //--------------------------------------------------------------------------
237  //--------------------------------------------------------------------------
238  inline void toRotMat(cMatrix3d& a_matrix) const
239  {
240  double x2 = 2.0*x*x;
241  double y2 = 2.0*y*y;
242  double z2 = 2.0*z*z;
243  double xy = 2.0*x*y;
244  double wz = 2.0*w*z;
245  double xz = 2.0*x*z;
246  double wy = 2.0*w*y;
247  double yz = 2.0*y*z;
248  double wx = 2.0*w*x;
249 
250  a_matrix(0,0) = 1.0 - y2 - z2;
251  a_matrix(0,1) = xy - wz;
252  a_matrix(0,2) = xz + wy;
253  a_matrix(1,0) = xy + wz;
254  a_matrix(1,1) = 1.0 - x2 - z2;
255  a_matrix(1,2) = yz - wx;
256  a_matrix(2,0) = xz - wy;
257  a_matrix(2,1) = yz + wx;
258  a_matrix(2,2) = 1.0 - x2 - y2;
259  }
260 
261 
262  //--------------------------------------------------------------------------
273  //--------------------------------------------------------------------------
274  inline void fromRotMat(cMatrix3d const& a_matrix)
275  {
276  double trace = 1.0 + a_matrix(0,0) + a_matrix(1,1) + a_matrix(2,2);
277 
278  if (trace > C_SMALL)
279  {
280  double s = 2.0*sqrt(trace);
281  x = (a_matrix(2,1) - a_matrix(1,2))/s;
282  y = (a_matrix(0,2) - a_matrix(2,0))/s;
283  z = (a_matrix(1,0) - a_matrix(0,1))/s;
284  w = 0.25*s;
285  }
286  else if ((a_matrix(0,0) > a_matrix(1,1)) && (a_matrix(0,0) > a_matrix(2,2)))
287  {
288  // column 1 has largest diagonal
289  double s = 2.0*sqrt(1.0+a_matrix(0,0)-a_matrix(1,1)-a_matrix(2,2));
290  x = 0.25*s;
291  y = (a_matrix(1,0) + a_matrix(0,1))/s;
292  z = (a_matrix(0,2) + a_matrix(2,0))/s;
293  w = (a_matrix(2,1) - a_matrix(1,2))/s;
294  }
295  else if (a_matrix(1,1) > a_matrix(2,2))
296  {
297  // column 2 has largest diagonal
298  double s = 2.0*sqrt(1.0+a_matrix(1,1)-a_matrix(0,0)-a_matrix(2,2));
299  x = (a_matrix(1,0) + a_matrix(0,1))/s;
300  y = 0.25*s;
301  z = (a_matrix(2,1) + a_matrix(1,2))/s;
302  w = (a_matrix(0,2) - a_matrix(2,0))/s;
303  }
304  else
305  {
306  // column 3 has largest diagonal
307  double s = 2.0*sqrt(1.0+a_matrix(2,2)-a_matrix(0,0)-a_matrix(1,1));
308  x = (a_matrix(0,2) + a_matrix(2,0))/s;
309  y = (a_matrix(2,1) + a_matrix(1,2))/s;
310  z = 0.25*s;
311  w = (a_matrix(1,0) - a_matrix(0,1))/s;
312  }
313  }
314 
315 
316  //--------------------------------------------------------------------------
328  //--------------------------------------------------------------------------
329  inline void fromAxisAngle(cVector3d a_axis, double a_angleRad)
330  {
331  // note that the axis is passed by value so that we can normalize it
332  // without affecting the original value.
333  a_axis.normalize();
334  double sina = sin(a_angleRad / 2.0);
335  double cosa = cos(a_angleRad / 2.0);
336  w = cosa;
337  x = a_axis(0) * sina;
338  y = a_axis(1) * sina;
339  z = a_axis(2) * sina;
340  }
341 
342 
343  //--------------------------------------------------------------------------
358  //---------------------------------------------------------------------------
359  inline void toAxisAngle(cVector3d& a_axis, double& a_angleRad) const
360  {
361  double cosa = w / mag();
362  a_angleRad = acos(cosa);
363  a_axis(0) = x;
364  a_axis(1) = y;
365  a_axis(2) = z;
366  }
367 
368 
369  //--------------------------------------------------------------------------
378  //---------------------------------------------------------------------------
379  inline void conj()
380  {
381  x = -x;
382  y = -y;
383  z = -z;
384  }
385 
386 
387  //--------------------------------------------------------------------------
397  //---------------------------------------------------------------------------
398  inline void invert()
399  {
400  double m2 = magsq();
401  w = w/m2;
402  x = -x/m2;
403  y = -y/m2;
404  z = -z/m2;
405  }
406 
407 
408  //---------------------------------------------------------------
421  //---------------------------------------------------------------
422  inline void mul(cQuaternion const& a_quaternion)
423  {
424  double neww = w*a_quaternion.w - x*a_quaternion.x - y*a_quaternion.y - z*a_quaternion.z;
425  double newx = w*a_quaternion.x + x*a_quaternion.w + y*a_quaternion.z - z*a_quaternion.y;
426  double newy = w*a_quaternion.y - x*a_quaternion.z + y*a_quaternion.w + z*a_quaternion.x;
427  double newz = w*a_quaternion.z + x*a_quaternion.y - y*a_quaternion.x + z*a_quaternion.w;
428 
429  w = neww;
430  x = newx;
431  y = newy;
432  z = newz;
433  }
434 
435 
436  //---------------------------------------------------------------
448  //---------------------------------------------------------------
449  inline void mul(double a_scale)
450  {
451  w *= a_scale;
452  x *= a_scale;
453  y *= a_scale;
454  z *= a_scale;
455  }
456 
457 
458  //---------------------------------------------------------------
473  //---------------------------------------------------------------
474  inline double dot(cQuaternion const& a_quaternion) const
475  {
476  return (w*a_quaternion.w + x*a_quaternion.x + y*a_quaternion.y + z*a_quaternion.z);
477  }
478 
479 
480  //---------------------------------------------------------------
493  //---------------------------------------------------------------
494  inline void add(cQuaternion const& a_quaternion)
495  {
496  w+=a_quaternion.w;
497  x+=a_quaternion.x;
498  y+=a_quaternion.y;
499  z+=a_quaternion.z;
500  }
501 
502 
503  //---------------------------------------------------------------
516  //---------------------------------------------------------------
517  inline void sub(cQuaternion const& a_quaternion)
518  {
519  w-=a_quaternion.w;
520  x-=a_quaternion.x;
521  y-=a_quaternion.y;
522  z-=a_quaternion.z;
523  }
524 
525 
526  //---------------------------------------------------------------
544  //---------------------------------------------------------------
545  inline void slerp(double a_level,
546  cQuaternion const& a_quaternion0,
547  cQuaternion a_quaternion1)
548  {
549  // a_quaternion1 is passed by value so that we can scale it, etc.
550  // compute angle between a_quaternion0 and a_quaternion1
551  double costheta = a_quaternion0.dot(a_quaternion1);
552  if ((costheta-1.0) < 1e-4 && (costheta-1.0) > -1e-4)
553  {
554  // quaternions are parallel
555  // linearly interpolate and normalize
556  *this = a_quaternion0;
557  this->mul(1.0-a_level);
558  a_quaternion1.mul(a_level);
559  this->operator +=(a_quaternion1);
560  this->normalize();
561  }
562  else
563  {
564  double ratio1, ratio2;
565  if ((costheta+1.0) > -1e-4 && (costheta+1.0) < 1e-4)
566  {
567  // a_quaternion0 and a_quaternion1 are 180 degrees apart
568  // there is no unique path between them
569  a_quaternion1.w = a_quaternion0.z;
570  a_quaternion1.x = -a_quaternion0.y;
571  a_quaternion1.y = a_quaternion0.x;
572  a_quaternion1.z = -a_quaternion0.w;
573  ratio1 = sin(C_PI*(0.5-a_level));
574  ratio2 = sin(C_PI*a_level);
575  }
576  else
577  {
578  if (costheta < 0.0)
579  {
580  costheta = -costheta;
581  a_quaternion1.negate();
582  }
583  double theta = acos(costheta);
584  double sintheta = sin(theta);
585 
586  ratio1 = sin(theta*(1.0-a_level))/sintheta;
587  ratio2 = sin(theta*a_level)/sintheta;
588  }
589  *this = a_quaternion0;
590  this->mul(ratio1);
591  a_quaternion1.mul(ratio2);
592  this->operator +=(a_quaternion1);
593  }
594  }
595 
596 
597  //--------------------------------------------------------------------------
610  //--------------------------------------------------------------------------
611  inline std::string str(const unsigned int a_precision = 2) const
612  {
613  std::string result;
614  result = ("("+
615  cStr(w, a_precision) + "| " +
616  cStr(x, a_precision) + ", " +
617  cStr(y, a_precision) + ", " +
618  cStr(z, a_precision) +
619  ")");
620  return (result);
621  }
622 };
623 
624 
625 //==============================================================================
626 // OPERATORS:
627 //==============================================================================
628 
629 
631 inline cQuaternion operator*(const cQuaternion& a_quaternion, const double a_scale)
632 {
633  cQuaternion result = a_quaternion;
634  result.mul(a_scale);
635  return (result);
636 }
637 
638 
640 inline cQuaternion operator*(const double a_scale, const cQuaternion& a_quaternion)
641 {
642  cQuaternion result = a_quaternion;
643  result.mul(a_scale);
644  return (result);
645 }
646 
647 
649 inline cQuaternion operator*(const cQuaternion& a_quaternion0, const cQuaternion& a_quaternion1)
650 {
651  cQuaternion result = a_quaternion0;
652  result.mul(a_quaternion1);
653  return (result);
654 }
655 
656 
658 inline cQuaternion operator+(const cQuaternion& a_quaternion0, const cQuaternion& a_quaternion1)
659 {
660  cQuaternion result = a_quaternion0;
661  result.add(a_quaternion1);
662  return (result);
663 }
664 
665 
667 inline cQuaternion operator-(const cQuaternion& a_quaternion0, const cQuaternion& a_quaternion1)
668 {
669  cQuaternion result = a_quaternion0;
670  result.sub(a_quaternion1);
671  return (result);
672 }
673 
674 
676 static inline std::ostream &operator << (std::ostream &a_os, cQuaternion const& a_quaternion)
677 {
678  a_os << a_quaternion.str(3);
679  return (a_os);
680 }
681 
682 
683 //------------------------------------------------------------------------------
684 } // namespace chai3d
685 //------------------------------------------------------------------------------
686 
687 //------------------------------------------------------------------------------
688 #endif
689 //------------------------------------------------------------------------------
This class implements a 3D vector.
Definition: CVector3d.h:88
const double C_SMALL
Small value near zero.
Definition: CConstants.h:103
double y
Component y of quaternion.
Definition: CQuaternion.h:98
void fromRotMat(cMatrix3d const &a_matrix)
This method converts a rotation matrix into a quaternion.
Definition: CQuaternion.h:274
void toAxisAngle(cVector3d &a_axis, double &a_angleRad) const
This method converts a quaternion representation into an axis-angle representation.
Definition: CQuaternion.h:359
double lengthsq() const
This method returns the squared value of the quaternion magnitude.
Definition: CQuaternion.h:206
void normalize()
This method normalizes this vector to length 1.
Definition: CVector3d.h:1054
This class implements a quaternion.
Definition: CQuaternion.h:83
cQuaternion operator+(const cQuaternion &a_quaternion0, const cQuaternion &a_quaternion1)
An overloaded + operator for quaternion addition.
Definition: CQuaternion.h:658
void toRotMat(cMatrix3d &a_matrix) const
This method convert this quaternion into a rotation matrix.
Definition: CQuaternion.h:238
cVector3d operator*(const cMatrix3d &a_matrix, const cVector3d &a_vector)
An overloaded * operator for matrix/vector multiplication.
Definition: CMatrix3d.h:2078
std::string cStr(const bool a_value)
This function converts a boolean into a string.
Definition: CString.cpp:189
cQuaternion & operator*=(cQuaternion const &a_quaternion)
*= operator (Grassman product).
Definition: CQuaternion.h:136
void sub(cQuaternion const &a_quaternion)
This method computes the subtraction between this quaternion and another passed as argument...
Definition: CQuaternion.h:517
void invert()
This method inverts this quaternion.
Definition: CQuaternion.h:398
cQuaternion(double a_w, double a_x, double a_y, double a_z)
Constructor of cQuaternion.
Definition: CQuaternion.h:114
const double C_PI
PI constant.
Definition: CConstants.h:88
std::string str(const unsigned int a_precision=2) const
This method converts this quaternion into a string.
Definition: CQuaternion.h:611
This class implements a 3D matrix.
Definition: CMatrix3d.h:97
cQuaternion operator-(const cQuaternion &a_quaternion0, const cQuaternion &a_quaternion1)
An overloaded - operator for quaternion subtraction.
Definition: CQuaternion.h:667
double x
Component x of quaternion.
Definition: CQuaternion.h:95
double magsq() const
This method returns the squared value of the quaternion magnitude.
Definition: CQuaternion.h:203
void conj()
This method computes the conjugate of this quaternion.
Definition: CQuaternion.h:379
void normalize()
This method normalizes this quaternion.
Definition: CQuaternion.h:215
Implements a 3D matrix.
void mul(cQuaternion const &a_quaternion)
This method computes the multiplication of this quaternion with another quaternion.
Definition: CQuaternion.h:422
double dot(cQuaternion const &a_quaternion) const
This method computes the dot product between this quaternion and another quaternion.
Definition: CQuaternion.h:474
void zero()
This method clears this quaternion with zeros.
Definition: CQuaternion.h:197
cQuaternion & operator+=(cQuaternion const &a_quaternion)
+= operator.
Definition: CQuaternion.h:161
double z
Component z of quaternion.
Definition: CQuaternion.h:101
cQuaternion & operator-=(cQuaternion const &a_quaternion)
-= operator.
Definition: CQuaternion.h:171
bool operator==(cQuaternion const &a_quaternion) const
== operator.
Definition: CQuaternion.h:181
Implements a 3D vector.
void fromAxisAngle(cVector3d a_axis, double a_angleRad)
This method converts an axis-angle representation into a quaternion.
Definition: CQuaternion.h:329
void negate()
This method negates this quaternion.
Definition: CQuaternion.h:200
Definition: CAudioBuffer.cpp:56
double length() const
This method returns the quaternion magnitude.
Definition: CQuaternion.h:212
cQuaternion()
Constructor of cQuaternion.
Definition: CQuaternion.h:111
void mul(double a_scale)
This method multiplies this quaternion by a scalar.
Definition: CQuaternion.h:449
double mag() const
This method returns the quaternion magnitude.
Definition: CQuaternion.h:209
void add(cQuaternion const &a_quaternion)
This method computes the addition between this quaternion and another passed as argument.
Definition: CQuaternion.h:494
void slerp(double a_level, cQuaternion const &a_quaternion0, cQuaternion a_quaternion1)
This method computes a spherical linear interpolation between two quaternions (SLERP).
Definition: CQuaternion.h:545
cQuaternion(double const *in)
Constructor of cQuaternion.
Definition: CQuaternion.h:120
double w
Component w of quaternion.
Definition: CQuaternion.h:92