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