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