Logo ROOT   6.08/07
Reference Guide
TQuaternion.cxx
Go to the documentation of this file.
1 // @(#)root/physics:$Id$
2 // Author: Eric Anciant 28/06/2005
3 
4 
5 /** \class TQuaternion
6  \ingroup Physics
7  Quaternion is a 4-component mathematic object quite convenient when dealing with
8 space rotation (or reference frame transformation).
9 
10  In short, think of quaternion Q as a 3-vector augmented by a real number.
11  \f$ Q = Q|_r + Q|_V \f$
12 
13  #### Quaternion multiplication :
14 
15  Quaternion multiplication is given by :
16  \f[
17  Q.Q' = (Q|_r + Q|_V )*( Q'|_r + Q'|_V) = [ Q|_r*Q'|_r - Q|_V*Q'|_V ] + [ Q|_r*Q'|_V + Q'|_r*Q|_V + Q|_V X Q'|_V ]
18 \f]
19 
20  where :
21  - \f$ Q|_r*Q'|_r \f$ is a real number product of real numbers
22  - \f$ Q|_V*Q'|_V \f$ is a real number, scalar product of two 3-vectors
23  - \f$ Q|_r*Q'|_V \f$ is a 3-vector, scaling of a 3-vector by a real number
24  - \f$ Q|_VXQ'|_V \f$ is a 3-vector, cross product of two 3-vectors
25 
26 Thus, quaternion product is a generalization of real number product and product of a
27 vector by a real number. Product of two pure vectors gives a quaternion whose real part
28 is the opposite of scalar product and the vector part the cross product.
29 
30 The conjugate of a quaternion \f$ Q = Q|r + Q|V \f$ is \f$ \bar{Q} = Q|r - Q|V \f$
31 
32 The magnitude of a quaternion \f$ Q \f$ is given by \f$ |Q|^2 = Q.\bar{Q} = \bar{Q}.Q = Q^2|r + |Q|V|^2 \f$
33 
34 Therefore, the inverse of a quaternion is \f$ Q-1 = \bar{Q} /|Q|^2 \f$
35 
36 "unit" quaternion is a quaternion of magnitude 1 : \f$ |Q|^2 = 1. \f$
37 Unit quaternions are a subset of the quaternions set.
38 
39  #### Quaternion and rotations :
40 
41 
42  A rotation of angle \f$ f \f$ around a given axis, is represented by a unit quaternion Q :
43  - The axis of the rotation is given by the vector part of Q.
44  - The ratio between the magnitude of the vector part and the real part of Q equals tan(\frac{f}{2}).
45 
46  In other words : \f$ Q = Q|_r + Q|_V = cos(\frac{f}{2}) + sin(\frac{f}{2}) \f$.
47  (where u is a unit vector // to the rotation axis,
48 \f$ cos(\frac{f}{2}) \f$ is the real part, \f$ sin(\frac{f}{2}) \f$ .u is the vector part)
49  Note : The quaternion of identity is \f$ Q_I = cos(0) + sin(0)*(AnyVector) = 1\f$ .
50 
51  The composition of two rotations is described by the product of the two corresponding quaternions.
52  As for 3-space rotations, quaternion multiplication is not commutative !
53 
54  \f$ Q = Q_1.Q_2 \f$ represents the composition of the successive rotation R1 and R2 expressed in the current frame (the axis of rotation hold by \f$ Q_2 \f$ is expressed in the frame as it is after R1 rotation).
55  \f$ Q = Q_2.Q_1 \f$ represents the composition of the successive rotation R1 and R2 expressed in the initial reference frame.
56 
57  The inverse of a rotation is a rotation about the same axis but of opposite angle, thus if Q is a unit quaternion,
58  \f$ Q = cos(\frac{f}{2}) + sin(\frac{f}{2}).u = Q|_r + Q|_V\f$ , then :
59  \f$ Q^{-1} =cos(-\frac{f}{2}) + sin(-\frac{f}{2}).u = cos(\frac{f}{2}) - sin(\frac{f}{2}).u = Q|_r -Q|_V \f$ is its inverse quaternion.
60 
61  One verifies that :
62  \f$ Q.Q^{-1} = Q^{-1}.Q = Q|_r*Q|_r + Q|_V*Q|_V + Q|_r*Q|_V -Q|_r*Q|_V + Q|_VXQ|_V = Q\leq|_r + Q\leq|_V = 1 \f$
63 
64 
65  The rotation of a vector V by the rotation described by a unit quaternion Q is obtained by the following operation :
66  \f$ V' = Q*V*Q^{-1} \f$, considering V as a quaternion whose real part is null.
67 
68  #### Numeric computation considerations :
69 
70  Numerically, the quaternion multiplication involves 12 additions and 16 multiplications.
71  It is therefore faster than 3x3 matrixes multiplication involving 18 additions and 27 multiplications.
72 
73  On the contrary, rotation of a vector by the above formula ( \f$ Q*V*Q^{-1} \f$ ) involves 18 additions
74  and 24 multiplications, whereas multiplication of a 3-vector by a 3x3 matrix involves only 6 additions
75  and 9 multiplications.
76 
77  When dealing with numerous composition of space rotation, it is therefore faster to use quaternion product. On the other hand if a huge set of vectors must be rotated by a given quaternion, it is more optimized to convert the quaternion into a rotation matrix once, and then use that later to rotate the set of vectors.
78 
79  #### More information :
80 
81 http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
82 
83 http://en.wikipedia.org/wiki/Quaternion
84 
85  This Class represents all quaternions (unit or non-unit)
86  It possesses a Normalize() method to make a given quaternion unit
87  The Rotate(TVector3&) and Rotation(TVector3&) methods can be used even for a non-unit quaternion, in that case, the proper normalization is applied to perform the rotation.
88 
89  A TRotation constructor exists than takes a quaternion for parameter (even non-unit), in that cas the proper normalisation is applied.
90 */
91 
92 #include "TMath.h"
93 #include "TQuaternion.h"
94 
96 
97 /****************** CONSTRUCTORS ****************************************************/
98 ////////////////////////////////////////////////////////////////////////////////
99 
101  fRealPart(q.fRealPart), fVectorPart(q.fVectorPart) {}
102 
104  : fRealPart(real), fVectorPart(vect) {}
105 
107  : fRealPart(x0[3]), fVectorPart(x0) {}
108 
110  : fRealPart(x0[3]), fVectorPart(x0) {}
111 
113  : fRealPart(real), fVectorPart(X,Y,Z) {}
114 
116 
117 ////////////////////////////////////////////////////////////////////////////////
118 ///dereferencing operator const
119 
121  switch(i) {
122  case 0:
123  case 1:
124  case 2:
125  return fVectorPart(i);
126  case 3:
127  return fRealPart;
128  default:
129  Error("operator()(i)", "bad index (%d) returning 0",i);
130  }
131  return 0.;
132 }
133 
134 ////////////////////////////////////////////////////////////////////////////////
135 ///dereferencing operator
136 
138  switch(i) {
139  case 0:
140  case 1:
141  case 2:
142  return fVectorPart(i);
143  case 3:
144  return fRealPart;
145  default:
146  Error("operator()(i)", "bad index (%d) returning &fRealPart",i);
147  }
148  return fRealPart;
149 }
150 ////////////////////////////////////////////////////////////////////////////////
151 /// Get angle of quaternion (rad)
152 /// N.B : this angle is half of the corresponding rotation angle
153 
155  if (fRealPart == 0) return TMath::PiOver2();
156  Double_t denominator = fVectorPart.Mag();
157  return atan(denominator/fRealPart);
158 }
159 
160 ////////////////////////////////////////////////////////////////////////////////
161 /// Set angle of quaternion (rad) - keep quaternion norm
162 /// N.B : this angle is half of the corresponding rotation angle
163 
165  Double_t norm = Norm();
166  Double_t normSinV = fVectorPart.Mag();
167  if (normSinV != 0) fVectorPart *= (sin(angle)*norm/normSinV);
168  fRealPart = cos(angle)*norm;
169 
170  return (*this);
171 }
172 
173 ////////////////////////////////////////////////////////////////////////////////
174 /// set quaternion from vector and angle (rad)
175 /// quaternion is set as unitary
176 /// N.B : this angle is half of the corresponding rotation angle
177 
179  fVectorPart = v;
180  double norm = v.Mag();
181  if (norm>0) fVectorPart*=(1./norm);
182  fVectorPart*=sin(QAngle);
183  fRealPart = cos(QAngle);
184 
185  return (*this);
186 }
187 
188 /**************** REAL TO QUATERNION ALGEBRA ****************************************/
189 
190 ////////////////////////////////////////////////////////////////////////////////
191 /// sum of quaternion with a real
192 
194  return TQuaternion(fVectorPart, fRealPart + real);
195 }
196 
197 ////////////////////////////////////////////////////////////////////////////////
198 /// substraction of real to quaternion
199 
201  return TQuaternion(fVectorPart, fRealPart - real);
202 }
203 
204 ////////////////////////////////////////////////////////////////////////////////
205 /// product of quaternion with a real
206 
208  return TQuaternion(fRealPart*real,fVectorPart.x()*real,fVectorPart.y()*real,fVectorPart.z()*real);
209 }
210 
211 
212 ////////////////////////////////////////////////////////////////////////////////
213 /// division by a real
214 
216  if (real !=0 ) {
217  return TQuaternion(fRealPart/real,fVectorPart.x()/real,fVectorPart.y()/real,fVectorPart.z()/real);
218  } else {
219  Error("operator/(Double_t)", "bad value (%f) ignored",real);
220  }
221 
222  return (*this);
223 }
224 
225 TQuaternion operator + (Double_t r, const TQuaternion & q) { return (q+r); }
226 TQuaternion operator - (Double_t r, const TQuaternion & q) { return (-q+r); }
227 TQuaternion operator * (Double_t r, const TQuaternion & q) { return (q*r); }
228 TQuaternion operator / (Double_t r, const TQuaternion & q) { return (q.Invert()*r); }
229 
230 /**************** VECTOR TO QUATERNION ALGEBRA ****************************************/
231 
232 ////////////////////////////////////////////////////////////////////////////////
233 /// sum of quaternion with a real
234 
236  return TQuaternion(fVectorPart + vect, fRealPart);
237 }
238 
239 ////////////////////////////////////////////////////////////////////////////////
240 /// substraction of real to quaternion
241 
243  return TQuaternion(fVectorPart - vect, fRealPart);
244 }
245 
246 ////////////////////////////////////////////////////////////////////////////////
247 /// left multiplication
248 
250  Double_t savedRealPart = fRealPart;
251  fRealPart = - (fVectorPart * vect);
252  fVectorPart = vect.Cross(fVectorPart);
253  fVectorPart += (vect * savedRealPart);
254 
255  return (*this);
256 }
257 
258 ////////////////////////////////////////////////////////////////////////////////
259 /// right multiplication
260 
262  Double_t savedRealPart = fRealPart;
263  fRealPart = -(fVectorPart * vect);
264  fVectorPart = fVectorPart.Cross(vect);
265  fVectorPart += (vect * savedRealPart );
266 
267  return (*this);
268 }
269 
270 ////////////////////////////////////////////////////////////////////////////////
271 /// left product
272 
274  return TQuaternion(vect * fRealPart + vect.Cross(fVectorPart), -(fVectorPart * vect));
275 }
276 
277 ////////////////////////////////////////////////////////////////////////////////
278 /// right product
279 
281  return TQuaternion(vect * fRealPart + fVectorPart.Cross(vect), -(fVectorPart * vect));
282 }
283 
284 ////////////////////////////////////////////////////////////////////////////////
285 /// left division
286 
288  Double_t norm2 = vect.Mag2();
289  MultiplyLeft(vect);
290  if (norm2 > 0 ) {
291  // use (1./nom2) to be numerically compliant with LeftQuotient(const TVector3 &)
292  (*this) *= -(1./norm2); // minus <- using conjugate of vect
293  } else {
294  Error("DivideLeft(const TVector3)", "bad norm2 (%f) ignored",norm2);
295  }
296  return (*this);
297 }
298 
299 ////////////////////////////////////////////////////////////////////////////////
300 /// right division
301 
303  Double_t norm2 = vect.Mag2();
304  (*this) *= vect;
305  if (norm2 > 0 ) {
306  // use (1./real) to be numerically compliant with operator/(const TVector3 &)
307  (*this) *= - (1./norm2); // minus <- using conjugate of vect
308  } else {
309  Error("operator/=(const TVector3 &)", "bad norm2 (%f) ignored",norm2);
310  }
311  return (*this);
312 }
313 
314 ////////////////////////////////////////////////////////////////////////////////
315 /// left quotient
316 
318  Double_t norm2 = vect.Mag2();
319 
320  if (norm2>0) {
321  double invNorm2 = 1./norm2;
322  return TQuaternion((vect * -fRealPart - vect.Cross(fVectorPart))*invNorm2,
323  (fVectorPart * vect ) * invNorm2 );
324  } else {
325  Error("LeftQuotient(const TVector3 &)", "bad norm2 (%f) ignored",norm2);
326  }
327  return (*this);
328 }
329 
330 ////////////////////////////////////////////////////////////////////////////////
331 /// right quotient
332 
334  Double_t norm2 = vect.Mag2();
335 
336  if (norm2>0) {
337  double invNorm2 = 1./norm2;
338  return TQuaternion((vect * -fRealPart - fVectorPart.Cross(vect)) * invNorm2,
339  (fVectorPart * vect) * invNorm2 );
340  } else {
341  Error("operator/(const TVector3 &)", "bad norm2 (%f) ignored",norm2);
342  }
343  return (*this);
344 }
345 
346 TQuaternion operator + (const TVector3 &V, const TQuaternion &Q) { return (Q+V); }
347 TQuaternion operator - (const TVector3 &V, const TQuaternion &Q) { return (-Q+V); }
348 TQuaternion operator * (const TVector3 &V, const TQuaternion &Q) { return Q.LeftProduct(V); }
349 
350 TQuaternion operator / (const TVector3 &vect, const TQuaternion &quat) {
351  //divide operator
352  TQuaternion res(vect);
353  res /= quat;
354  return res;
355 }
356 
357 /**************** QUATERNION ALGEBRA ****************************************/
358 
359 ////////////////////////////////////////////////////////////////////////////////
360 /// right multiplication
361 
363  Double_t saveRP = fRealPart;
364  TVector3 cross(fVectorPart.Cross(quaternion.fVectorPart));
365 
366  fRealPart = fRealPart * quaternion.fRealPart - fVectorPart * quaternion.fVectorPart;
367 
368  fVectorPart *= quaternion.fRealPart;
369  fVectorPart += quaternion.fVectorPart * saveRP;
370  fVectorPart += cross;
371  return (*this);
372 }
373 
374 ////////////////////////////////////////////////////////////////////////////////
375 /// left multiplication
376 
378  Double_t saveRP = fRealPart;
379  TVector3 cross(quaternion.fVectorPart.Cross(fVectorPart));
380 
381  fRealPart = fRealPart * quaternion.fRealPart - fVectorPart * quaternion.fVectorPart;
382 
383  fVectorPart *= quaternion.fRealPart;
384  fVectorPart += quaternion.fVectorPart * saveRP;
385  fVectorPart += cross;
386 
387  return (*this);
388 }
389 
390 ////////////////////////////////////////////////////////////////////////////////
391 /// left product
392 
394  return TQuaternion( fVectorPart*quaternion.fRealPart + quaternion.fVectorPart*fRealPart
395  + quaternion.fVectorPart.Cross(fVectorPart),
396  fRealPart*quaternion.fRealPart - fVectorPart*quaternion.fVectorPart );
397 }
398 
399 ////////////////////////////////////////////////////////////////////////////////
400 /// right product
401 
403  return TQuaternion(fVectorPart*quaternion.fRealPart + quaternion.fVectorPart*fRealPart
404  + fVectorPart.Cross(quaternion.fVectorPart),
405  fRealPart*quaternion.fRealPart - fVectorPart*quaternion.fVectorPart );
406 }
407 
408 ////////////////////////////////////////////////////////////////////////////////
409 /// left division
410 
412  Double_t norm2 = quaternion.Norm2();
413 
414  if (norm2 > 0 ) {
415  MultiplyLeft(quaternion.Conjugate());
416  (*this) *= (1./norm2);
417  } else {
418  Error("DivideLeft(const TQuaternion &)", "bad norm2 (%f) ignored",norm2);
419  }
420  return (*this);
421 }
422 
423 ////////////////////////////////////////////////////////////////////////////////
424 /// right division
425 
427  Double_t norm2 = quaternion.Norm2();
428 
429  if (norm2 > 0 ) {
430  (*this) *= quaternion.Conjugate();
431  // use (1./norm2) top be numerically compliant with operator/(const TQuaternion&)
432  (*this) *= (1./norm2);
433  } else {
434  Error("operator/=(const TQuaternion&)", "bad norm2 (%f) ignored",norm2);
435  }
436  return (*this);
437 }
438 
439 ////////////////////////////////////////////////////////////////////////////////
440 /// left quotient
441 
443  Double_t norm2 = quaternion.Norm2();
444 
445  if (norm2 > 0 ) {
446  double invNorm2 = 1./norm2;
447  return TQuaternion(
448  (fVectorPart*quaternion.fRealPart - quaternion.fVectorPart*fRealPart
449  - quaternion.fVectorPart.Cross(fVectorPart)) * invNorm2,
450  (fRealPart*quaternion.fRealPart + fVectorPart*quaternion.fVectorPart)*invNorm2 );
451  } else {
452  Error("LeftQuotient(const TQuaternion&)", "bad norm2 (%f) ignored",norm2);
453  }
454  return (*this);
455 }
456 
457 ////////////////////////////////////////////////////////////////////////////////
458 /// right quotient
459 
461  Double_t norm2 = quaternion.Norm2();
462 
463  if (norm2 > 0 ) {
464  double invNorm2 = 1./norm2;
465  return TQuaternion(
466  (fVectorPart*quaternion.fRealPart - quaternion.fVectorPart*fRealPart
467  - fVectorPart.Cross(quaternion.fVectorPart)) * invNorm2,
468  (fRealPart*quaternion.fRealPart + fVectorPart*quaternion.fVectorPart) * invNorm2 );
469  } else {
470  Error("operator/(const TQuaternion &)", "bad norm2 (%f) ignored",norm2);
471  }
472  return (*this);
473 }
474 
475 ////////////////////////////////////////////////////////////////////////////////
476 /// invert
477 
479  double norm2 = Norm2();
480  if (norm2 > 0 ) {
481  double invNorm2 = 1./norm2;
482  return TQuaternion(fVectorPart*(-invNorm2), fRealPart*invNorm2 );
483  } else {
484  Error("Invert()", "bad norm2 (%f) ignored",norm2);
485  }
486  return (*this);
487 }
488 
489 ////////////////////////////////////////////////////////////////////////////////
490 /// rotate vect by current quaternion
491 
492 void TQuaternion::Rotate(TVector3 & vect) const {
493  vect = Rotation(vect);
494 }
495 
496 ////////////////////////////////////////////////////////////////////////////////
497 /// rotation of vect by current quaternion
498 
500  // Vres = (*this) * vect * (this->Invert());
501  double norm2 = Norm2();
502 
503  if (norm2>0) {
504  TQuaternion quat(*this);
505  quat *= vect;
506 
507  // only compute vect part : (real part has to be 0 ) :
508  // VECT [ quat * ( this->Conjugate() ) ] = quat.fRealPart * -this->fVectorPart
509  // + this->fRealPart * quat.fVectorPart
510  // + quat.fVectorPart X (-this->fVectorPart)
511  TVector3 cross(fVectorPart.Cross(quat.fVectorPart));
512  quat.fVectorPart *= fRealPart;
513  quat.fVectorPart -= fVectorPart * quat.fRealPart;
514  quat.fVectorPart += cross;
515 
516  return quat.fVectorPart*(1./norm2);
517  } else {
518  Error("Rotation()", "bad norm2 (%f) ignored",norm2);
519  }
520  return vect;
521 }
522 
523 ////////////////////////////////////////////////////////////////////////////////
524 ///Print Quaternion parameters
525 
527 {
528  Printf("%s %s (r,x,y,z)=(%f,%f,%f,%f) \n (alpha,rho,theta,phi)=(%f,%f,%f,%f)",GetName(),GetTitle(),
531 }
Double_t X() const
Definition: TVector3.h:224
TQuaternion operator-() const
Definition: TQuaternion.h:283
float Float_t
Definition: RtypesCore.h:53
const char Option_t
Definition: RtypesCore.h:62
TVector3 fVectorPart
Definition: TQuaternion.h:115
Quaternion is a 4-component mathematic object quite convenient when dealing with space rotation (or r...
Definition: TQuaternion.h:15
Double_t RadToDeg()
Definition: TMath.h:49
Double_t Mag2() const
Definition: TVector3.h:347
TQuaternion & SetQAngle(Double_t angle)
Set angle of quaternion (rad) - keep quaternion norm N.B : this angle is half of the corresponding ro...
Double_t y() const
Definition: TVector3.h:222
void Rotate(TVector3 &vect) const
rotate vect by current quaternion
double cos(double)
Double_t Mag() const
Definition: TVector3.h:94
TQuaternion & operator/=(Double_t real)
Definition: TQuaternion.h:180
virtual ~TQuaternion()
Double_t Y() const
Definition: TVector3.h:225
TQuaternion & DivideLeft(const TVector3 &vector)
left division
double sin(double)
TVector3 is a general three vector class, which can be used for the description of different vectors ...
Definition: TVector3.h:30
TVector3 Cross(const TVector3 &) const
Definition: TVector3.h:343
Double_t Z() const
Definition: TVector3.h:226
TQuaternion & operator*=(Double_t real)
Definition: TQuaternion.h:174
TRandom2 r(17)
SVector< double, 2 > v
Definition: Dict.h:5
TQuaternion(Double_t real=0, Double_t X=0, Double_t Y=0, Double_t Z=0)
TQuaternion & SetAxisQAngle(TVector3 &v, Double_t QAngle)
set quaternion from vector and angle (rad) quaternion is set as unitary N.B : this angle is half of t...
Double_t Theta() const
Return the polar angle.
Definition: TVector3.cxx:238
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:925
void Print(Option_t *option="") const
Print Quaternion parameters.
TQuaternion operator*(Double_t real) const
product of quaternion with a real
Double_t Norm() const
Definition: TQuaternion.h:269
Double_t GetQAngle() const
Get angle of quaternion (rad) N.B : this angle is half of the corresponding rotation angle...
#define Printf
Definition: TGeoToOCC.h:18
Double_t z() const
Definition: TVector3.h:223
TQuaternion & MultiplyLeft(const TVector3 &vector)
left multiplication
TQuaternion Conjugate() const
Definition: TQuaternion.h:287
#define ClassImp(name)
Definition: Rtypes.h:279
TQuaternion operator/(Double_t real) const
division by a real
double Double_t
Definition: RtypesCore.h:55
TVector3 Rotation(const TVector3 &vect) const
rotation of vect by current quaternion
TQuaternion Invert() const
invert
TQuaternion LeftQuotient(const TVector3 &vector) const
left quotient
double atan(double)
TQuaternion operator+(Double_t real) const
sum of quaternion with a real
Mother of all ROOT objects.
Definition: TObject.h:37
virtual const char * GetTitle() const
Returns title of object.
Definition: TObject.cxx:460
Double_t PiOver2()
Definition: TMath.h:46
Double_t Phi() const
Return the azimuth angle. Returns phi from -pi to pi.
Definition: TVector3.cxx:230
Double_t x() const
Definition: TVector3.h:221
Double_t fRealPart
Definition: TQuaternion.h:114
Double_t operator()(int) const
dereferencing operator const
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:416
float * q
Definition: THbookFile.cxx:87
double norm(double *x, double *p)
Definition: unuranDistr.cxx:40
Double_t Norm2() const
Definition: TQuaternion.h:273
TQuaternion LeftProduct(const TVector3 &vector) const
left product
static double Q[]