libmoldeo (Moldeo 1.0 Core)  1.0
libmoldeo es el conjunto de objetos y funciones, que permiten ejecutar las operaciones básicas de la plataforma Moldeo, y que compone su núcleo.
moMathQuaternion.cpp
Ir a la documentación de este archivo.
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 
moQuaternion Exp() const
moQuaternion & Slerp(Real fT, const moQuaternion &rkP, const moQuaternion &rkQ)
void ToAxisAngle(moVector3< Real > &rkAxis, Real &rfAngle) const
moQuaternion & FromAxisAngle(const moVector3< Real > &rkAxis, Real fAngle)
static const moQuaternion IDENTITY
bool operator>(const moQuaternion &rkQ) const
moQuaternion & Intermediate(const moQuaternion &rkQ0, const moQuaternion &rkQ1, const moQuaternion &rkQ2)
Real Dot(const moQuaternion &rkQ) const
moQuaternion & SlerpExtraSpins(Real fT, const moQuaternion &rkP, const moQuaternion &rkQ, int iExtraSpins)
static Real ACos(Real fValue)
Definition: moMath.h:81
bool operator>=(const moQuaternion &rkQ) const
bool operator<(const moQuaternion &rkQ) const
moVector3< Real > Rotate(const moVector3< Real > &rkVector) const
static Real Sin(Real fValue)
Definition: moMath.h:260
Clase base abstracta de donde deben derivar los objetos [virtual pura].
Definition: moAbstract.h:191
bool operator==(const moQuaternion &rkQ) const
moQuaternion & FromRotationMatrix(const moMatrix3< Real > &rkRot)
int CompareArrays(const moQuaternion &rkQ) const
moVector3 Cross(const moVector3 &rkV) const
static Real InvSqrt(Real fValue)
Definition: moMath.h:210
moQuaternion Conjugate() const
bool operator<=(const moQuaternion &rkQ) const
moQuaternion Inverse() const
static Real Sqrt(Real fValue)
Definition: moMath.h:279
Real Z() const
Definition: moMathVector3.h:77
void DecomposeTwistTimesSwing(const moVector3< Real > &rkV1, moQuaternion &rkTwist, moQuaternion &rkSwing)
Real Normalize()
moQuaternion & Squad(Real fT, const moQuaternion &rkQ0, const moQuaternion &rkA0, const moQuaternion &rkA1, const moQuaternion &rkQ1)
Real Dot(const moVector3 &rkV) const
Real Y() const
Definition: moMathVector3.h:75
static const moQuaternion ZERO
moQuaternion & Align(const moVector3< Real > &rkV1, const moVector3< Real > &rkV2)
static Real Cos(Real fValue)
Definition: moMath.h:160
moQuaternion Log() const
Real X() const
Definition: moMathVector3.h:73
Definition: moMath.h:64
bool operator!=(const moQuaternion &rkQ) const
void DecomposeSwingTimesTwist(const moVector3< Real > &rkV1, moQuaternion &rkSwing, moQuaternion &rkTwist)
void ToRotationMatrix(moMatrix3< Real > &rkRot) const