NGL  6.5
The NCCA Graphics Library
Quaternion.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 Rob Bateman / Jon Macey
3 
4  This program is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITH ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this progra_m. If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 //----------------------------------------------------------------------------------------------------------------------
21 //----------------------------------------------------------------------------------------------------------------------
22 
23 #include "Quaternion.h"
24 #include "Util.h"
25 
26 namespace ngl
27 {
28 
29 //----------------------------------------------------------------------------------------------------------------------
30 Quaternion::Quaternion(const Mat4 &_m) noexcept
31 {
32  Real T = 1 + _m.m_openGL[0] + _m.m_openGL[5] + _m.m_openGL[10];
33  if ( T > 0.00000001f ) //to avoid large distortions!
34  {
35  Real S = static_cast<Real>(sqrt(T) * 2.0f);
36  m_x = ( _m.m_openGL[6] - _m.m_openGL[9] ) / S;
37  m_y = ( _m.m_openGL[8] - _m.m_openGL[2] ) / S;
38  m_z = ( _m.m_openGL[1] - _m.m_openGL[4] ) / S;
39  m_s = 0.25f * S;
40  }
41  else
42  if ( _m.m_openGL[0] > _m.m_openGL[5] &&
43  _m.m_openGL[0] > _m.m_openGL[10] )
44  { // Column 0:
45  Real S = static_cast<Real>(sqrt( 1.0f + _m.m_openGL[0] - _m.m_openGL[5] - _m.m_openGL[10] ) * 2.0f);
46  m_x = 0.25f * S;
47  m_y = (_m.m_openGL[1] + _m.m_openGL[4] ) / S;
48  m_z = (_m.m_openGL[8] + _m.m_openGL[2] ) / S;
49  m_s = (_m.m_openGL[6] - _m.m_openGL[9] ) / S;
50  }
51  else
52  if ( _m.m_openGL[5] > _m.m_openGL[10] )
53  { // Column 1:
54  Real S = static_cast<Real>(sqrt( 1.0 + _m.m_openGL[5] - _m.m_openGL[0] - _m.m_openGL[10] ) * 2.0f);
55  m_x = (_m.m_openGL[1] + _m.m_openGL[4] ) / S;
56  m_y = 0.25f * S;
57  m_z = (_m.m_openGL[6] + _m.m_openGL[9] ) / S;
58  m_s = (_m.m_openGL[8] - _m.m_openGL[2] ) / S;
59  }
60  else
61  { // Column 2:
62  Real S = static_cast<Real>(sqrt( 1.0 + _m.m_openGL[10] - _m.m_openGL[0] - _m.m_openGL[5] ) * 2.0f);
63  m_x = (_m.m_openGL[8] + _m.m_openGL[2] ) / S;
64  m_y = (_m.m_openGL[6] + _m.m_openGL[9] ) / S;
65  m_z = 0.25f * S;
66  m_s = (_m.m_openGL[1] - _m.m_openGL[4] ) / S;
67  }
68 }
69 
70 Quaternion::Quaternion(const Vec3 &_rot) noexcept
71 {
72 
73  Real sx = sinf(radians(_rot.m_x/2.0f));
74  Real sy = sinf(radians(_rot.m_y/2.0f));
75  Real sz = sinf(radians(_rot.m_z/2.0f));
76  Real cx = cosf(radians(_rot.m_x/2.0f));
77  Real cy = cosf(radians(_rot.m_y/2.0f));
78  Real cz = cosf(radians(_rot.m_z/2.0f));
79 
80  m_s=cx*cy*cz + sx*sy*sz,
81  m_x=sx*cy*cz - cx*sy*sz,
82  m_y=cx*sy*cz + sx*cy*sz,
83  m_z=cx*cy*sz - sx*sy*cz;
84 
85 }
86 
87 //----------------------------------------------------------------------------------------------------------------------
89 {
90  Quaternion ret(0.0,0.0,0.0,0.0);
91  // if we have two Quaternions Qa Qb we get the following
92  // Qa*Qb
93  // first we do the scalar parts SaSb - A . B (where A and B are the vector parts) . the dot product
94  ret.m_s=(m_s*_q.m_s)-(m_x*_q.m_x+m_y*_q.m_y+m_z*_q.m_z);
95  // now the x component of the vector part
96  // this is the form of saB + sbA + sbA + A x B (X is the cross product)
97 
98  Vec4 v1( m_x, m_y, m_z );
99  Vec4 v2( _q.m_x, _q.m_y, _q.m_z );
100 
101  Vec4 vectorPart = (m_s * v2) + (_q.m_s * v1) + (v1.cross(v2));
102 
103  ret.m_x=vectorPart.m_x;
104  ret.m_y=vectorPart.m_y;
105  ret.m_z=vectorPart.m_z;
106  return ret;
107 }
108 
109 //----------------------------------------------------------------------------------------------------------------------
110 void Quaternion::operator *=(const Quaternion& _q) noexcept
111 {
112  // as we have already written the code to do the mult above re-use
113  *this=*this*_q;
114 }
115 
116 //----------------------------------------------------------------------------------------------------------------------
118 {
119  Quaternion ret;
120  ret.m_s=m_s+_q.m_s;
121  ret.m_x=m_x+_q.m_x;
122  ret.m_y=m_y+_q.m_y;
123  ret.m_z=m_z+_q.m_z;
124  return ret;
125 }
126 
127 //----------------------------------------------------------------------------------------------------------------------
129 {
130  Quaternion ret;
131  ret.m_s=m_s-_q.m_s;
132  ret.m_x=m_x-_q.m_x;
133  ret.m_y=m_y-_q.m_y;
134  ret.m_z=m_z-_q.m_z;
135  return ret;
136 }
137 
138 
139 //----------------------------------------------------------------------------------------------------------------------
140 void Quaternion::operator +=(const Quaternion& _q) noexcept
141 {
142  // re-call the code from above
143  *this=*this+_q;
144 }
145 //----------------------------------------------------------------------------------------------------------------------
146 void Quaternion::operator -=(const Quaternion& _q) noexcept
147 {
148  // re-call the code from above
149  *this=*this-_q;
150 }
151 
152 //----------------------------------------------------------------------------------------------------------------------
154 {
155  return Quaternion(m_s*_s,m_x*_s,m_y*_s,m_z*_s);
156 
157 }
158 
159 //----------------------------------------------------------------------------------------------------------------------
160 void Quaternion::operator *=(Real _s) noexcept
161 {
162  m_s*=_s;
163  m_x*=_s;
164  m_y*=_s;
165  m_z*=_s;
166 }
167 
168 
169 
170 //----------------------------------------------------------------------------------------------------------------------
171 void Quaternion::normalise() noexcept
172 {
173  Real inverseOverOne = 1.0f/magnitude();
174  m_s*=inverseOverOne;
175  m_x*=inverseOverOne;
176  m_y*=inverseOverOne;
177  m_z*=inverseOverOne;
178 }
179 
180 
181 //----------------------------------------------------------------------------------------------------------------------
183 {
184  return static_cast<Real>( sqrt(m_s*m_s + m_x*m_x + m_y*m_y + m_z*m_z) );
185 }
186 
187 //----------------------------------------------------------------------------------------------------------------------
188 bool Quaternion::operator == (const Quaternion& _q)const noexcept
189 {
190  return (
191  FCompare(_q.m_s,m_s) &&
192  FCompare(_q.m_x,m_x) &&
193  FCompare(_q.m_y,m_y) &&
194  FCompare(_q.m_z,m_z)
195  );
196 }
197 
198 
199 //----------------------------------------------------------------------------------------------------------------------
200 Vec4 Quaternion::operator* (const Vec4 &_vec) const noexcept
201 {
202  Quaternion temp=-*this;
203  Quaternion point(0.0,_vec.m_x,_vec.m_y,_vec.m_z);
204  point = temp*point* *this;
205  return Vec4(point.m_x,point.m_y,point.m_z,1.0);
206 }
207 
208 
209 
210 
211 void Quaternion::rotateX(Real _angle) noexcept
212 {
213 _angle/=2.0;
214 // q=[cos 1/2 theta, sin 1/2 theta V]
215 m_s=cosf(radians(_angle));
216 m_x=sinf(radians(_angle));
217 m_y=0;
218 m_z=0;
219 }
220 
221 void Quaternion::rotateY(Real _angle) noexcept
222 {
223  _angle/=2.0;
224  // q=[cos 1/2 theta, sin 1/2 theta V]
225  m_s=cosf(radians(_angle));
226  m_x=0;
227 
228  m_y=sinf(radians(_angle));
229  m_z=0;
230 }
231 
232 void Quaternion::rotateZ(Real _angle) noexcept
233 {
234 
235  _angle/=2.0;
236  // q=[cos 1/2 theta, sin 1/2 theta V]
237  m_s=cosf(radians(_angle));
238  m_x=0;
239  m_y=0;
240  m_z=sinf(radians(_angle));
241 
242 }
243 
244 
245 void Quaternion::fromAxisAngle(const Vec3& _axis, Real _angle) noexcept
246 {
247  Vec3 axis = _axis;
248  axis.normalize();
249  _angle=radians(_angle);
250  Real sinAngle = static_cast<Real>(sin( _angle / 2.0f ));
251  Real cosAngle = static_cast<Real>(cos( _angle / 2.0f ));
252  m_s = cosAngle;
253  m_x = axis.m_x * sinAngle;
254  m_y = axis.m_y * sinAngle;
255  m_z = axis.m_z * sinAngle;
256 }
257 
258 
259 void Quaternion::fromEulerAngles(const Real _x,const Real _y,const Real _z) noexcept
260 {
261  Real sx = sinf(radians(_x/2.0f));
262  Real sy = sinf(radians(_y/2.0f));
263  Real sz = sinf(radians(_z/2.0f));
264  Real cx = cosf(radians(_x/2.0f));
265  Real cy = cosf(radians(_y/2.0f));
266  Real cz = cosf(radians(_z/2.0f));
267 
268  m_s=cx*cy*cz + sx*sy*sz,
269  m_x=sx*cy*cz - cx*sy*sz,
270  m_y=cx*sy*cz + sx*cy*sz,
271  m_z=cx*cy*sz - sx*sy*cz;
272 }
273 
274 void Quaternion::rotatePoint(const Quaternion& _r,Vec3 & io_p) noexcept
275 {
276 Quaternion temp = -_r;
277 Quaternion point(0.0,io_p.m_x, io_p.m_y, io_p.m_z);
278 point = temp * point * _r;
279 io_p.set(point.m_x, point.m_y, point.m_z);
280 }
281 
282 void Quaternion::toAxisAngle(Vec3& o_axis,Real &o_angle) noexcept
283 {
284  o_angle = degrees(static_cast<Real>(acos( m_s ) * 2.0f));
285  Real sinA = static_cast<Real>(sqrt( 1.0f - m_s * m_s ));
286  if( fabs( sinA ) < 0.0005f )
287  {
288  sinA = 1.0f;
289  }
290  o_axis.m_x = m_x / sinA;
291  o_axis.m_y = m_y / sinA;
292  o_axis.m_z = m_z / sinA;
293 }
294 
295 Quaternion Quaternion::slerp(const Quaternion &_q1, const Quaternion &_q2, const Real &_t) noexcept
296 {
297  // based on the http://ggt.sourceforge.net/ gmtl version from assimp
298  Quaternion out;
299  // calc cosine theta
300  Real cosom = _q1.m_x * _q2.m_x + _q1.m_y * _q2.m_y + _q1.m_z * _q2.m_z + _q1.m_s * _q2.m_s;
301 
302  // adjust signs (if necessary)
303  Quaternion end = _q2;
304  if( cosom < 0.0f)
305  {
306  cosom = -cosom;
307  end.m_x = -end.m_x; // Reverse all signs
308  end.m_y = -end.m_y;
309  end.m_z = -end.m_z;
310  end.m_s = -end.m_s;
311  }
312 
313  // Calculate coefficients
314  Real sclp, sclq;
315  if( (1.0f - cosom) > 0.0001f) // 0.0001 -> some epsillon
316  {
317  // Standard case (slerp)
318  Real omega, sinom;
319  omega = acosf( cosom); // extract theta from dot product's cos theta
320  sinom = sinf( omega);
321  sclp = sinf( (1.0f - _t) * omega) / sinom;
322  sclq = sinf( _t * omega) / sinom;
323  }
324  else
325  {
326  // Very close, do linear interp (because it's faster)
327  sclp = 1.0f - _t;
328  sclq = _t;
329  }
330 
331  out.m_x = sclp * _q1.m_x + sclq * end.m_x;
332  out.m_y = sclp * _q1.m_y + sclq * end.m_y;
333  out.m_z = sclp * _q1.m_z + sclq * end.m_z;
334  out.m_s = sclp * _q1.m_s + sclq * end.m_s;
335  return out;
336 }
337 
338 
339 
340 Mat4 Quaternion::toMat4() const noexcept
341 {
342  // written by Rob Bateman
343  // sacrafice a few bytes to pre-calculate some values
344  Real xx = m_x * m_x;
345  Real xy = m_x * m_y;
346  Real xz = m_x * m_z;
347  Real xs = m_x * m_s;
348  Real yy = m_y * m_y;
349  Real yz = m_y * m_z;
350  Real ys = m_y * m_s;
351  Real zz = m_z * m_z;
352  Real zs = m_z * m_s;
353  Mat4 o;
354  o.m_openGL[0] = 1.0f - 2.0f * (yy+zz);
355  o.m_openGL[1] = 2.0f * (xy+zs);
356  o.m_openGL[2] = 2.0f * (xz-ys);
357  o.m_openGL[3] = 0.0f;
358 
359  // [4] -> [7]
360  o.m_openGL[4] = 2.0f * (xy-zs);
361  o.m_openGL[5] = 1.0f - 2.0f * (xx+zz);
362  o.m_openGL[6] = 2.0f * (yz+xs);
363  o.m_openGL[7] = 0.0f;
364 
365  // [8] -> [11]
366  o.m_openGL[8] = 2.0f * (xz+ys);
367  o.m_openGL[9] = 2.0f * (yz-xs);
368  o.m_openGL[10]= 1.0f - 2.0f * (xx+yy);
369  o.m_openGL[11] = 0.0f;
370 
371  // [12] -> [15]
372  o.m_openGL[12] = 0.0f;
373  o.m_openGL[13] = 0.0f;
374  o.m_openGL[14] = 0.0f;
375  o.m_openGL[15] = 1.0f;
376  return o;
377 }
378 
380 {
381  // written by Rob Bateman
382  // sacrafice a few bytes to pre-calculate some values
383  Real xx = m_x * m_x;
384  Real xy = m_x * m_y;
385  Real xz = m_x * m_z;
386  Real xs = m_x * m_s;
387  Real yy = m_y * m_y;
388  Real yz = m_y * m_z;
389  Real ys = m_y * m_s;
390  Real zz = m_z * m_z;
391  Real zs = m_z * m_s;
392  Mat4 o;
393  o.m_openGL[0] = 1.0f - 2.0f * (yy+zz);
394  o.m_openGL[4] = 2.0f * (xy+zs);
395  o.m_openGL[8] = 2.0f * (xz-ys);
396  o.m_openGL[12] = 0.0f;
397 
398  // [4] -> [7]
399  o.m_openGL[1] = 2.0f * (xy-zs);
400  o.m_openGL[5] = 1.0f - 2.0f * (xx+zz);
401  o.m_openGL[9] = 2.0f * (yz+xs);
402  o.m_openGL[13] = 0.0f;
403 
404  // [8] -> [11]
405  o.m_openGL[2] = 2.0f * (xz+ys);
406  o.m_openGL[6] = 2.0f * (yz-xs);
407  o.m_openGL[10]= 1.0f - 2.0f * (xx+yy);
408  o.m_openGL[14] = 0.0f;
409 
410  // [12] -> [15]
411  o.m_openGL[3] = 0.0f;
412  o.m_openGL[7] = 0.0f;
413  o.m_openGL[11] = 0.0f;
414  o.m_openGL[15] = 1.0f;
415  return o;
416 }
417 
418 
419 
420 
421 } // end ngl namespace
422 //----------------------------------------------------------------------------------------------------------------------
423 
424 
425 
some useful definitions and functions
void rotateZ(Real _angle) noexcept
set the current quaternion as a rotation around the Z cartesian axis [0,0,1]
Definition: Quaternion.cpp:232
void fromEulerAngles(const Real _x, const Real _y, const Real _z) noexcept
set the current quaternion as a rotation based on 3 Euler angles this will create the quat as a produ...
Definition: Quaternion.cpp:259
simple Vector class for OpenGL graphics, contains overloaded operators for most math functions...
Definition: Vec4.h:57
Quaternion operator+(const Quaternion &_q) const noexcept
add two quaternions
Definition: Quaternion.cpp:117
Real m_s
the quaternion data for the scalar real part
Definition: Quaternion.h:306
GLfloat GLfloat v1
Definition: glew.h:1855
void operator-() noexcept
conjugate negate the vector part but for the current vector -
Definition: Quaternion.h:220
void normalise() noexcept
normalise this quaternion this sets each of the component parts by calculating the magnitude and divi...
Definition: Quaternion.cpp:171
GLfloat GLfloat GLfloat v2
Definition: glew.h:1859
void rotateX(Real _angle) noexcept
set the current quaternion as a rotation around the X cartesian axis [1,0,0]
Definition: Quaternion.cpp:211
Real m_y
the quaternion data for y
Definition: Quaternion.h:310
simple Vec3 encapsulates a 3 float object like glsl vec3 but not maths use the Vec3 class for maths a...
Definition: Vec3.h:51
implementation files for RibExport class
Definition: AABB.cpp:22
Real m_x
the quaternion data for x
Definition: Quaternion.h:308
PRECISION Real
create a variable called Real which is the main data type we use (GLfloat for most cases) ...
Definition: Types.h:127
Quaternion operator*(const Quaternion &_q) const noexcept
Perform a multiplication between 2 quaternions.
Definition: Quaternion.cpp:88
#define FCompare(a, b)
FCompare macro used for floating point comparision functions.
Definition: Types.h:136
void fromAxisAngle(const Vec3 &_axis, Real _angle) noexcept
set the current quaternion as a rotation around the vector _axis
Definition: Quaternion.cpp:245
void operator+=(const Quaternion &_q) noexcept
add _q to the current quaternion
Definition: Quaternion.cpp:140
void set(Real _s, Real _x, Real _y, Real _z) noexcept
method to set the quaternion values
Definition: Quaternion.h:87
void operator-=(const Quaternion &_q) noexcept
subtract _q from the current quaternion
Definition: Quaternion.cpp:146
Real m_y
y component
Definition: Vec3.h:311
void toAxisAngle(Vec3 &o_axis, Real &o_angle) noexcept
return the axis and angle of the current quat (angle in degrees)
Definition: Quaternion.cpp:282
GLuint GLuint end
Definition: glew.h:1256
Real m_z
z component
Definition: Vec4.h:323
Real m_x
x component
Definition: Vec3.h:310
Quaternion(const Real _s=0.0f, const Real _x=0.0f, const Real _y=0.0f, const Real _z=0.0f) noexcept
constructor I use the format used in John Vinces bood where we have a scalar and a vector...
Definition: Quaternion.h:51
Real m_z
the quaternion data for z
Definition: Quaternion.h:312
Defines the class Quaternion based on John Vinces lecture notes basically we have a scalar part and t...
Real m_x
x component
Definition: Vec4.h:321
NGL_DLLEXPORT Real degrees(const Real _rad) noexcept
converts Radians to Degrees
Definition: Util.cpp:95
Mat4 toMat4() const noexcept
return the current quat as a 4x4 transform matrix
Definition: Quaternion.cpp:340
void rotatePoint(const Quaternion &_r, Vec3 &io_p) noexcept
rotate our point by a quat (but can also be done using the * operator)
Definition: Quaternion.cpp:274
void rotateY(Real _angle) noexcept
set the current quaternion as a rotation around the Y cartesian axis [0,1,0]
Definition: Quaternion.cpp:221
void operator*=(const Quaternion &_q) noexcept
Perform a multiplication this and another quaternions sets the current quat q1 = q1*q2.
Definition: Quaternion.cpp:110
NGL_DLLEXPORT Real radians(const Real _deg)
converts Degrees to Radians
Definition: Util.cpp:89
Matrix Class to do simple matrix operations included operator overloaded functions for maths and matr...
Definition: Mat4.h:58
std::array< Real, 16 > m_openGL
The matrix in m_openGL 16 Real array format usefull for OpenGL fv formats mapped to m_m[][] elements ...
Definition: Mat4.h:300
Mat4 toMat4Transpose() const noexcept
return the current quat as a 4x4 transform matrix transposed
Definition: Quaternion.cpp:379
Real m_y
y component
Definition: Vec4.h:322
bool operator==(const Quaternion &_q) const noexcept
test for equality
Definition: Quaternion.cpp:188
void normalize() noexcept
Normalize the vector using .
Definition: Vec3.cpp:206
void cross(const Vec4 &_v1, const Vec4 &_v2) noexcept
set the vector as the cross product from 2 other vectors
Definition: Vec4.cpp:110
static Quaternion slerp(const Quaternion &_q1, const Quaternion &_q2, const Real &_t) noexcept
this function spherically interpolates between two quaternions with respect to t
Definition: Quaternion.cpp:295
Real m_z
z component
Definition: Vec3.h:312
Real magnitude() const noexcept
returns the magnitude of the quaternion
Definition: Quaternion.cpp:182
GLclampf f
Definition: glew.h:3511