Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
Rotation3D.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 class Rotation in 3 dimensions, represented by 3x3 matrix
12 //
13 // Created by: Mark Fischler Thurs June 9 2005
14 //
15 // Last update: $Id$
16 //
17 #ifndef ROOT_Math_GenVector_Rotation3D
18 #define ROOT_Math_GenVector_Rotation3D 1
19 
20 
28 
36 
37 
38 #include <algorithm>
39 #include <cassert>
40 #include <iostream>
41 
42 
43 namespace ROOT {
44 namespace Math {
45 
46 
47 //__________________________________________________________________________________________
48  /**
49  Rotation class with the (3D) rotation represented by
50  a 3x3 orthogonal matrix.
51  This is the optimal representation for application to vectors.
52  See also ROOT::Math::AxisAngle, ROOT::Math::EulerAngles, and ROOT::Math::Quaternion for
53  classes which have conversion operators to Rotation3D.
54 
55  All Rotations types (not only Rotation3D) can be applied to all 3D Vector classes
56  (like ROOT::Math::DisplacementVector3D and ROOT::Math::PositionVector3D)
57  and also to the 4D Vectors (ROOT::Math::LorentzVector classes), acting on the 3D components.
58  A rotation operation is applied by using the operator() or the operator *.
59  With the operator * is possible also to combine rotations.
60  Note that the operator is NOT commutative, the order how the rotations are applied is relevant.
61 
62  @ingroup GenVector
63  */
64 
65 class Rotation3D {
66 
67 public:
68 
69  typedef double Scalar;
70 
71  enum ERotation3DMatrixIndex {
72  kXX = 0, kXY = 1, kXZ = 2
73  , kYX = 3, kYY = 4, kYZ = 5
74  , kZX = 6, kZY = 7, kZZ = 8
75  };
76 
77  // ========== Constructors and Assignment =====================
78 
79  /**
80  Default constructor (identity rotation)
81  */
82  Rotation3D();
83 
84  /**
85  Construct given a pair of pointers or iterators defining the
86  beginning and end of an array of nine Scalars
87  */
88  template<class IT>
89  Rotation3D(IT begin, IT end) { SetComponents(begin,end); }
90 
91  /**
92  copy constructor
93  */
94  Rotation3D ( Rotation3D const & r ) {
95  *this = r;
96  }
97 
98  /**
99  Construct from an AxisAngle
100  */
101  explicit Rotation3D( AxisAngle const & a ) { gv_detail::convert(a, *this); }
102 
103  /**
104  Construct from EulerAngles
105  */
106  explicit Rotation3D( EulerAngles const & e ) { gv_detail::convert(e, *this); }
107 
108  /**
109  Construct from RotationZYX
110  */
111  explicit Rotation3D( RotationZYX const & e ) { gv_detail::convert(e, *this); }
112 
113  /**
114  Construct from a Quaternion
115  */
116  explicit Rotation3D( Quaternion const & q ) { gv_detail::convert(q, *this); }
117 
118  /**
119  Construct from an axial rotation
120  */
121  explicit Rotation3D( RotationZ const & r ) { gv_detail::convert(r, *this); }
122  explicit Rotation3D( RotationY const & r ) { gv_detail::convert(r, *this); }
123  explicit Rotation3D( RotationX const & r ) { gv_detail::convert(r, *this); }
124 
125  /**
126  Construct from a linear algebra matrix of size at least 3x3,
127  which must support operator()(i,j) to obtain elements (0,0) thru (2,2).
128  Precondition: The matrix is assumed to be orthonormal. No checking
129  or re-adjusting is performed.
130  */
131  template<class ForeignMatrix>
132  explicit Rotation3D(const ForeignMatrix & m) { SetComponents(m); }
133 
134  /**
135  Construct from three orthonormal vectors (which must have methods
136  x(), y() and z()) which will be used as the columns of the rotation
137  matrix. The orthonormality will be checked, and values adjusted
138  so that the result will always be a good rotation matrix.
139  */
140  template<class ForeignVector>
141  Rotation3D(const ForeignVector& v1,
142  const ForeignVector& v2,
143  const ForeignVector& v3 ) { SetComponents(v1, v2, v3); }
144 
145  // compiler generated destruuctor is ok
146 
147  /**
148  Raw constructor from nine Scalar components (without any checking)
149  */
150  Rotation3D(Scalar xx, Scalar xy, Scalar xz,
151  Scalar yx, Scalar yy, Scalar yz,
152  Scalar zx, Scalar zy, Scalar zz)
153  {
154  SetComponents (xx, xy, xz, yx, yy, yz, zx, zy, zz);
155  }
156 
157  // need to implement assignment operator to avoid using the templated one
158 
159  /**
160  Assignment operator
161  */
162  Rotation3D &
163  operator=( Rotation3D const & rhs ) {
164  SetComponents( rhs.fM[0], rhs.fM[1], rhs.fM[2],
165  rhs.fM[3], rhs.fM[4], rhs.fM[5],
166  rhs.fM[6], rhs.fM[7], rhs.fM[8] );
167  return *this;
168  }
169 
170  /**
171  Assign from an AxisAngle
172  */
173  Rotation3D &
174  operator=( AxisAngle const & a ) { return operator=(Rotation3D(a)); }
175 
176  /**
177  Assign from EulerAngles
178  */
179  Rotation3D &
180  operator=( EulerAngles const & e ) { return operator=(Rotation3D(e)); }
181 
182  /**
183  Assign from RotationZYX
184  */
185  Rotation3D &
186  operator=( RotationZYX const & r ) { return operator=(Rotation3D(r)); }
187 
188  /**
189  Assign from a Quaternion
190  */
191  Rotation3D &
192  operator=( Quaternion const & q ) {return operator=(Rotation3D(q)); }
193 
194  /**
195  Assign from an axial rotation
196  */
197  Rotation3D &
198  operator=( RotationZ const & r ) { return operator=(Rotation3D(r)); }
199  Rotation3D &
200  operator=( RotationY const & r ) { return operator=(Rotation3D(r)); }
201  Rotation3D &
202  operator=( RotationX const & r ) { return operator=(Rotation3D(r)); }
203 
204  /**
205  Assign from an orthonormal linear algebra matrix of size 3x3,
206  which must support operator()(i,j) to obtain elements (0,0) thru (2,2).
207  */
208  template<class ForeignMatrix>
209  Rotation3D &
210  operator=(const ForeignMatrix & m) {
211  SetComponents( m(0,0), m(0,1), m(0,2),
212  m(1,0), m(1,1), m(1,2),
213  m(2,0), m(2,1), m(2,2) );
214  return *this;
215  }
216 
217  /**
218  Re-adjust components to eliminate small deviations from perfect
219  orthonormality.
220  */
221  void Rectify();
222 
223  // ======== Components ==============
224 
225  /**
226  Set components from three orthonormal vectors (which must have methods
227  x(), y() and z()) which will be used as the columns of the rotation
228  matrix. The orthonormality will be checked, and values adjusted
229  so that the result will always be a good rotation matrix.
230  */
231  template<class ForeignVector>
232  void
233  SetComponents (const ForeignVector& v1,
234  const ForeignVector& v2,
235  const ForeignVector& v3 ) {
236  fM[kXX]=v1.x(); fM[kXY]=v2.x(); fM[kXZ]=v3.x();
237  fM[kYX]=v1.y(); fM[kYY]=v2.y(); fM[kYZ]=v3.y();
238  fM[kZX]=v1.z(); fM[kZY]=v2.z(); fM[kZZ]=v3.z();
239  Rectify();
240  }
241 
242  /**
243  Get components into three vectors which will be the (orthonormal)
244  columns of the rotation matrix. (The vector class must have a
245  constructor from 3 Scalars.)
246  */
247  template<class ForeignVector>
248  void
249  GetComponents ( ForeignVector& v1,
250  ForeignVector& v2,
251  ForeignVector& v3 ) const {
252  v1 = ForeignVector ( fM[kXX], fM[kYX], fM[kZX] );
253  v2 = ForeignVector ( fM[kXY], fM[kYY], fM[kZY] );
254  v3 = ForeignVector ( fM[kXZ], fM[kYZ], fM[kZZ] );
255  }
256 
257  /**
258  Set the 9 matrix components given an iterator to the start of
259  the desired data, and another to the end (9 past start).
260  */
261  template<class IT>
262 #ifndef NDEBUG
263  void SetComponents(IT begin, IT end) {
264 #else
265  void SetComponents(IT begin, IT ) {
266 #endif
267  for (int i = 0; i <9; ++i) {
268  fM[i] = *begin;
269  ++begin;
270  }
271  assert (end==begin);
272  }
273 
274  /**
275  Get the 9 matrix components into data specified by an iterator begin
276  and another to the end of the desired data (9 past start).
277  */
278  template<class IT>
279 #ifndef NDEBUG
280  void GetComponents(IT begin, IT end) const {
281 #else
282  void GetComponents(IT begin, IT ) const {
283 #endif
284  for (int i = 0; i <9; ++i) {
285  *begin = fM[i];
286  ++begin;
287  }
288  assert (end==begin);
289  }
290 
291  /**
292  Get the 9 matrix components into data specified by an iterator begin
293  */
294  template<class IT>
295  void GetComponents(IT begin) const {
296  std::copy ( fM, fM+9, begin );
297  }
298 
299  /**
300  Set components from a linear algebra matrix of size at least 3x3,
301  which must support operator()(i,j) to obtain elements (0,0) thru (2,2).
302  Precondition: The matrix is assumed to be orthonormal. NO checking
303  or re-adjusting is performed.
304  */
305  template<class ForeignMatrix>
306  void
307  SetRotationMatrix (const ForeignMatrix & m) {
308  fM[kXX]=m(0,0); fM[kXY]=m(0,1); fM[kXZ]=m(0,2);
309  fM[kYX]=m(1,0); fM[kYY]=m(1,1); fM[kYZ]=m(1,2);
310  fM[kZX]=m(2,0); fM[kZY]=m(2,1); fM[kZZ]=m(2,2);
311  }
312 
313  /**
314  Get components into a linear algebra matrix of size at least 3x3,
315  which must support operator()(i,j) for write access to elements
316  (0,0) thru (2,2).
317  */
318  template<class ForeignMatrix>
319  void
320  GetRotationMatrix (ForeignMatrix & m) const {
321  m(0,0)=fM[kXX]; m(0,1)=fM[kXY]; m(0,2)=fM[kXZ];
322  m(1,0)=fM[kYX]; m(1,1)=fM[kYY]; m(1,2)=fM[kYZ];
323  m(2,0)=fM[kZX]; m(2,1)=fM[kZY]; m(2,2)=fM[kZZ];
324  }
325 
326  /**
327  Set the components from nine scalars -- UNCHECKED for orthonormaility
328  */
329  void
330  SetComponents (Scalar xx, Scalar xy, Scalar xz,
331  Scalar yx, Scalar yy, Scalar yz,
332  Scalar zx, Scalar zy, Scalar zz) {
333  fM[kXX]=xx; fM[kXY]=xy; fM[kXZ]=xz;
334  fM[kYX]=yx; fM[kYY]=yy; fM[kYZ]=yz;
335  fM[kZX]=zx; fM[kZY]=zy; fM[kZZ]=zz;
336  }
337 
338  /**
339  Get the nine components into nine scalars
340  */
341  void
342  GetComponents (Scalar &xx, Scalar &xy, Scalar &xz,
343  Scalar &yx, Scalar &yy, Scalar &yz,
344  Scalar &zx, Scalar &zy, Scalar &zz) const {
345  xx=fM[kXX]; xy=fM[kXY]; xz=fM[kXZ];
346  yx=fM[kYX]; yy=fM[kYY]; yz=fM[kYZ];
347  zx=fM[kZX]; zy=fM[kZY]; zz=fM[kZZ];
348  }
349 
350  // =========== operations ==============
351 
352 
353  /**
354  Rotation operation on a displacement vector in any coordinate system
355  */
356  template <class CoordSystem, class U>
357  DisplacementVector3D<CoordSystem,U>
358  operator() (const DisplacementVector3D<CoordSystem,U> & v) const {
359  DisplacementVector3D< Cartesian3D<double>,U > xyz;
360  xyz.SetXYZ( fM[kXX] * v.X() + fM[kXY] * v.Y() + fM[kXZ] * v.Z() ,
361  fM[kYX] * v.X() + fM[kYY] * v.Y() + fM[kYZ] * v.Z() ,
362  fM[kZX] * v.X() + fM[kZY] * v.Y() + fM[kZZ] * v.Z() );
363  return DisplacementVector3D<CoordSystem,U>( xyz );
364  }
365 
366  /**
367  Rotation operation on a position vector in any coordinate system
368  */
369  template <class CoordSystem, class U>
370  PositionVector3D<CoordSystem,U>
371  operator() (const PositionVector3D<CoordSystem,U> & v) const {
372  DisplacementVector3D< Cartesian3D<double>,U > xyz(v);
373  DisplacementVector3D< Cartesian3D<double>,U > rxyz = operator()(xyz);
374  return PositionVector3D<CoordSystem,U> ( rxyz );
375  }
376 
377  /**
378  Rotation operation on a Lorentz vector in any spatial coordinate system
379  */
380  template <class CoordSystem>
381  LorentzVector<CoordSystem>
382  operator() (const LorentzVector<CoordSystem> & v) const {
383  DisplacementVector3D< Cartesian3D<double> > xyz(v.Vect());
384  xyz = operator()(xyz);
385  LorentzVector< PxPyPzE4D<double> > xyzt (xyz.X(), xyz.Y(), xyz.Z(), v.E());
386  return LorentzVector<CoordSystem> ( xyzt );
387  }
388 
389  /**
390  Rotation operation on an arbitrary vector v.
391  Preconditions: v must implement methods x(), y(), and z()
392  and the arbitrary vector type must have a constructor taking (x,y,z)
393  */
394  template <class ForeignVector>
395  ForeignVector
396  operator() (const ForeignVector & v) const {
397  DisplacementVector3D< Cartesian3D<double> > xyz(v);
398  DisplacementVector3D< Cartesian3D<double> > rxyz = operator()(xyz);
399  return ForeignVector ( rxyz.X(), rxyz.Y(), rxyz.Z() );
400  }
401 
402  /**
403  Overload operator * for rotation on a vector
404  */
405  template <class AVector>
406  inline
407  AVector operator* (const AVector & v) const
408  {
409  return operator()(v);
410  }
411 
412  /**
413  Invert a rotation in place
414  */
415  void Invert();
416 
417  /**
418  Return inverse of a rotation
419  */
420  Rotation3D Inverse() const { Rotation3D t(*this); t.Invert(); return t; }
421 
422  // ========= Multi-Rotation Operations ===============
423 
424  /**
425  Multiply (combine) two rotations
426  */
427  Rotation3D operator * (const Rotation3D & r) const {
428  return Rotation3D
429  ( fM[kXX]*r.fM[kXX] + fM[kXY]*r.fM[kYX] + fM[kXZ]*r.fM[kZX]
430  , fM[kXX]*r.fM[kXY] + fM[kXY]*r.fM[kYY] + fM[kXZ]*r.fM[kZY]
431  , fM[kXX]*r.fM[kXZ] + fM[kXY]*r.fM[kYZ] + fM[kXZ]*r.fM[kZZ]
432 
433  , fM[kYX]*r.fM[kXX] + fM[kYY]*r.fM[kYX] + fM[kYZ]*r.fM[kZX]
434  , fM[kYX]*r.fM[kXY] + fM[kYY]*r.fM[kYY] + fM[kYZ]*r.fM[kZY]
435  , fM[kYX]*r.fM[kXZ] + fM[kYY]*r.fM[kYZ] + fM[kYZ]*r.fM[kZZ]
436 
437  , fM[kZX]*r.fM[kXX] + fM[kZY]*r.fM[kYX] + fM[kZZ]*r.fM[kZX]
438  , fM[kZX]*r.fM[kXY] + fM[kZY]*r.fM[kYY] + fM[kZZ]*r.fM[kZY]
439  , fM[kZX]*r.fM[kXZ] + fM[kZY]*r.fM[kYZ] + fM[kZZ]*r.fM[kZZ] );
440 
441  }
442 
443 
444  /**
445  Multiplication with arbitrary rotations
446  */
447  // note: cannot have a template method since it is ambigous with the operator * on vectors
448 
449  Rotation3D operator * (const AxisAngle & a) const;
450  Rotation3D operator * (const EulerAngles & e) const;
451  Rotation3D operator * (const Quaternion & q) const;
452  Rotation3D operator * (const RotationZYX & r) const;
453  Rotation3D operator * (const RotationX & rx) const;
454  Rotation3D operator * (const RotationY & ry) const;
455  Rotation3D operator * (const RotationZ & rz) const;
456 
457  /**
458  Post-Multiply (on right) by another rotation : T = T*R
459  */
460  template <class R>
461  Rotation3D & operator *= (const R & r) { return *this = (*this)*r; }
462 
463  /**
464  Equality/inequality operators
465  */
466  bool operator == (const Rotation3D & rhs) const {
467  if( fM[0] != rhs.fM[0] ) return false;
468  if( fM[1] != rhs.fM[1] ) return false;
469  if( fM[2] != rhs.fM[2] ) return false;
470  if( fM[3] != rhs.fM[3] ) return false;
471  if( fM[4] != rhs.fM[4] ) return false;
472  if( fM[5] != rhs.fM[5] ) return false;
473  if( fM[6] != rhs.fM[6] ) return false;
474  if( fM[7] != rhs.fM[7] ) return false;
475  if( fM[8] != rhs.fM[8] ) return false;
476  return true;
477  }
478  bool operator != (const Rotation3D & rhs) const {
479  return ! operator==(rhs);
480  }
481 
482 private:
483 
484  Scalar fM[9]; // 9 elements (3x3 matrix) representing the rotation
485 
486 }; // Rotation3D
487 
488 // ============ Class Rotation3D ends here ============
489 
490 /**
491  Distance between two rotations
492  */
493 template <class R>
494 inline
495 typename Rotation3D::Scalar
496 Distance ( const Rotation3D& r1, const R & r2) {return gv_detail::dist(r1,r2);}
497 
498 /**
499  Multiplication of an axial rotation by a Rotation3D
500  */
501 Rotation3D operator* (RotationX const & r1, Rotation3D const & r2);
502 Rotation3D operator* (RotationY const & r1, Rotation3D const & r2);
503 Rotation3D operator* (RotationZ const & r1, Rotation3D const & r2);
504 
505 /**
506  Multiplication of an axial rotation by another axial Rotation
507  */
508 Rotation3D operator* (RotationX const & r1, RotationY const & r2);
509 Rotation3D operator* (RotationX const & r1, RotationZ const & r2);
510 
511 Rotation3D operator* (RotationY const & r1, RotationX const & r2);
512 Rotation3D operator* (RotationY const & r1, RotationZ const & r2);
513 
514 Rotation3D operator* (RotationZ const & r1, RotationX const & r2);
515 Rotation3D operator* (RotationZ const & r1, RotationY const & r2);
516 
517 /**
518  Stream Output and Input
519  */
520  // TODO - I/O should be put in the manipulator form
521 
522 std::ostream & operator<< (std::ostream & os, const Rotation3D & r);
523 
524 } // namespace Math
525 } // namespace ROOT
526 
527 #endif // ROOT_Math_GenVector_Rotation3D