Skip to content
47 changes: 43 additions & 4 deletions math/genvector/inc/Math/GenVector/VectorUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,15 +275,16 @@ namespace ROOT {

// rotation and transformations


/**
rotation along X axis for a generic vector by an Angle alpha
returning a new vector.
The only pre requisite on the Vector is that it has to implement the X() , Y() and Z()
The only pre requisite on the Vector is that it has to implement the X(), Y() and Z()
and SetXYZ methods.
*/
template <class Vector>
Vector RotateX(const Vector & v, double alpha) {
if (std::fmod(alpha, 2 * M_PI) == 0.)
return v;
using std::sin;
double sina = sin(alpha);
using std::cos;
Expand All @@ -298,11 +299,13 @@ namespace ROOT {
/**
rotation along Y axis for a generic vector by an Angle alpha
returning a new vector.
The only pre requisite on the Vector is that it has to implement the X() , Y() and Z()
The only pre requisite on the Vector is that it has to implement the X(), Y() and Z()
and SetXYZ methods.
*/
template <class Vector>
Vector RotateY(const Vector & v, double alpha) {
if (std::fmod(alpha, 2 * M_PI) == 0.)
return v;
using std::sin;
double sina = sin(alpha);
using std::cos;
Expand All @@ -317,11 +320,13 @@ namespace ROOT {
/**
rotation along Z axis for a generic vector by an Angle alpha
returning a new vector.
The only pre requisite on the Vector is that it has to implement the X() , Y() and Z()
The only pre requisite on the Vector is that it has to implement the X(), Y() and Z()
and SetXYZ methods.
*/
template <class Vector>
Vector RotateZ(const Vector & v, double alpha) {
if (std::fmod(alpha, 2 * M_PI) == 0.)
return v;
using std::sin;
double sina = sin(alpha);
using std::cos;
Expand All @@ -333,6 +338,40 @@ namespace ROOT {
return vrot;
}

/**
rotation along a custom axis for a generic vector by an Angle alpha (in rad)
returning a new vector.
The only pre requisite on the Vector is that it has to implement the X(), Y() and Z()
and SetXYZ methods.
*/
template <class Vector>
Vector Rotate(const Vector &v, double alpha, const Vector &axis)
{
if (std::fmod(alpha, 2 * M_PI) == 0.)
return v;
const double ll = std::sqrt(axis.X() * axis.X() + axis.Y() * axis.Y() + axis.Z() * axis.Z());
if (ll == 0.)
GenVector::Throw("Axis Vector has zero magnitude");
const double sa = std::sin(alpha);
const double ca = std::cos(alpha);
const double dx = axis.X() / ll;
const double dy = axis.Y() / ll;
const double dz = axis.Z() / ll;
// clang-format off
const double rot00 = (1 - ca) * dx * dx + ca , rot01 = (1 - ca) * dx * dy - sa * dz, rot02 = (1 - ca) * dx * dz + sa * dy,
rot10 = (1 - ca) * dy * dx + sa * dz, rot11 = (1 - ca) * dy * dy + ca , rot12 = (1 - ca) * dy * dz - sa * dx,
rot20 = (1 - ca) * dz * dx - sa * dy, rot21 = (1 - ca) * dz * dy + sa * dx, rot22 = (1 - ca) * dz * dz + ca ;
// clang-format on
const double xX = v.X();
const double yY = v.Y();
const double zZ = v.Z();
const double x2 = rot00 * xX + rot01 * yY + rot02 * zZ;
const double y2 = rot10 * xX + rot11 * yY + rot12 * zZ;
const double z2 = rot20 * xX + rot21 * yY + rot22 * zZ;
Vector vrot;
vrot.SetXYZ(x2, y2, z2);
return vrot;
}

/**
rotation on a generic vector using a generic rotation class.
Expand Down
15 changes: 15 additions & 0 deletions math/genvector/test/testGenVector.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,21 @@ int testRotations3D() {
iret |= compare(qr1.Y(), qr2.Y(),"y diff",10 );
iret |= compare(qr1.Z(), qr2.Z(),"z diff",10 );

// test TVector3-like Rotate function around some axis by an angle. Test case taken from cwessel:
// https://root-forum.cern.ch/t/tvector3-rotate-to-arbitrary-rotation-using-xyzvector/63244/7
XYZVector ag(17, -4, -23);
double angle = 100;
XYZVector axisg(-23.4, 1.7, -0.3);
XYZVector rotated = Rotate(ag, angle, axisg);
// should be equivalent to:
// TVector3 at(17, -4, -23);
// TVector3 axist(-23.4, 1.7, -0.3);
// at.Rotate(angle, axist);
// at.Print();
// (17.856456,8.106555,-21.199782)
iret |= compare(rotated.X(), 17.856456, "x diff", 1e10);
iret |= compare(rotated.Y(), 8.106555, "y diff", 1e10);
iret |= compare(rotated.Z(), -21.199782, "z diff", 1e10);

if (iret == 0) std::cout << "\tOK\n";
else std::cout << "\t FAILED\n";
Expand Down
3 changes: 2 additions & 1 deletion math/physics/src/TRotation.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ TVector3 class:
#include "TRotation.h"
#include "TMath.h"
#include "TQuaternion.h"
#include <cmath>

ClassImp(TRotation);

Expand Down Expand Up @@ -323,7 +324,7 @@ TRotation::TRotation(const TQuaternion & Q) {
/// Rotate along an axis.

TRotation & TRotation::Rotate(Double_t a, const TVector3& axis) {
if (a != 0.0) {
if (std::fmod(a, 2 * TMath::Pi()) != 0.) {
Double_t ll = axis.Mag();
if (ll == 0.0) {
Warning("Rotate(angle,axis)"," zero axis");
Expand Down
Loading