Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/externals/clhep/src/RotationE.cc

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

Diff markup

Differences between /externals/clhep/src/RotationE.cc (Version 11.3.0) and /externals/clhep/src/RotationE.cc (Version 11.0)


  1 // -*- C++ -*-                                      1 // -*- C++ -*-
  2 // -------------------------------------------      2 // ---------------------------------------------------------------------------
  3 //                                                  3 //
  4 // This file is a part of the CLHEP - a Class       4 // This file is a part of the CLHEP - a Class Library for High Energy Physics.
  5 //                                                  5 //
  6 // This is the implementation of methods of th      6 // This is the implementation of methods of the HepRotation class which
  7 // were introduced when ZOOM PhysicsVectors wa      7 // were introduced when ZOOM PhysicsVectors was merged in, and which involve
  8 // Euler Angles representation.                     8 // Euler Angles representation.
  9 //                                                  9 //
 10 // Apr 28, 2003  mf  Modified way of computing     10 // Apr 28, 2003  mf  Modified way of computing Euler angles to avoid flawed
 11 //                   answers in the case where     11 //                   answers in the case where theta is near 0 of pi, and
 12 //                   the matrix is not a perfe     12 //                   the matrix is not a perfect rotation (due to roundoff).
 13                                                    13 
 14 #include "CLHEP/Vector/Rotation.h"                 14 #include "CLHEP/Vector/Rotation.h"
 15 #include "CLHEP/Vector/EulerAngles.h"              15 #include "CLHEP/Vector/EulerAngles.h"
 16 #include "CLHEP/Units/PhysicalConstants.h"         16 #include "CLHEP/Units/PhysicalConstants.h"
 17                                                    17 
 18 #include <cmath>                                   18 #include <cmath>
 19 #include <iostream>                                19 #include <iostream>
 20                                                    20 
 21 namespace CLHEP  {                                 21 namespace CLHEP  {
 22                                                    22 
 23 static inline double safe_acos (double x) {        23 static inline double safe_acos (double x) {
 24   if (std::abs(x) <= 1.0) return std::acos(x);     24   if (std::abs(x) <= 1.0) return std::acos(x);
 25   return ( (x>0) ? 0 : CLHEP::pi );                25   return ( (x>0) ? 0 : CLHEP::pi );
 26 }                                                  26 }
 27                                                    27 
 28 // ----------  Constructors and Assignment:        28 // ----------  Constructors and Assignment:
 29                                                    29 
 30 // Euler angles                                    30 // Euler angles
 31                                                    31 
 32 HepRotation & HepRotation::set(double phi1, do     32 HepRotation & HepRotation::set(double phi1, double theta1, double psi1) {
 33                                                    33 
 34   double sinPhi   = std::sin( phi1   ), cosPhi     34   double sinPhi   = std::sin( phi1   ), cosPhi   = std::cos( phi1   );
 35   double sinTheta = std::sin( theta1 ), cosThe     35   double sinTheta = std::sin( theta1 ), cosTheta = std::cos( theta1 );
 36   double sinPsi   = std::sin( psi1   ), cosPsi     36   double sinPsi   = std::sin( psi1   ), cosPsi   = std::cos( psi1   );
 37                                                    37 
 38   rxx =   cosPsi * cosPhi - cosTheta * sinPhi      38   rxx =   cosPsi * cosPhi - cosTheta * sinPhi * sinPsi;
 39   rxy =   cosPsi * sinPhi + cosTheta * cosPhi      39   rxy =   cosPsi * sinPhi + cosTheta * cosPhi * sinPsi;
 40   rxz =   sinPsi * sinTheta;                       40   rxz =   sinPsi * sinTheta;
 41                                                    41 
 42   ryx = - sinPsi * cosPhi - cosTheta * sinPhi      42   ryx = - sinPsi * cosPhi - cosTheta * sinPhi * cosPsi;
 43   ryy = - sinPsi * sinPhi + cosTheta * cosPhi      43   ryy = - sinPsi * sinPhi + cosTheta * cosPhi * cosPsi;
 44   ryz =   cosPsi * sinTheta;                       44   ryz =   cosPsi * sinTheta;
 45                                                    45 
 46   rzx =   sinTheta * sinPhi;                       46   rzx =   sinTheta * sinPhi;
 47   rzy = - sinTheta * cosPhi;                       47   rzy = - sinTheta * cosPhi;
 48   rzz =   cosTheta;                                48   rzz =   cosTheta;
 49                                                    49 
 50   return  *this;                                   50   return  *this;
 51                                                    51 
 52 }  // Rotation::set(phi, theta, psi)               52 }  // Rotation::set(phi, theta, psi)
 53                                                    53 
 54 HepRotation::HepRotation( double phi1, double      54 HepRotation::HepRotation( double phi1, double theta1, double psi1 ) 
 55 {                                                  55 {
 56   set (phi1, theta1, psi1);                        56   set (phi1, theta1, psi1);
 57 }                                                  57 }
 58 HepRotation & HepRotation::set( const HepEuler     58 HepRotation & HepRotation::set( const HepEulerAngles & e ) {
 59   return set(e.phi(), e.theta(), e.psi());         59   return set(e.phi(), e.theta(), e.psi());
 60 }                                                  60 }
 61 HepRotation::HepRotation ( const HepEulerAngle     61 HepRotation::HepRotation ( const HepEulerAngles & e ) 
 62 {                                                  62 {
 63   set(e.phi(), e.theta(), e.psi());                63   set(e.phi(), e.theta(), e.psi());
 64 }                                                  64 }
 65                                                    65 
 66                                                    66  
 67 double HepRotation::phi  () const {                67 double HepRotation::phi  () const {
 68                                                    68 
 69   double s2 =  1.0 - rzz*rzz;                      69   double s2 =  1.0 - rzz*rzz;
 70   if (s2 < 0) {                                    70   if (s2 < 0) {
 71     std::cerr << "HepRotation::phi() - "           71     std::cerr << "HepRotation::phi() - "
 72         << "HepRotation::phi() finds | rzz | >     72         << "HepRotation::phi() finds | rzz | > 1 " << std::endl;
 73     s2 = 0;                                        73     s2 = 0;
 74   }                                                74   }
 75   const double sinTheta = std::sqrt( s2 );         75   const double sinTheta = std::sqrt( s2 );
 76                                                    76 
 77   if (sinTheta < .01) { // For theta close to      77   if (sinTheta < .01) { // For theta close to 0 or PI, use the more stable
 78         // algorithm to get all three Euler an     78         // algorithm to get all three Euler angles
 79     HepEulerAngles ea = eulerAngles();             79     HepEulerAngles ea = eulerAngles();
 80     return ea.phi();                               80     return ea.phi();
 81   }                                                81   }
 82                                                    82   
 83   const double cscTheta = 1/sinTheta;              83   const double cscTheta = 1/sinTheta;
 84   double cosabsphi =  - rzy * cscTheta;            84   double cosabsphi =  - rzy * cscTheta;
 85   if ( std::fabs(cosabsphi) > 1 ) { // NaN-pro     85   if ( std::fabs(cosabsphi) > 1 ) { // NaN-proofing
 86     std::cerr << "HepRotation::phi() - "           86     std::cerr << "HepRotation::phi() - "
 87       << "HepRotation::phi() finds | cos phi |     87       << "HepRotation::phi() finds | cos phi | > 1 " << std::endl;
 88     cosabsphi = 1;                                 88     cosabsphi = 1;
 89   }                                                89   }
 90   const double absPhi = std::acos ( cosabsphi      90   const double absPhi = std::acos ( cosabsphi );
 91   if (rzx > 0) {                                   91   if (rzx > 0) {
 92     return   absPhi;                               92     return   absPhi;
 93   } else if (rzx < 0) {                            93   } else if (rzx < 0) {
 94     return  -absPhi;                               94     return  -absPhi;
 95   } else {                                         95   } else {
 96     return  (rzy < 0) ? 0 : CLHEP::pi;             96     return  (rzy < 0) ? 0 : CLHEP::pi;
 97   }                                                97   }
 98                                                    98 
 99 } // phi()                                         99 } // phi()
100                                                   100 
101 double HepRotation::theta() const {               101 double HepRotation::theta() const {
102                                                   102 
103   return  safe_acos( rzz );                       103   return  safe_acos( rzz );
104                                                   104 
105 } // theta()                                      105 } // theta()
106                                                   106 
107 double HepRotation::psi  () const {               107 double HepRotation::psi  () const {
108                                                   108 
109   double sinTheta;                                109   double sinTheta;
110   if ( std::fabs(rzz) > 1 ) { // NaN-proofing     110   if ( std::fabs(rzz) > 1 ) { // NaN-proofing
111     std::cerr << "HepRotation::psi() - "          111     std::cerr << "HepRotation::psi() - "
112       << "HepRotation::psi() finds | rzz | > 1    112       << "HepRotation::psi() finds | rzz | > 1" << std::endl;
113     sinTheta = 0;                                 113     sinTheta = 0;
114   } else {                                        114   } else { 
115     sinTheta = std::sqrt( 1.0 - rzz*rzz );        115     sinTheta = std::sqrt( 1.0 - rzz*rzz );
116   }                                               116   }
117                                                   117   
118   if (sinTheta < .01) { // For theta close to     118   if (sinTheta < .01) { // For theta close to 0 or PI, use the more stable
119         // algorithm to get all three Euler an    119         // algorithm to get all three Euler angles
120     HepEulerAngles ea = eulerAngles();            120     HepEulerAngles ea = eulerAngles();
121     return ea.psi();                              121     return ea.psi();
122   }                                               122   }
123                                                   123 
124   const double cscTheta = 1/sinTheta;             124   const double cscTheta = 1/sinTheta;
125   double cosabspsi =  ryz * cscTheta;             125   double cosabspsi =  ryz * cscTheta;
126   if ( std::fabs(cosabspsi) > 1 ) { // NaN-pro    126   if ( std::fabs(cosabspsi) > 1 ) { // NaN-proofing
127     std::cerr << "HepRotation::psi() - "          127     std::cerr << "HepRotation::psi() - "
128       << "HepRotation::psi() finds | cos psi |    128       << "HepRotation::psi() finds | cos psi | > 1" << std::endl;
129     cosabspsi = 1;                                129     cosabspsi = 1;
130   }                                               130   }
131   const double absPsi = std::acos ( cosabspsi     131   const double absPsi = std::acos ( cosabspsi );
132   if (rxz > 0) {                                  132   if (rxz > 0) {
133     return   absPsi;                              133     return   absPsi;
134   } else if (rxz < 0) {                           134   } else if (rxz < 0) {
135     return  -absPsi;                              135     return  -absPsi;
136   } else {                                        136   } else {
137     return  (ryz > 0) ? 0 : CLHEP::pi;            137     return  (ryz > 0) ? 0 : CLHEP::pi;
138   }                                               138   }
139                                                   139 
140 } // psi()                                        140 } // psi()
141                                                   141 
142 // Helpers for eulerAngles():                     142 // Helpers for eulerAngles():
143                                                   143 
144 static                                            144 static         
145 void correctByPi ( double& psi1, double& phi1     145 void correctByPi ( double& psi1, double& phi1 ) {
146   if (psi1 > 0) {                                 146   if (psi1 > 0) {
147     psi1 -= CLHEP::pi;                            147     psi1 -= CLHEP::pi;
148   } else {                                        148   } else {
149     psi1 += CLHEP::pi;                            149     psi1 += CLHEP::pi;
150   }                                               150   }
151   if (phi1 > 0) {                                 151   if (phi1 > 0) {
152     phi1 -= CLHEP::pi;                            152     phi1 -= CLHEP::pi;
153   } else {                                        153   } else {
154     phi1 += CLHEP::pi;                            154     phi1 += CLHEP::pi;
155   }                                               155   }  
156 }                                                 156 }
157                                                   157 
158 static                                            158 static
159 void correctPsiPhi ( double rxz, double rzx, d    159 void correctPsiPhi ( double rxz, double rzx, double ryz, double rzy, 
160          double& psi1, double& phi1 ) {           160          double& psi1, double& phi1 ) {
161                                                   161 
162   // set up quatities which would be positive     162   // set up quatities which would be positive if sin and cosine of
163   // psi1 and phi1 were positive:                 163   // psi1 and phi1 were positive:
164   double w[4];                                    164   double w[4];
165   w[0] = rxz; w[1] = rzx; w[2] = ryz; w[3] = -    165   w[0] = rxz; w[1] = rzx; w[2] = ryz; w[3] = -rzy;
166                                                   166 
167   // find biggest relevant term, which is the     167   // find biggest relevant term, which is the best one to use in correcting.
168   double maxw = std::abs(w[0]);                   168   double maxw = std::abs(w[0]); 
169   int imax = 0;                                   169   int imax = 0;
170   for (int i = 1; i < 4; ++i) {                   170   for (int i = 1; i < 4; ++i) {
171     if (std::abs(w[i]) > maxw) {                  171     if (std::abs(w[i]) > maxw) {
172       maxw = std::abs(w[i]);                      172       maxw = std::abs(w[i]);
173       imax = i;                                   173       imax = i;
174     }                                             174     }
175   }                                               175   }
176   // Determine if the correction needs to be a    176   // Determine if the correction needs to be applied:  The criteria are 
177   // different depending on whether a sine or     177   // different depending on whether a sine or cosine was the determinor: 
178   switch (imax) {                                 178   switch (imax) {
179     case 0:                                       179     case 0:
180       if (w[0] > 0 && psi1 < 0)           corr    180       if (w[0] > 0 && psi1 < 0)           correctByPi ( psi1, phi1 );
181       if (w[0] < 0 && psi1 > 0)           corr    181       if (w[0] < 0 && psi1 > 0)           correctByPi ( psi1, phi1 );
182       break;                                      182       break;
183     case 1:                                       183     case 1:
184       if (w[1] > 0 && phi1 < 0)           corr    184       if (w[1] > 0 && phi1 < 0)           correctByPi ( psi1, phi1 );
185       if (w[1] < 0 && phi1 > 0)           corr    185       if (w[1] < 0 && phi1 > 0)           correctByPi ( psi1, phi1 );
186       break;                                      186       break;
187     case 2:                                       187     case 2:
188       if (w[2] > 0 && std::abs(psi1) > CLHEP::    188       if (w[2] > 0 && std::abs(psi1) > CLHEP::halfpi) correctByPi ( psi1, phi1 );    
189       if (w[2] < 0 && std::abs(psi1) < CLHEP::    189       if (w[2] < 0 && std::abs(psi1) < CLHEP::halfpi) correctByPi ( psi1, phi1 );    
190       break;                                      190       break;
191     case 3:                                       191     case 3:
192       if (w[3] > 0 && std::abs(phi1) > CLHEP::    192       if (w[3] > 0 && std::abs(phi1) > CLHEP::halfpi) correctByPi ( psi1, phi1 );    
193       if (w[3] < 0 && std::abs(phi1) < CLHEP::    193       if (w[3] < 0 && std::abs(phi1) < CLHEP::halfpi) correctByPi ( psi1, phi1 );    
194       break;                                      194       break;
195   }                                               195   }          
196 }                                                 196 }
197                                                   197 
198 HepEulerAngles HepRotation::eulerAngles() cons    198 HepEulerAngles HepRotation::eulerAngles() const {
199                                                   199 
200   // Please see the mathematical justification    200   // Please see the mathematical justification in eulerAngleComputations.ps
201                                                   201 
202   double phi1, theta1, psi1;                      202   double phi1, theta1, psi1;
203   double psiPlusPhi, psiMinusPhi;                 203   double psiPlusPhi, psiMinusPhi;
204                                                   204   
205   theta1 = safe_acos( rzz );                      205   theta1 = safe_acos( rzz );
206                                                   206   
207 //  if (rzz > 1 || rzz < -1) {                    207 //  if (rzz > 1 || rzz < -1) {
208 //    std::cerr << "HepRotation::eulerAngles()    208 //    std::cerr << "HepRotation::eulerAngles() - "
209 //        << "HepRotation::eulerAngles() finds    209 //        << "HepRotation::eulerAngles() finds | rzz | > 1 " << std::endl;
210 //  }                                             210 //  }
211                                                   211   
212   double cosTheta = rzz;                          212   double cosTheta = rzz;
213   if (cosTheta > 1)  cosTheta = 1;                213   if (cosTheta > 1)  cosTheta = 1;
214   if (cosTheta < -1) cosTheta = -1;               214   if (cosTheta < -1) cosTheta = -1;
215                                                   215 
216   if (cosTheta == 1) {                            216   if (cosTheta == 1) {
217     psiPlusPhi = std::atan2 ( rxy - ryx, rxx +    217     psiPlusPhi = std::atan2 ( rxy - ryx, rxx + ryy );
218     psiMinusPhi = 0;                              218     psiMinusPhi = 0;     
219                                                   219 
220   } else if (cosTheta >= 0) {                     220   } else if (cosTheta >= 0) {
221                                                   221 
222     // In this realm, the atan2 expression for    222     // In this realm, the atan2 expression for psi + phi is numerically stable
223     psiPlusPhi = std::atan2 ( rxy - ryx, rxx +    223     psiPlusPhi = std::atan2 ( rxy - ryx, rxx + ryy );
224                                                   224 
225     // psi - phi is potentially more subtle, b    225     // psi - phi is potentially more subtle, but when unstable it is moot
226     double s1 = -rxy - ryx; // sin (psi-phi) *    226     double s1 = -rxy - ryx; // sin (psi-phi) * (1 - cos theta)
227     double c1 =  rxx - ryy; // cos (psi-phi) *    227     double c1 =  rxx - ryy; // cos (psi-phi) * (1 - cos theta)
228     psiMinusPhi = std::atan2 ( s1, c1 );          228     psiMinusPhi = std::atan2 ( s1, c1 );
229                                                   229         
230   } else if (cosTheta > -1) {                     230   } else if (cosTheta > -1) {
231                                                   231 
232     // In this realm, the atan2 expression for    232     // In this realm, the atan2 expression for psi - phi is numerically stable
233     psiMinusPhi = std::atan2 ( -rxy - ryx, rxx    233     psiMinusPhi = std::atan2 ( -rxy - ryx, rxx - ryy );
234                                                   234 
235    // psi + phi is potentially more subtle, bu    235    // psi + phi is potentially more subtle, but when unstable it is moot
236     double s1 = rxy - ryx; // sin (psi+phi) *     236     double s1 = rxy - ryx; // sin (psi+phi) * (1 + cos theta)
237     double c1 = rxx + ryy; // cos (psi+phi) *     237     double c1 = rxx + ryy; // cos (psi+phi) * (1 + cos theta)
238     psiPlusPhi = std::atan2 ( s1, c1 );           238     psiPlusPhi = std::atan2 ( s1, c1 );
239                                                   239 
240   } else { // cosTheta == -1                      240   } else { // cosTheta == -1
241                                                   241 
242     psiMinusPhi = std::atan2 ( -rxy - ryx, rxx    242     psiMinusPhi = std::atan2 ( -rxy - ryx, rxx - ryy );
243     psiPlusPhi = 0;                               243     psiPlusPhi = 0;
244                                                   244 
245   }                                               245   }
246                                                   246   
247   psi1 = .5 * (psiPlusPhi + psiMinusPhi);         247   psi1 = .5 * (psiPlusPhi + psiMinusPhi); 
248   phi1 = .5 * (psiPlusPhi - psiMinusPhi);         248   phi1 = .5 * (psiPlusPhi - psiMinusPhi); 
249                                                   249 
250   // Now correct by pi if we have managed to g    250   // Now correct by pi if we have managed to get a value of psiPlusPhi
251   // or psiMinusPhi that was off by 2 pi:         251   // or psiMinusPhi that was off by 2 pi:
252   correctPsiPhi ( rxz, rzx, ryz, rzy, psi1, ph    252   correctPsiPhi ( rxz, rzx, ryz, rzy, psi1, phi1 );
253                                                   253   
254   return  HepEulerAngles( phi1, theta1, psi1 )    254   return  HepEulerAngles( phi1, theta1, psi1 );
255                                                   255 
256 } // eulerAngles()                                256 } // eulerAngles()
257                                                   257 
258                                                   258 
259 void HepRotation::setPhi (double phi1) {          259 void HepRotation::setPhi (double phi1) {
260   set ( phi1, theta(), psi() );                   260   set ( phi1, theta(), psi() );
261 }                                                 261 }
262                                                   262 
263 void HepRotation::setTheta (double theta1) {      263 void HepRotation::setTheta (double theta1) {
264   set ( phi(), theta1, psi() );                   264   set ( phi(), theta1, psi() );
265 }                                                 265 }
266                                                   266 
267 void HepRotation::setPsi (double psi1) {          267 void HepRotation::setPsi (double psi1) {
268   set ( phi(), theta(), psi1 );                   268   set ( phi(), theta(), psi1 );
269 }                                                 269 }
270                                                   270 
271 }  // namespace CLHEP                             271 }  // namespace CLHEP
272                                                   272 
273                                                   273