libmoldeo (Moldeo 1.0 Core)  1.0
libmoldeo is the group of objects and functions that executes the basic operations of Moldeo 1.0 Platform.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
moMathQuaternion.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2 
3  moMathQuaternion.cpp
4 
5  ****************************************************************************
6  * *
7  * This source is free software; you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation; either version 2 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This code is distributed in the hope that it will be useful, but *
13  * WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
15  * General Public License for more details. *
16  * *
17  * A copy of the GNU General Public License is available on the World *
18  * Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
19  * obtain it by writing to the Free Software Foundation, *
20  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21  * *
22  ****************************************************************************
23 
24  Copyright(C) 2006 Fabricio Costa
25 
26  Authors:
27  Fabricio Costa
28  Andrés Colubri
29 
30  Portions taken from
31  Wild Magic Source Code
32  David Eberly
33  http://www.geometrictools.com
34  Copyright (c) 1998-2007
35 
36 *******************************************************************************/
37 
38 #include "moMathQuaternion.h"
39 
40 template <class Real>
42 {
43  // uninitialized for performance in array construction
44 }
45 
46 template <class Real>
47 moQuaternion<Real>::moQuaternion (Real fW, Real fX, Real fY, Real fZ)
48 {
49  m_afTuple[0] = fW;
50  m_afTuple[1] = fX;
51  m_afTuple[2] = fY;
52  m_afTuple[3] = fZ;
53 }
54 
55 template <class Real>
57 {
58  m_afTuple[0] = rkQ.m_afTuple[0];
59  m_afTuple[1] = rkQ.m_afTuple[1];
60  m_afTuple[2] = rkQ.m_afTuple[2];
61  m_afTuple[3] = rkQ.m_afTuple[3];
62 }
63 
64 template <class Real>
65 moQuaternion<Real>::moQuaternion (const moMatrix3<Real>& rkRot)
66 {
67  FromRotationMatrix(rkRot);
68 }
69 
70 template <class Real>
72 {
73  FromAxisAngle(rkAxis,fAngle);
74 }
75 
76 template <class Real>
78 {
79  FromRotationMatrix(akRotColumn);
80 }
81 
82 template <class Real>
84 {
85  return memcmp(m_afTuple,rkQ.m_afTuple,4*sizeof(Real));
86 }
87 
88 template <class Real>
90 {
91  return CompareArrays(rkQ) == 0;
92 }
93 
94 template <class Real>
96 {
97  return CompareArrays(rkQ) != 0;
98 }
99 
100 template <class Real>
102 {
103  return CompareArrays(rkQ) < 0;
104 }
105 
106 template <class Real>
108 {
109  return CompareArrays(rkQ) <= 0;
110 }
111 
112 template <class Real>
114 {
115  return CompareArrays(rkQ) > 0;
116 }
117 
118 template <class Real>
120 {
121  return CompareArrays(rkQ) >= 0;
122 }
123 
124 template <class Real>
126  const moMatrix3<Real>& rkRot)
127 {
128  // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
129  // article "Quaternion Calculus and Fast Animation".
130 
131  Real fTrace = rkRot(0,0) + rkRot(1,1) + rkRot(2,2);
132  Real fRoot;
133 
134  if (fTrace > (Real)0.0)
135  {
136  // |w| > 1/2, may as well choose w > 1/2
137  fRoot = moMath<Real>::Sqrt(fTrace + (Real)1.0); // 2w
138  m_afTuple[0] = ((Real)0.5)*fRoot;
139  fRoot = ((Real)0.5)/fRoot; // 1/(4w)
140  m_afTuple[1] = (rkRot(2,1)-rkRot(1,2))*fRoot;
141  m_afTuple[2] = (rkRot(0,2)-rkRot(2,0))*fRoot;
142  m_afTuple[3] = (rkRot(1,0)-rkRot(0,1))*fRoot;
143  }
144  else
145  {
146  // |w| <= 1/2
147  int i = 0;
148  if ( rkRot(1,1) > rkRot(0,0) )
149  {
150  i = 1;
151  }
152  if ( rkRot(2,2) > rkRot(i,i) )
153  {
154  i = 2;
155  }
156  int j = ms_iNext[i];
157  int k = ms_iNext[j];
158 
159  fRoot = moMath<Real>::Sqrt(rkRot(i,i)-rkRot(j,j)-rkRot(k,k)+(Real)1.0);
160  Real* apfQuat[3] = { &m_afTuple[1], &m_afTuple[2], &m_afTuple[3] };
161  *apfQuat[i] = ((Real)0.5)*fRoot;
162  fRoot = ((Real)0.5)/fRoot;
163  m_afTuple[0] = (rkRot(k,j)-rkRot(j,k))*fRoot;
164  *apfQuat[j] = (rkRot(j,i)+rkRot(i,j))*fRoot;
165  *apfQuat[k] = (rkRot(k,i)+rkRot(i,k))*fRoot;
166  }
167 
168  return *this;
169 }
170 
171 template <class Real>
172 void moQuaternion<Real>::ToRotationMatrix (moMatrix3<Real>& rkRot) const
173 {
174  Real fTx = ((Real)2.0)*m_afTuple[1];
175  Real fTy = ((Real)2.0)*m_afTuple[2];
176  Real fTz = ((Real)2.0)*m_afTuple[3];
177  Real fTwx = fTx*m_afTuple[0];
178  Real fTwy = fTy*m_afTuple[0];
179  Real fTwz = fTz*m_afTuple[0];
180  Real fTxx = fTx*m_afTuple[1];
181  Real fTxy = fTy*m_afTuple[1];
182  Real fTxz = fTz*m_afTuple[1];
183  Real fTyy = fTy*m_afTuple[2];
184  Real fTyz = fTz*m_afTuple[2];
185  Real fTzz = fTz*m_afTuple[3];
186 
187  rkRot(0,0) = (Real)1.0-(fTyy+fTzz);
188  rkRot(0,1) = fTxy-fTwz;
189  rkRot(0,2) = fTxz+fTwy;
190  rkRot(1,0) = fTxy+fTwz;
191  rkRot(1,1) = (Real)1.0-(fTxx+fTzz);
192  rkRot(1,2) = fTyz-fTwx;
193  rkRot(2,0) = fTxz-fTwy;
194  rkRot(2,1) = fTyz+fTwx;
195  rkRot(2,2) = (Real)1.0-(fTxx+fTyy);
196 }
197 
198 template <class Real>
200  const moVector3<Real> akRotColumn[3])
201 {
202  moMatrix3<Real> kRot;
203  for (int iCol = 0; iCol < 3; iCol++)
204  {
205  kRot(0,iCol) = akRotColumn[iCol][0];
206  kRot(1,iCol) = akRotColumn[iCol][1];
207  kRot(2,iCol) = akRotColumn[iCol][2];
208  }
209  return FromRotationMatrix(kRot);
210 }
211 
212 template <class Real>
214 {
215  moMatrix3<Real> kRot;
216  ToRotationMatrix(kRot);
217  for (int iCol = 0; iCol < 3; iCol++)
218  {
219  akRotColumn[iCol][0] = kRot(0,iCol);
220  akRotColumn[iCol][1] = kRot(1,iCol);
221  akRotColumn[iCol][2] = kRot(2,iCol);
222  }
223 }
224 
225 template <class Real>
227  const moVector3<Real>& rkAxis, Real fAngle)
228 {
229  // assert: axis[] is unit length
230  //
231  // The quaternion representing the rotation is
232  // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
233 
234  Real fHalfAngle = ((Real)0.5)*fAngle;
235  Real fSin = moMath<Real>::Sin(fHalfAngle);
236  m_afTuple[0] = moMath<Real>::Cos(fHalfAngle);
237  m_afTuple[1] = fSin*rkAxis[0];
238  m_afTuple[2] = fSin*rkAxis[1];
239  m_afTuple[3] = fSin*rkAxis[2];
240 
241  return *this;
242 }
243 
244 template <class Real>
246  const
247 {
248  // The quaternion representing the rotation is
249  // q = cos(A/2)+sin(A/2)*(x*i+y*j+z*k)
250 
251  Real fSqrLength = m_afTuple[1]*m_afTuple[1] + m_afTuple[2]*m_afTuple[2]
252  + m_afTuple[3]*m_afTuple[3];
253 
254  if (fSqrLength > moMath<Real>::ZERO_TOLERANCE)
255  {
256  rfAngle = ((Real)2.0)*moMath<Real>::ACos(m_afTuple[0]);
257  Real fInvLength = moMath<Real>::InvSqrt(fSqrLength);
258  rkAxis[0] = m_afTuple[1]*fInvLength;
259  rkAxis[1] = m_afTuple[2]*fInvLength;
260  rkAxis[2] = m_afTuple[3]*fInvLength;
261  }
262  else
263  {
264  // angle is 0 (mod 2*pi), so any axis will do
265  rfAngle = (Real)0.0;
266  rkAxis[0] = (Real)1.0;
267  rkAxis[1] = (Real)0.0;
268  rkAxis[2] = (Real)0.0;
269  }
270 }
271 
272 template <class Real>
274 {
275  moQuaternion kInverse;
276 
277  Real fNorm = (Real)0.0;
278  int i;
279  for (i = 0; i < 4; i++)
280  {
281  fNorm += m_afTuple[i]*m_afTuple[i];
282  }
283 
284  if (fNorm > (Real)0.0)
285  {
286  Real fInvNorm = ((Real)1.0)/fNorm;
287  kInverse.m_afTuple[0] = m_afTuple[0]*fInvNorm;
288  kInverse.m_afTuple[1] = -m_afTuple[1]*fInvNorm;
289  kInverse.m_afTuple[2] = -m_afTuple[2]*fInvNorm;
290  kInverse.m_afTuple[3] = -m_afTuple[3]*fInvNorm;
291  }
292  else
293  {
294  // return an invalid result to flag the error
295  for (i = 0; i < 4; i++)
296  {
297  kInverse.m_afTuple[i] = (Real)0.0;
298  }
299  }
300 
301  return kInverse;
302 }
303 
304 template <class Real>
306 {
307  return moQuaternion(m_afTuple[0],-m_afTuple[1],-m_afTuple[2],
308  -m_afTuple[3]);
309 }
310 
311 template <class Real>
313 {
314  // If q = A*(x*i+y*j+z*k) where (x,y,z) is unit length, then
315  // exp(q) = cos(A)+sin(A)*(x*i+y*j+z*k). If sin(A) is near zero,
316  // use exp(q) = cos(A)+A*(x*i+y*j+z*k) since A/sin(A) has limit 1.
317 
318  moQuaternion kResult;
319 
320  Real fAngle = moMath<Real>::Sqrt(m_afTuple[1]*m_afTuple[1] +
321  m_afTuple[2]*m_afTuple[2] + m_afTuple[3]*m_afTuple[3]);
322 
323  Real fSin = moMath<Real>::Sin(fAngle);
324  kResult.m_afTuple[0] = moMath<Real>::Cos(fAngle);
325 
326  int i;
327 
329  {
330  Real fCoeff = fSin/fAngle;
331  for (i = 1; i <= 3; i++)
332  {
333  kResult.m_afTuple[i] = fCoeff*m_afTuple[i];
334  }
335  }
336  else
337  {
338  for (i = 1; i <= 3; i++)
339  {
340  kResult.m_afTuple[i] = m_afTuple[i];
341  }
342  }
343 
344  return kResult;
345 }
346 
347 template <class Real>
349 {
350  // If q = cos(A)+sin(A)*(x*i+y*j+z*k) where (x,y,z) is unit length, then
351  // log(q) = A*(x*i+y*j+z*k). If sin(A) is near zero, use log(q) =
352  // sin(A)*(x*i+y*j+z*k) since sin(A)/A has limit 1.
353 
354  moQuaternion kResult;
355  kResult.m_afTuple[0] = (Real)0.0;
356 
357  int i;
358 
359  if (moMath<Real>::FAbs(m_afTuple[0]) < (Real)1.0)
360  {
361  Real fAngle = moMath<Real>::ACos(m_afTuple[0]);
362  Real fSin = moMath<Real>::Sin(fAngle);
364  {
365  Real fCoeff = fAngle/fSin;
366  for (i = 1; i <= 3; i++)
367  {
368  kResult.m_afTuple[i] = fCoeff*m_afTuple[i];
369  }
370  return kResult;
371  }
372  }
373 
374  for (i = 1; i <= 3; i++)
375  {
376  kResult.m_afTuple[i] = m_afTuple[i];
377  }
378  return kResult;
379 }
380 
381 template <class Real>
383  const
384 {
385  // Given a vector u = (x0,y0,z0) and a unit length quaternion
386  // q = <w,x,y,z>, the vector v = (x1,y1,z1) which represents the
387  // rotation of u by q is v = q*u*q^{-1} where * indicates quaternion
388  // multiplication and where u is treated as the quaternion <0,x0,y0,z0>.
389  // Note that q^{-1} = <w,-x,-y,-z>, so no real work is required to
390  // invert q. Now
391  //
392  // q*u*q^{-1} = q*<0,x0,y0,z0>*q^{-1}
393  // = q*(x0*i+y0*j+z0*k)*q^{-1}
394  // = x0*(q*i*q^{-1})+y0*(q*j*q^{-1})+z0*(q*k*q^{-1})
395  //
396  // As 3-vectors, q*i*q^{-1}, q*j*q^{-1}, and 2*k*q^{-1} are the columns
397  // of the rotation matrix computed in moQuaternion<Real>::ToRotationMatrix.
398  // The vector v is obtained as the product of that rotation matrix with
399  // vector u. As such, the quaternion representation of a rotation
400  // matrix requires less space than the matrix and more time to compute
401  // the rotated vector. Typical space-time tradeoff...
402 
403  moMatrix3<Real> kRot;
404  ToRotationMatrix(kRot);
405  return kRot*rkVector;
406 }
407 
408 template <class Real>
410  const moQuaternion& rkQ)
411 {
412  Real fCos = rkP.Dot(rkQ);
413  Real fAngle = moMath<Real>::ACos(fCos);
414 
416  {
417  Real fSin = moMath<Real>::Sin(fAngle);
418  Real fInvSin = ((Real)1.0)/fSin;
419  Real fCoeff0 = moMath<Real>::Sin(((Real)1.0-fT)*fAngle)*fInvSin;
420  Real fCoeff1 = moMath<Real>::Sin(fT*fAngle)*fInvSin;
421  *this = fCoeff0*rkP + fCoeff1*rkQ;
422  }
423  else
424  {
425  *this = rkP;
426  }
427 
428  return *this;
429 }
430 
431 template <class Real>
433  const moQuaternion& rkP, const moQuaternion& rkQ, int iExtraSpins)
434 {
435  Real fCos = rkP.Dot(rkQ);
436  Real fAngle = moMath<Real>::ACos(fCos);
437 
439  {
440  Real fSin = moMath<Real>::Sin(fAngle);
441  Real fPhase = moMath<Real>::PI*iExtraSpins*fT;
442  Real fInvSin = ((Real)1.0)/fSin;
443  Real fCoeff0 = moMath<Real>::Sin(((Real)1.0-fT)*fAngle-fPhase)*fInvSin;
444  Real fCoeff1 = moMath<Real>::Sin(fT*fAngle + fPhase)*fInvSin;
445  *this = fCoeff0*rkP + fCoeff1*rkQ;
446  }
447  else
448  {
449  *this = rkP;
450  }
451 
452  return *this;
453 }
454 
455 template <class Real>
457  const moQuaternion& rkQ1, const moQuaternion& rkQ2)
458 {
459  // assert: Q0, Q1, Q2 all unit-length
460  moQuaternion kQ1Inv = rkQ1.Conjugate();
461  moQuaternion kP0 = kQ1Inv*rkQ0;
462  moQuaternion kP2 = kQ1Inv*rkQ2;
463  moQuaternion kArg = -((Real)0.25)*(kP0.Log()+kP2.Log());
464  moQuaternion kA = rkQ1*kArg.Exp();
465  *this = kA;
466 
467  return *this;
468 }
469 
470 template <class Real>
472  const moQuaternion& rkA0, const moQuaternion& rkA1, const moQuaternion& rkQ1)
473 {
474  Real fSlerpT = ((Real)2.0)*fT*((Real)1.0-fT);
475  moQuaternion kSlerpP = Slerp(fT,rkQ0,rkQ1);
476  moQuaternion kSlerpQ = Slerp(fT,rkA0,rkA1);
477  return Slerp(fSlerpT,kSlerpP,kSlerpQ);
478 }
479 
480 template <class Real>
482  const moVector3<Real>& rkV2)
483 {
484  // If V1 and V2 are not parallel, the axis of rotation is the unit-length
485  // vector U = Cross(V1,V2)/Length(Cross(V1,V2)). The angle of rotation,
486  // A, is the angle between V1 and V2. The quaternion for the rotation is
487  // q = cos(A/2) + sin(A/2)*(ux*i+uy*j+uz*k) where U = (ux,uy,uz).
488  //
489  // (1) Rather than extract A = acos(Dot(V1,V2)), multiply by 1/2, then
490  // compute sin(A/2) and cos(A/2), we reduce the computational costs by
491  // computing the bisector B = (V1+V2)/Length(V1+V2), so cos(A/2) =
492  // Dot(V1,B).
493  //
494  // (2) The rotation axis is U = Cross(V1,B)/Length(Cross(V1,B)), but
495  // Length(Cross(V1,B)) = Length(V1)*Length(B)*sin(A/2) = sin(A/2), in
496  // which case sin(A/2)*(ux*i+uy*j+uz*k) = (cx*i+cy*j+cz*k) where
497  // C = Cross(V1,B).
498  //
499  // If V1 = V2, then B = V1, cos(A/2) = 1, and U = (0,0,0). If V1 = -V2,
500  // then B = 0. This can happen even if V1 is approximately -V2 using
501  // floating point arithmetic, since moVector3::Normalize checks for
502  // closeness to zero and returns the zero vector accordingly. The test
503  // for exactly zero is usually not recommend for floating point
504  // arithmetic, but the implementation of moVector3::Normalize guarantees
505  // the comparison is robust. In this case, the A = pi and any axis
506  // perpendicular to V1 may be used as the rotation axis.
507 
508  moVector3<Real> kBisector = rkV1 + rkV2;
509  kBisector.Normalize();
510 
511  Real fCosHalfAngle = rkV1.Dot(kBisector);
512  moVector3<Real> kCross;
513 
514  m_afTuple[0] = fCosHalfAngle;
515 
516  if (fCosHalfAngle != (Real)0.0)
517  {
518  kCross = rkV1.Cross(kBisector);
519  m_afTuple[1] = kCross.X();
520  m_afTuple[2] = kCross.Y();
521  m_afTuple[3] = kCross.Z();
522  }
523  else
524  {
525  Real fInvLength;
526  if (moMath<Real>::FAbs(rkV1[0]) >= moMath<Real>::FAbs(rkV1[1]))
527  {
528  // V1.x or V1.z is the largest magnitude component
529  fInvLength = moMath<Real>::InvSqrt(rkV1[0]*rkV1[0] +
530  rkV1[2]*rkV1[2]);
531 
532  m_afTuple[1] = -rkV1[2]*fInvLength;
533  m_afTuple[2] = (Real)0.0;
534  m_afTuple[3] = +rkV1[0]*fInvLength;
535  }
536  else
537  {
538  // V1.y or V1.z is the largest magnitude component
539  fInvLength = moMath<Real>::InvSqrt(rkV1[1]*rkV1[1] +
540  rkV1[2]*rkV1[2]);
541 
542  m_afTuple[1] = (Real)0.0;
543  m_afTuple[2] = +rkV1[2]*fInvLength;
544  m_afTuple[3] = -rkV1[1]*fInvLength;
545  }
546  }
547 
548  return *this;
549 }
550 
551 template <class Real>
553  const moVector3<Real>& rkV1, moQuaternion& rkTwist, moQuaternion& rkSwing)
554 {
555  moVector3<Real> kV2 = Rotate(rkV1);
556  rkSwing = Align(rkV1,kV2);
557  rkTwist = (*this)*rkSwing.Conjugate();
558 }
559 
560 template <class Real>
562  const moVector3<Real>& rkV1, moQuaternion& rkSwing, moQuaternion& rkTwist)
563 {
564  moVector3<Real> kV2 = Rotate(rkV1);
565  rkSwing = Align(rkV1,kV2);
566  rkTwist = rkSwing.Conjugate()*(*this);
567 }
568 
569 template<> const moQuaternion<MOfloat>
570  moQuaternion<MOfloat>::IDENTITY(1.0f,0.0f,0.0f,0.0f);
571 template<> const moQuaternion<MOfloat>
572  moQuaternion<MOfloat>::ZERO(0.0f,0.0f,0.0f,0.0f);
573 template<> int moQuaternion<MOfloat>::ms_iNext[3] = { 1, 2, 0 };
574 
575 template<> const moQuaternion<MOdouble>
576  moQuaternion<MOdouble>::IDENTITY(1.0,0.0,0.0,0.0);
577 template<> const moQuaternion<MOdouble>
578  moQuaternion<MOdouble>::ZERO(0.0,0.0,0.0,0.0);
579 template<> int moQuaternion<MOdouble>::ms_iNext[3] = { 1, 2, 0 };
580 
bool operator>(const moQuaternion &rkQ) const
moMatrix3< Real > & FromAxisAngle(const moVector3< Real > &rkAxis, Real fAngle)
Definition: moMathMatrix.h:849
moQuaternion & Slerp(Real fT, const moQuaternion &rkP, const moQuaternion &rkQ)
moQuaternion & FromAxisAngle(const moVector3< Real > &rkAxis, Real fAngle)
static const moQuaternion IDENTITY
moQuaternion & Intermediate(const moQuaternion &rkQ0, const moQuaternion &rkQ1, const moQuaternion &rkQ2)
moQuaternion & SlerpExtraSpins(Real fT, const moQuaternion &rkP, const moQuaternion &rkQ, int iExtraSpins)
static Real ACos(Real fValue)
Definition: moMath.h:81
moQuaternion Conjugate() const
static Real Sin(Real fValue)
Definition: moMath.h:260
void ToAxisAngle(moVector3< Real > &rkAxis, Real &rfAngle) const
Real Z() const
Definition: moMathVector3.h:77
Clase base abstracta de donde deben derivar los objetos [virtual pura].
Definition: moAbstract.h:191
Real X() const
Definition: moMathVector3.h:73
bool operator!=(const moQuaternion &rkQ) const
moQuaternion & FromRotationMatrix(const moMatrix3< Real > &rkRot)
moQuaternion Log() const
void ToRotationMatrix(moMatrix3< Real > &rkRot) const
static Real InvSqrt(Real fValue)
Definition: moMath.h:210
bool operator>=(const moQuaternion &rkQ) const
static Real Sqrt(Real fValue)
Definition: moMath.h:279
Real Dot(const moVector3 &rkV) const
void DecomposeTwistTimesSwing(const moVector3< Real > &rkV1, moQuaternion &rkTwist, moQuaternion &rkSwing)
moMatrix3< Real > & Slerp(Real fT, const moMatrix3 &rkR0, const moMatrix3 &rkR1)
bool operator<=(const moQuaternion &rkQ) const
Real Normalize()
moQuaternion & Squad(Real fT, const moQuaternion &rkQ0, const moQuaternion &rkA0, const moQuaternion &rkA1, const moQuaternion &rkQ1)
static const moQuaternion ZERO
moQuaternion & Align(const moVector3< Real > &rkV1, const moVector3< Real > &rkV2)
static Real Cos(Real fValue)
Definition: moMath.h:160
bool operator==(const moQuaternion &rkQ) const
moVector3 Cross(const moVector3 &rkV) const
Real Y() const
Definition: moMathVector3.h:75
moQuaternion Exp() const
bool operator<(const moQuaternion &rkQ) const
moQuaternion Inverse() const
Definition: moMath.h:64
Real Dot(const moQuaternion &rkQ) const
moVector3< Real > Rotate(const moVector3< Real > &rkVector) const
void DecomposeSwingTimesTwist(const moVector3< Real > &rkV1, moQuaternion &rkSwing, moQuaternion &rkTwist)