Skip to content

[math] implement genvector custom axis rotation #18462

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 6, 2025
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