Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
Quaternion.h
Go to the documentation of this file.
1 // @(#)root/mathcore:$Id$
2 // Authors: W. Brown, M. Fischler, L. Moneta 2005
3 
4  /**********************************************************************
5  * *
6  * Copyright (c) 2005 , LCG ROOT FNAL MathLib Team *
7  * *
8  * *
9  **********************************************************************/
10 
11 // Header file for rotation in 3 dimensions, represented by a quaternion
12 // Created by: Mark Fischler Thurs June 9 2005
13 //
14 // Last update: $Id$
15 //
16 #ifndef ROOT_Math_GenVector_Quaternion
17 #define ROOT_Math_GenVector_Quaternion 1
18 
19 
26 
27 #include <algorithm>
28 #include <cassert>
29 
30 
31 namespace ROOT {
32 namespace Math {
33 
34 
35 //__________________________________________________________________________________________
36  /**
37  Rotation class with the (3D) rotation represented by
38  a unit quaternion (u, i, j, k).
39  This is the optimal representation for multiplication of multiple
40  rotations, and for computation of group-manifold-invariant distance
41  between two rotations.
42  See also ROOT::Math::AxisAngle, ROOT::Math::EulerAngles, and ROOT::Math::Rotation3D.
43 
44  @ingroup GenVector
45  */
46 
47 class Quaternion {
48 
49 public:
50 
51  typedef double Scalar;
52 
53  // ========== Constructors and Assignment =====================
54 
55  /**
56  Default constructor (identity rotation)
57  */
58  Quaternion()
59  : fU(1.0)
60  , fI(0.0)
61  , fJ(0.0)
62  , fK(0.0)
63  { }
64 
65  /**
66  Construct given a pair of pointers or iterators defining the
67  beginning and end of an array of four Scalars
68  */
69  template<class IT>
70  Quaternion(IT begin, IT end) { SetComponents(begin,end); }
71 
72  // ======== Construction From other Rotation Forms ==================
73 
74  /**
75  Construct from another supported rotation type (see gv_detail::convert )
76  */
77  template <class OtherRotation>
78  explicit Quaternion(const OtherRotation & r) {gv_detail::convert(r,*this);}
79 
80 
81  /**
82  Construct from four Scalars representing the coefficients of u, i, j, k
83  */
84  Quaternion(Scalar u, Scalar i, Scalar j, Scalar k) :
85  fU(u), fI(i), fJ(j), fK(k) { }
86 
87  // The compiler-generated copy ctor, copy assignment, and dtor are OK.
88 
89  /**
90  Re-adjust components to eliminate small deviations from |Q| = 1
91  orthonormality.
92  */
93  void Rectify();
94 
95  /**
96  Assign from another supported rotation type (see gv_detail::convert )
97  */
98  template <class OtherRotation>
99  Quaternion & operator=( OtherRotation const & r ) {
100  gv_detail::convert(r,*this);
101  return *this;
102  }
103 
104  // ======== Components ==============
105 
106  /**
107  Set the four components given an iterator to the start of
108  the desired data, and another to the end (4 past start).
109  */
110  template<class IT>
111 #ifndef NDEBUG
112  void SetComponents(IT begin, IT end) {
113 #else
114  void SetComponents(IT begin, IT ) {
115 #endif
116  fU = *begin++;
117  fI = *begin++;
118  fJ = *begin++;
119  fK = *begin++;
120  assert (end==begin);
121  }
122 
123  /**
124  Get the components into data specified by an iterator begin
125  and another to the end of the desired data (4 past start).
126  */
127  template<class IT>
128 #ifndef NDEBUG
129  void GetComponents(IT begin, IT end) const {
130 #else
131  void GetComponents(IT begin, IT ) const {
132 #endif
133  *begin++ = fU;
134  *begin++ = fI;
135  *begin++ = fJ;
136  *begin++ = fK;
137  assert (end==begin);
138  }
139 
140  /**
141  Get the components into data specified by an iterator begin
142  */
143  template<class IT>
144  void GetComponents(IT begin ) const {
145  *begin++ = fU;
146  *begin++ = fI;
147  *begin++ = fJ;
148  *begin = fK;
149  }
150 
151  /**
152  Set the components based on four Scalars. The sum of the squares of
153  these Scalars should be 1; no checking is done.
154  */
155  void SetComponents(Scalar u, Scalar i, Scalar j, Scalar k) {
156  fU=u; fI=i; fJ=j; fK=k;
157  }
158 
159  /**
160  Get the components into four Scalars.
161  */
162  void GetComponents(Scalar & u, Scalar & i, Scalar & j, Scalar & k) const {
163  u=fU; i=fI; j=fJ; k=fK;
164  }
165 
166  /**
167  Access to the four quaternion components:
168  U() is the coefficient of the identity Pauli matrix,
169  I(), J() and K() are the coefficients of sigma_x, sigma_y, sigma_z
170  */
171  Scalar U() const { return fU; }
172  Scalar I() const { return fI; }
173  Scalar J() const { return fJ; }
174  Scalar K() const { return fK; }
175 
176  // =========== operations ==============
177 
178  /**
179  Rotation operation on a cartesian vector
180  */
181  typedef DisplacementVector3D<Cartesian3D<double>, DefaultCoordinateSystemTag > XYZVector;
182  XYZVector operator() (const XYZVector & v) const {
183 
184  const Scalar alpha = fU*fU - fI*fI - fJ*fJ - fK*fK;
185  const Scalar twoQv = 2*(fI*v.X() + fJ*v.Y() + fK*v.Z());
186  const Scalar twoU = 2 * fU;
187  return XYZVector ( alpha * v.X() + twoU * (fJ*v.Z() - fK*v.Y()) + twoQv * fI ,
188  alpha * v.Y() + twoU * (fK*v.X() - fI*v.Z()) + twoQv * fJ ,
189  alpha * v.Z() + twoU * (fI*v.Y() - fJ*v.X()) + twoQv * fK );
190  }
191 
192  /**
193  Rotation operation on a displacement vector in any coordinate system
194  */
195  template <class CoordSystem,class Tag>
196  DisplacementVector3D<CoordSystem,Tag>
197  operator() (const DisplacementVector3D<CoordSystem,Tag> & v) const {
198  DisplacementVector3D< Cartesian3D<double> > xyz(v.X(), v.Y(), v.Z());
199  DisplacementVector3D< Cartesian3D<double> > rxyz = operator()(xyz);
200  DisplacementVector3D< CoordSystem,Tag > vNew;
201  vNew.SetXYZ( rxyz.X(), rxyz.Y(), rxyz.Z() );
202  return vNew;
203  }
204 
205  /**
206  Rotation operation on a position vector in any coordinate system
207  */
208  template <class CoordSystem, class Tag>
209  PositionVector3D<CoordSystem,Tag>
210  operator() (const PositionVector3D<CoordSystem,Tag> & p) const {
211  DisplacementVector3D< Cartesian3D<double>,Tag > xyz(p);
212  DisplacementVector3D< Cartesian3D<double>,Tag > rxyz = operator()(xyz);
213  return PositionVector3D<CoordSystem,Tag> ( rxyz );
214  }
215 
216  /**
217  Rotation operation on a Lorentz vector in any 4D coordinate system
218  */
219  template <class CoordSystem>
220  LorentzVector<CoordSystem>
221  operator() (const LorentzVector<CoordSystem> & v) const {
222  DisplacementVector3D< Cartesian3D<double> > xyz(v.Vect());
223  xyz = operator()(xyz);
224  LorentzVector< PxPyPzE4D<double> > xyzt (xyz.X(), xyz.Y(), xyz.Z(), v.E());
225  return LorentzVector<CoordSystem> ( xyzt );
226  }
227 
228  /**
229  Rotation operation on an arbitrary vector v.
230  Preconditions: v must implement methods x(), y(), and z()
231  and the arbitrary vector type must have a constructor taking (x,y,z)
232  */
233  template <class ForeignVector>
234  ForeignVector
235  operator() (const ForeignVector & v) const {
236  DisplacementVector3D< Cartesian3D<double> > xyz(v);
237  DisplacementVector3D< Cartesian3D<double> > rxyz = operator()(xyz);
238  return ForeignVector ( rxyz.X(), rxyz.Y(), rxyz.Z() );
239  }
240 
241  /**
242  Overload operator * for rotation on a vector
243  */
244  template <class AVector>
245  inline
246  AVector operator* (const AVector & v) const
247  {
248  return operator()(v);
249  }
250 
251  /**
252  Invert a rotation in place
253  */
254  void Invert() { fI = -fI; fJ = -fJ; fK = -fK; }
255 
256  /**
257  Return inverse of a rotation
258  */
259  Quaternion Inverse() const { return Quaternion(fU, -fI, -fJ, -fK); }
260 
261  // ========= Multi-Rotation Operations ===============
262 
263  /**
264  Multiply (combine) two rotations
265  */
266  /**
267  Multiply (combine) two rotations
268  */
269  Quaternion operator * (const Quaternion & q) const {
270  return Quaternion ( fU*q.fU - fI*q.fI - fJ*q.fJ - fK*q.fK ,
271  fU*q.fI + fI*q.fU + fJ*q.fK - fK*q.fJ ,
272  fU*q.fJ - fI*q.fK + fJ*q.fU + fK*q.fI ,
273  fU*q.fK + fI*q.fJ - fJ*q.fI + fK*q.fU );
274  }
275 
276  Quaternion operator * (const Rotation3D & r) const;
277  Quaternion operator * (const AxisAngle & a) const;
278  Quaternion operator * (const EulerAngles & e) const;
279  Quaternion operator * (const RotationZYX & r) const;
280  Quaternion operator * (const RotationX & rx) const;
281  Quaternion operator * (const RotationY & ry) const;
282  Quaternion operator * (const RotationZ & rz) const;
283 
284  /**
285  Post-Multiply (on right) by another rotation : T = T*R
286  */
287  template <class R>
288  Quaternion & operator *= (const R & r) { return *this = (*this)*r; }
289 
290 
291  /**
292  Distance between two rotations in Quaternion form
293  Note: The rotation group is isomorphic to a 3-sphere
294  with diametrically opposite points identified.
295  The (rotation group-invariant) is the smaller
296  of the two possible angles between the images of
297  the two totations on that sphere. Thus the distance
298  is never greater than pi/2.
299  */
300 
301  Scalar Distance(const Quaternion & q) const ;
302 
303  /**
304  Equality/inequality operators
305  */
306  bool operator == (const Quaternion & rhs) const {
307  if( fU != rhs.fU ) return false;
308  if( fI != rhs.fI ) return false;
309  if( fJ != rhs.fJ ) return false;
310  if( fK != rhs.fK ) return false;
311  return true;
312  }
313  bool operator != (const Quaternion & rhs) const {
314  return ! operator==(rhs);
315  }
316 
317 private:
318 
319  Scalar fU;
320  Scalar fI;
321  Scalar fJ;
322  Scalar fK;
323 
324 }; // Quaternion
325 
326 // ============ Class Quaternion ends here ============
327 
328 /**
329  Distance between two rotations
330  */
331 template <class R>
332 inline
333 typename Quaternion::Scalar
334 Distance ( const Quaternion& r1, const R & r2) {return gv_detail::dist(r1,r2);}
335 
336 /**
337  Multiplication of an axial rotation by an AxisAngle
338  */
339 Quaternion operator* (RotationX const & r1, Quaternion const & r2);
340 Quaternion operator* (RotationY const & r1, Quaternion const & r2);
341 Quaternion operator* (RotationZ const & r1, Quaternion const & r2);
342 
343 /**
344  Stream Output and Input
345  */
346  // TODO - I/O should be put in the manipulator form
347 
348 std::ostream & operator<< (std::ostream & os, const Quaternion & q);
349 
350 
351 } // namespace Math
352 } // namespace ROOT
353 
354 #endif // ROOT_Math_GenVector_Quaternion