#ifndef ROOT_Math_GenVector_RotationZ
#define ROOT_Math_GenVector_RotationZ 1
#include "Math/GenVector/Cartesian3D.h"
#include "Math/GenVector/DisplacementVector3D.h"
#include "Math/GenVector/PositionVector3D.h"
#include "Math/GenVector/LorentzVector.h"
#include "Math/GenVector/3DDistances.h"
#include "Math/GenVector/RotationZfwd.h"
#include <cmath>
namespace ROOT {
namespace Math {
class RotationZ {
public:
typedef double Scalar;
RotationZ() : fAngle(0), fSin(0), fCos(1) { }
explicit RotationZ( Scalar angle ) : fAngle(angle),
fSin(std::sin(angle)),
fCos(std::cos(angle))
{
Rectify();
}
void Rectify() {
if ( std::fabs(fAngle) >= M_PI ) {
double x = fAngle / (2.0 * M_PI);
fAngle = (2.0 * M_PI) * ( x + std::floor(.5-x) );
fSin = std::sin(fAngle);
fCos = std::cos(fAngle);
}
}
void SetAngle (Scalar angle) {
fSin=std::sin(angle);
fCos=std::cos(angle);
fAngle= angle;
Rectify();
}
void SetComponents (Scalar angle) { SetAngle(angle); }
void GetAngle ( Scalar & angle ) const { angle = atan2 (fSin,fCos); }
void GetComponents ( Scalar & angle ) const { GetAngle(angle); }
Scalar Angle () const { return atan2 (fSin,fCos); }
Scalar SinAngle () const { return fSin; }
Scalar CosAngle () const { return fCos; }
template <class CoordSystem, class U>
DisplacementVector3D<CoordSystem,U>
operator() (const DisplacementVector3D<CoordSystem,U> & v) const {
DisplacementVector3D< Cartesian3D<double>,U > xyz;
xyz.SetXYZ( fCos*v.x()-fSin*v.y(), fCos*v.y()+fSin*v.x(), v.z() );
return DisplacementVector3D<CoordSystem,U>(xyz);
}
template <class CoordSystem, class U>
PositionVector3D<CoordSystem, U>
operator() (const PositionVector3D<CoordSystem,U> & v) const {
DisplacementVector3D< Cartesian3D<double>,U > xyz(v);
DisplacementVector3D< Cartesian3D<double>,U > rxyz = operator()(xyz);
return PositionVector3D<CoordSystem,U> ( 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() { fAngle = -fAngle; fSin = -fSin; }
RotationZ Inverse() const { RotationZ t(*this); t.Invert(); return t; }
RotationZ operator * (const RotationZ & r) const {
RotationZ ans;
double x = (fAngle + r.fAngle) / (2.0 * M_PI);
ans.fAngle = (2.0 * M_PI) * ( x + std::floor(.5-x) );
ans.fSin = fSin*r.fCos + fCos*r.fSin;
ans.fCos = fCos*r.fCos - fSin*r.fSin;
return ans;
}
RotationZ & operator *= (const RotationZ & r) { return *this = (*this)*r; }
bool operator == (const RotationZ & rhs) const {
if( fAngle != rhs.fAngle ) return false;
return true;
}
bool operator != (const RotationZ & rhs) const {
return ! operator==(rhs);
}
private:
Scalar fAngle;
Scalar fSin;
Scalar fCos;
};
template <class R>
inline
typename RotationZ::Scalar
Distance ( const RotationZ& r1, const R & r2) {return gv_detail::dist(r1,r2);}
inline
std::ostream & operator<< (std::ostream & os, const RotationZ & r) {
os << " RotationZ(" << r.Angle() << ") ";
return os;
}
}
}
#endif // ROOT_Math_GenVector_RotationZ