source: trunk/CLHEP/src/RotationC.cc@ 16

Last change on this file since 16 was 4, checked in by Pavel Demin, 17 years ago

first commit

File size: 6.3 KB
Line 
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, which involve
8// correcting user-supplied data which is supposed to form a Rotation, or
9// rectifying a rotation matrix which may have drifted due to roundoff.
10//
11
12#ifdef GNUPRAGMA
13#pragma implementation
14#endif
15
16#include "CLHEP/Vector/defs.h"
17#include "CLHEP/Vector/Rotation.h"
18#include "CLHEP/Vector/ZMxpv.h"
19
20#include <cmath>
21
22namespace CLHEP {
23
24// --------- Helper methods (private) for setting from 3 columns:
25
26bool HepRotation::setCols
27 ( const Hep3Vector & u1, const Hep3Vector & u2, const Hep3Vector & u3,
28 double u1u2,
29 Hep3Vector & v1, Hep3Vector & v2, Hep3Vector & v3 ) const {
30
31 if ( (1-fabs(u1u2)) <= Hep4RotationInterface::tolerance ) {
32 ZMthrowC (ZMxpvParallelCols(
33 "All three cols supplied for a Rotation are parallel --"
34 "\n an arbitrary rotation will be returned"));
35 setArbitrarily (u1, v1, v2, v3);
36 return true;
37 }
38
39 v1 = u1;
40 v2 = Hep3Vector(u2 - u1u2 * u1).unit();
41 v3 = v1.cross(v2);
42 if ( v3.dot(u3) >= 0 ) {
43 return true;
44 } else {
45 return false; // looks more like a reflection in this case!
46 }
47
48} // HepRotation::setCols
49
50void HepRotation::setArbitrarily (const Hep3Vector & colX,
51 Hep3Vector & v1, Hep3Vector & v2, Hep3Vector & v3) const {
52
53 // We have all three col's parallel. Warnings already been given;
54 // this just supplies a result which is a valid rotation.
55
56 v1 = colX.unit();
57 v2 = v1.cross(Hep3Vector(0,0,1));
58 if (v2.mag2() != 0) {
59 v2 = v2.unit();
60 } else {
61 v2 = Hep3Vector(1,0,0);
62 }
63 v3 = v1.cross(v2);
64
65 return;
66
67} // HepRotation::setArbitrarily
68
69
70
71
72// ---------- Constructors and Assignment:
73
74// 3 orthogonal columns or rows
75
76HepRotation & HepRotation::set( const Hep3Vector & colX,
77 const Hep3Vector & colY,
78 const Hep3Vector & colZ ) {
79 Hep3Vector ucolX = colX.unit();
80 Hep3Vector ucolY = colY.unit();
81 Hep3Vector ucolZ = colZ.unit();
82
83 double u1u2 = ucolX.dot(ucolY);
84 double f12 = fabs(u1u2);
85 if ( f12 > Hep4RotationInterface::tolerance ) {
86 ZMthrowC (ZMxpvNotOrthogonal(
87 "col's X and Y supplied for Rotation are not close to orthogonal"));
88 }
89 double u1u3 = ucolX.dot(ucolZ);
90 double f13 = fabs(u1u3);
91 if ( f13 > Hep4RotationInterface::tolerance ) {
92 ZMthrowC (ZMxpvNotOrthogonal(
93 "col's X and Z supplied for Rotation are not close to orthogonal"));
94 }
95 double u2u3 = ucolY.dot(ucolZ);
96 double f23 = fabs(u2u3);
97 if ( f23 > Hep4RotationInterface::tolerance ) {
98 ZMthrowC (ZMxpvNotOrthogonal(
99 "col's Y and Z supplied for Rotation are not close to orthogonal"));
100 }
101
102 Hep3Vector v1, v2, v3;
103 bool isRotation;
104 if ( (f12 <= f13) && (f12 <= f23) ) {
105 isRotation = setCols ( ucolX, ucolY, ucolZ, u1u2, v1, v2, v3 );
106 if ( !isRotation ) {
107 ZMthrowC (ZMxpvImproperRotation(
108 "col's X Y and Z supplied form closer to a reflection than a Rotation "
109 "\n col Z is set to col X cross col Y"));
110 }
111 } else if ( f13 <= f23 ) {
112 isRotation = setCols ( ucolZ, ucolX, ucolY, u1u3, v3, v1, v2 );
113 if ( !isRotation ) {
114 ZMthrowC (ZMxpvImproperRotation(
115 "col's X Y and Z supplied form closer to a reflection than a Rotation "
116 "\n col Y is set to col Z cross col X"));
117 }
118 } else {
119 isRotation = setCols ( ucolY, ucolZ, ucolX, u2u3, v2, v3, v1 );
120 if ( !isRotation ) {
121 ZMthrowC (ZMxpvImproperRotation(
122 "col's X Y and Z supplied form closer to a reflection than a Rotation "
123 "\n col X is set to col Y cross col Z"));
124 }
125 }
126
127 rxx = v1.x(); ryx = v1.y(); rzx = v1.z();
128 rxy = v2.x(); ryy = v2.y(); rzy = v2.z();
129 rxz = v3.x(); ryz = v3.y(); rzz = v3.z();
130
131 return *this;
132
133} // HepRotation::set(colX, colY, colZ)
134
135HepRotation::HepRotation ( const Hep3Vector & colX,
136 const Hep3Vector & colY,
137 const Hep3Vector & colZ )
138{
139 set (colX, colY, colZ);
140}
141
142HepRotation & HepRotation::setRows( const Hep3Vector & rowX,
143 const Hep3Vector & rowY,
144 const Hep3Vector & rowZ ) {
145 set (rowX, rowY, rowZ);
146 invert();
147 return *this;
148}
149
150
151
152// ------- Rectify a near-rotation
153
154void HepRotation::rectify() {
155 // Assuming the representation of this is close to a true Rotation,
156 // but may have drifted due to round-off error from many operations,
157 // this forms an "exact" orthonormal matrix for the rotation again.
158
159 // The first step is to average with the transposed inverse. This
160 // will correct for small errors such as those occuring when decomposing
161 // a LorentzTransformation. Then we take the bull by the horns and
162 // formally extract the axis and delta (assuming the Rotation were true)
163 // and re-setting the rotation according to those.
164
165 double det = rxx * ryy * rzz +
166 rxy * ryz * rzx +
167 rxz * ryx * rzy -
168 rxx * ryz * rzy -
169 rxy * ryx * rzz -
170 rxz * ryy * rzx ;
171 if (det <= 0) {
172 ZMthrowA(ZMxpvImproperRotation(
173 "Attempt to rectify a Rotation with determinant <= 0\n"));
174 return;
175 }
176 double di = 1.0 / det;
177
178 // xx, xy, ... are components of inverse matrix:
179 double xx = (ryy * rzz - ryz * rzy) * di;
180 double xy = (rzy * rxz - rzz * rxy) * di;
181 double xz = (rxy * ryz - rxz * ryy) * di;
182 double yx = (ryz * rzx - ryx * rzz) * di;
183 double yy = (rzz * rxx - rzx * rxz) * di;
184 double yz = (rxz * ryx - rxx * ryz) * di;
185 double zx = (ryx * rzy - ryy * rzx) * di;
186 double zy = (rzx * rxy - rzy * rxx) * di;
187 double zz = (rxx * ryy - rxy * ryx) * di;
188
189 // Now average with the TRANSPOSE of that:
190 rxx = .5*(rxx + xx);
191 rxy = .5*(rxy + yx);
192 rxz = .5*(rxz + zx);
193 ryx = .5*(ryx + xy);
194 ryy = .5*(ryy + yy);
195 ryz = .5*(ryz + zy);
196 rzx = .5*(rzx + xz);
197 rzy = .5*(rzy + yz);
198 rzz = .5*(rzz + zz);
199
200 // Now force feed this improved rotation
201 double del = delta();
202 Hep3Vector u = axis();
203 u = u.unit(); // Because if the rotation is inexact, then the
204 // axis() returned will not have length 1!
205 set(u, del);
206
207} // rectify()
208
209} // namespace CLHEP
210
Note: See TracBrowser for help on using the repository browser.