#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 {
class Quaternion {
public:
typedef double Scalar;
Quaternion()
: fU(1.0)
, fI(0.0)
, fJ(0.0)
, fK(0.0)
{ }
template<class IT>
Quaternion(IT begin, IT end) { SetComponents(begin,end); }
template <class OtherRotation>
explicit Quaternion(const OtherRotation & r) {gv_detail::convert(r,*this);}
Quaternion(Scalar u, Scalar i, Scalar j, Scalar k) :
fU(u), fI(i), fJ(j), fK(k) { }
void Rectify();
template <class OtherRotation>
Quaternion & operator=( OtherRotation const & r ) {
gv_detail::convert(r,*this);
return *this;
}
template<class IT>
#ifndef NDEBUG
void SetComponents(IT begin, IT end) {
#else
void SetComponents(IT begin, IT ) {
#endif
fU = *begin++;
fI = *begin++;
fJ = *begin++;
fK = *begin++;
assert (end==begin);
}
template<class IT>
#ifndef NDEBUG
void GetComponents(IT begin, IT end) const {
#else
void GetComponents(IT begin, IT ) const {
#endif
*begin++ = fU;
*begin++ = fI;
*begin++ = fJ;
*begin++ = fK;
assert (end==begin);
}
template<class IT>
void GetComponents(IT begin ) const {
*begin++ = fU;
*begin++ = fI;
*begin++ = fJ;
*begin = fK;
}
void SetComponents(Scalar u, Scalar i, Scalar j, Scalar k) {
fU=u; fI=i; fJ=j; fK=k;
}
void GetComponents(Scalar & u, Scalar & i, Scalar & j, Scalar & k) const {
u=fU; i=fI; j=fJ; k=fK;
}
Scalar U() const { return fU; }
Scalar I() const { return fI; }
Scalar J() const { return fJ; }
Scalar K() const { return fK; }
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 );
}
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;
}
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 );
}
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 );
}
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() );
}
template <class AVector>
inline
AVector operator* (const AVector & v) const
{
return operator()(v);
}
void Invert() { fI = -fI; fJ = -fJ; fK = -fK; }
Quaternion Inverse() const { return Quaternion(fU, -fI, -fJ, -fK); }
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;
template <class R>
Quaternion & operator *= (const R & r) { return *this = (*this)*r; }
Scalar Distance(const Quaternion & q) const ;
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;
};
template <class R>
inline
typename Quaternion::Scalar
Distance ( const Quaternion& r1, const R & r2) {return gv_detail::dist(r1,r2);}
Quaternion operator* (RotationX const & r1, Quaternion const & r2);
Quaternion operator* (RotationY const & r1, Quaternion const & r2);
Quaternion operator* (RotationZ const & r1, Quaternion const & r2);
std::ostream & operator<< (std::ostream & os, const Quaternion & q);
}
}
#endif // ROOT_Math_GenVector_Quaternion