Skip to content

Commit 703a315

Browse files
ferdymercurymdessolebellenot
authored
[math] implement genvector custom axis rotation (root-project#18462)
* [math] implement genvector custom axis rotation Fixes https://root-forum.cern.ch/t/tvector3-rotate-to-arbitrary-rotation-using-xyzvector/63244 * [skip-ci] alignment * [math] wrap angle into 2pi as suggested by mdessole * [math] for consistency, do the same check in TRotation * Apply formatting * [nfc] format 3d matrix aligned * [test] add test case for GenVector Rotate around axis by angle as suggested by hageboeck * [test] fix dupe variable * [test] fix variable unused * [math] Update pi computation for Windows build Co-authored-by: Bertrand Bellenot <bellenot@users.noreply.github.com> --------- Co-authored-by: mdessole <monicadessole@gmail.com> Co-authored-by: Monica Dessole <36501030+mdessole@users.noreply.github.com> Co-authored-by: Bertrand Bellenot <bellenot@users.noreply.github.com>
1 parent c7dc3dd commit 703a315

File tree

3 files changed

+60
-5
lines changed

3 files changed

+60
-5
lines changed

math/genvector/inc/Math/GenVector/VectorUtil.h

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -275,15 +275,16 @@ namespace ROOT {
275275

276276
// rotation and transformations
277277

278-
279278
/**
280279
rotation along X axis for a generic vector by an Angle alpha
281280
returning a new vector.
282-
The only pre requisite on the Vector is that it has to implement the X() , Y() and Z()
281+
The only pre requisite on the Vector is that it has to implement the X(), Y() and Z()
283282
and SetXYZ methods.
284283
*/
285284
template <class Vector>
286285
Vector RotateX(const Vector & v, double alpha) {
286+
if (std::fmod(alpha, 2 * M_PI) == 0.)
287+
return v;
287288
using std::sin;
288289
double sina = sin(alpha);
289290
using std::cos;
@@ -298,11 +299,13 @@ namespace ROOT {
298299
/**
299300
rotation along Y axis for a generic vector by an Angle alpha
300301
returning a new vector.
301-
The only pre requisite on the Vector is that it has to implement the X() , Y() and Z()
302+
The only pre requisite on the Vector is that it has to implement the X(), Y() and Z()
302303
and SetXYZ methods.
303304
*/
304305
template <class Vector>
305306
Vector RotateY(const Vector & v, double alpha) {
307+
if (std::fmod(alpha, 2 * M_PI) == 0.)
308+
return v;
306309
using std::sin;
307310
double sina = sin(alpha);
308311
using std::cos;
@@ -317,11 +320,13 @@ namespace ROOT {
317320
/**
318321
rotation along Z axis for a generic vector by an Angle alpha
319322
returning a new vector.
320-
The only pre requisite on the Vector is that it has to implement the X() , Y() and Z()
323+
The only pre requisite on the Vector is that it has to implement the X(), Y() and Z()
321324
and SetXYZ methods.
322325
*/
323326
template <class Vector>
324327
Vector RotateZ(const Vector & v, double alpha) {
328+
if (std::fmod(alpha, 2 * M_PI) == 0.)
329+
return v;
325330
using std::sin;
326331
double sina = sin(alpha);
327332
using std::cos;
@@ -333,6 +338,40 @@ namespace ROOT {
333338
return vrot;
334339
}
335340

341+
/**
342+
rotation along a custom axis for a generic vector by an Angle alpha (in rad)
343+
returning a new vector.
344+
The only pre requisite on the Vector is that it has to implement the X(), Y() and Z()
345+
and SetXYZ methods.
346+
*/
347+
template <class Vector>
348+
Vector Rotate(const Vector &v, double alpha, const Vector &axis)
349+
{
350+
if (std::fmod(alpha, 2 * M_PI) == 0.)
351+
return v;
352+
const double ll = std::sqrt(axis.X() * axis.X() + axis.Y() * axis.Y() + axis.Z() * axis.Z());
353+
if (ll == 0.)
354+
GenVector::Throw("Axis Vector has zero magnitude");
355+
const double sa = std::sin(alpha);
356+
const double ca = std::cos(alpha);
357+
const double dx = axis.X() / ll;
358+
const double dy = axis.Y() / ll;
359+
const double dz = axis.Z() / ll;
360+
// clang-format off
361+
const double rot00 = (1 - ca) * dx * dx + ca , rot01 = (1 - ca) * dx * dy - sa * dz, rot02 = (1 - ca) * dx * dz + sa * dy,
362+
rot10 = (1 - ca) * dy * dx + sa * dz, rot11 = (1 - ca) * dy * dy + ca , rot12 = (1 - ca) * dy * dz - sa * dx,
363+
rot20 = (1 - ca) * dz * dx - sa * dy, rot21 = (1 - ca) * dz * dy + sa * dx, rot22 = (1 - ca) * dz * dz + ca ;
364+
// clang-format on
365+
const double xX = v.X();
366+
const double yY = v.Y();
367+
const double zZ = v.Z();
368+
const double x2 = rot00 * xX + rot01 * yY + rot02 * zZ;
369+
const double y2 = rot10 * xX + rot11 * yY + rot12 * zZ;
370+
const double z2 = rot20 * xX + rot21 * yY + rot22 * zZ;
371+
Vector vrot;
372+
vrot.SetXYZ(x2, y2, z2);
373+
return vrot;
374+
}
336375

337376
/**
338377
rotation on a generic vector using a generic rotation class.

math/genvector/test/testGenVector.cxx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,21 @@ int testRotations3D() {
466466
iret |= compare(qr1.Y(), qr2.Y(),"y diff",10 );
467467
iret |= compare(qr1.Z(), qr2.Z(),"z diff",10 );
468468

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

470485
if (iret == 0) std::cout << "\tOK\n";
471486
else std::cout << "\t FAILED\n";

math/physics/src/TRotation.cxx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ TVector3 class:
185185
#include "TRotation.h"
186186
#include "TMath.h"
187187
#include "TQuaternion.h"
188+
#include <cmath>
188189

189190
ClassImp(TRotation);
190191

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

325326
TRotation & TRotation::Rotate(Double_t a, const TVector3& axis) {
326-
if (a != 0.0) {
327+
if (std::fmod(a, 2 * TMath::Pi()) != 0.) {
327328
Double_t ll = axis.Mag();
328329
if (ll == 0.0) {
329330
Warning("Rotate(angle,axis)"," zero axis");

0 commit comments

Comments
 (0)