ROOT  6.07/01
Reference Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
TQuaternion.cxx
Go to the documentation of this file.
1 // @(#)root/physics:$Id$
2 // Author: Eric Anciant 28/06/2005
3 
4 
5 //////////////////////////////////////////////////////////////////////////
6 //____________________
7 //
8 // A Quaternion Class
9 // Begin_html
10 // <p> Quaternion is a 4-component mathematic object quite convenient when dealing with
11 // space rotation (or reference frame transformation). </p>
12 // </p>
13 // <p> In short, think of quaternion Q as a 3-vector augmented by a real number. Q = Q|<sub>r</sub> + Q|<sub>V</sub>
14 //
15 // <p> <u> Quaternion multiplication :</u>
16 // </p>
17 // <p> Quaternion multiplication is given by :
18 // <br> Q.Q' = (Q|<sub>r</sub> + Q|<sub>V</sub> )*( Q'|<sub>r</sub> + Q'|<sub>V</sub>)
19 // <br> = [ Q|<sub>r</sub>*Q'|<sub>r</sub> - Q|<sub>V</sub>*Q'|<sub>V</sub> ] + [ Q|<sub>r</sub>*Q'|<sub>V</sub> + Q'|<sub>r</sub>*Q|<sub>V</sub> + Q|<sub>V</sub> X Q'|<sub>V</sub> ]
20 // <br>
21 // <br> where :
22 // <br> Q|<sub>r</sub>*Q'|<sub>r</sub> is a real number product of real numbers
23 // <br> Q|<sub>V</sub>*Q'|<sub>V</sub> is a real number, scalar product of two 3-vectors
24 // <br> Q|<sub>r</sub>*Q'|<sub>V</sub> is a 3-vector, scaling of a 3-vector by a real number
25 // <br> Q|<sub>V</sub>XQ'|<sub>V</sub> is a 3-vector, cross product of two 3-vectors
26 // <br>
27 // <br> Thus, quaternion product is a generalization of real number product and product of a vector by a real number. Product of two pure vectors gives a quaternion whose real part is the opposite of scalar product and the vector part the cross product.
28 // </p>
29 //
30 // <p> The conjugate of a quaternion Q = Q|<sub>r</sub> + Q|<sub>V</sub> is Q_bar = Q|<sub>r</sub> - Q|<sub>V</sub>
31 // </p>
32 // <p> The magnitude of a quaternion Q is given by |Q|² = Q.Q_bar = Q_bar.Q = Q²|<sub>r</sub> + |Q|<sub>V</sub>|²// </p> // <p> Therefore, the inverse of a quaternion is Q<sup>-1</sup> = Q_bar /|Q|² // </p> // <p> "unit" quaternion is a quaternion of magnitude 1 : |Q|² = 1. // <br> Unit quaternions are a subset of the quaternions set. // </p> // // <p> <u>Quaternion and rotations :</u> // </p> // // <p> A rotation of angle <font face="Symbol">f</font> around a given axis, is represented by a unit quaternion Q : // <br> - The axis of the rotation is given by the vector part of Q. // <br> - The ratio between the magnitude of the vector part and the real part of Q equals tan(<font face="Symbol">f</font>/2). // </p> // <p> In other words : Q = Q|<sub>r</sub> + Q|<sub>V</sub> = cos(<font face="Symbol">f</font>/2) + sin(<font face="Symbol">f</font>/2). // <br> (where u is a unit vector // to the rotation axis, // cos(<font face="Symbol">f</font>/2) is the real part, sin(<font face="Symbol">f</font>/2).u is the vector part) // <br> Note : The quaternion of identity is Q<sub>I</sub> = cos(0) + sin(0)*(any vector) = 1. // </p> // <p> The composition of two rotations is described by the product of the two corresponding quaternions. // <br> As for 3-space rotations, quaternion multiplication is not commutative ! // <br> // <br> Q = Q<sub>1</sub>.Q<sub>2</sub> represents the composition of the successive rotation R1 and R2 expressed in the <b>current</b> frame (the axis of rotation hold by Q<sub>2</sub> is expressed in the frame as it is after R1 rotation). // <br> Q = Q<sub>2</sub>.Q<sub>1</sub> represents the composition of the successive rotation R1 and R2 expressed in the <b>initial</b> reference frame. // </p> // <p> The inverse of a rotation is a rotation about the same axis but of opposite angle, thus if Q is a unit quaternion, // <br> Q = cos(<font face="Symbol">f</font>/2) + sin(<font face="Symbol">f</font>/2).u = Q|<sub>r</sub> + Q|<sub>V</sub>, then : // <br> Q<sup>-1</sup> =cos(-<font face="Symbol">f</font>/2) + sin(-<font face="Symbol">f</font>/2).u = cos(<font face="Symbol">f</font>/2) - sin(<font face="Symbol">f</font>/2).u = Q|<sub>r</sub> -Q|<sub>V</sub> is its inverse quaternion. // </p> // <p> One verifies that : // <br> Q.Q<sup>-1</sup> = Q<sup>-1</sup>.Q = Q|<sub>r</sub>*Q|<sub>r</sub> + Q|<sub>V</sub>*Q|<sub>V</sub> + Q|<sub>r</sub>*Q|<sub>V</sub> -Q|<sub>r</sub>*Q|<sub>V</sub> + Q|<sub>V</sub>XQ|<sub>V</sub> // <br> = Q²|<sub>r</sub> + Q²|<sub>V</sub> = 1 // </p> // <br> // <p> The rotation of a vector V by the rotation described by a unit quaternion Q is obtained by the following operation : V' = Q*V*Q<sup>-1</sup>, considering V as a quaternion whose real part is null. // </p> // <p> <u>Numeric computation considerations :</u> // </p> // <p> Numerically, the quaternion multiplication involves 12 additions and 16 multiplications. // <br> It is therefore faster than 3x3 matrixes multiplication involving 18 additions and 27 multiplications. // <br> // <br> On the contrary, rotation of a vector by the above formula ( Q*V*Q<sup>-1</sup> ) involves 18 additions and 24 multiplications, whereas multiplication of a 3-vector by a 3x3 matrix involves only 6 additions and 9 multiplications. // <br> // <br> When dealing with numerous composition of space rotation, it is therefore faster to use quaternion product. On the other hand if a huge set of vectors must be rotated by a given quaternion, it is more optimized to convert the quaternion into a rotation matrix once, and then use that later to rotate the set of vectors. // </p> // <p> <u>More information :</u> // </p> // <p> // <A HREF="http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation"> // en.wikipedia.org/wiki/Quaternions_and_spatial_rotation </A>. // <br> <br> // <A HREF="http://en.wikipedia.org/wiki/Quaternion"> // en.wikipedia.org/wiki/Quaternion </A>. // </p> // <p> _______________________________________________ // <br> // <p> This Class represents all quaternions (unit or non-unit) // <br> It possesses a Normalize() method to make a given quaternion unit // <br> The Rotate(TVector3&) and Rotation(TVector3&) methods can be used even for a non-unit quaternion, in that case, the proper normalization is applied to perform the rotation. // <br> // <br> A TRotation constructor exists than takes a quaternion for parameter (even non-unit), in that cas the proper normalisation is applied. // </p> // End_html #include "TMath.h" #include "TQuaternion.h" ClassImp(TQuaternion) /****************** CONSTRUCTORS ****************************************************/ //////////////////////////////////////////////////////////////////////////////// TQuaternion::TQuaternion(const TQuaternion & q) : TObject(q), fRealPart(q.fRealPart), fVectorPart(q.fVectorPart) {} TQuaternion::TQuaternion(const TVector3 & vect, Double_t real) : fRealPart(real), fVectorPart(vect) {} TQuaternion::TQuaternion(const Double_t * x0) : fRealPart(x0[3]), fVectorPart(x0) {} TQuaternion::TQuaternion(const Float_t * x0) : fRealPart(x0[3]), fVectorPart(x0) {} TQuaternion::TQuaternion(Double_t real, Double_t X, Double_t Y, Double_t Z) : fRealPart(real), fVectorPart(X,Y,Z) {} TQuaternion::~TQuaternion() {} //////////////////////////////////////////////////////////////////////////////// ///dereferencing operator const Double_t TQuaternion::operator () (int i) const { switch(i) { case 0: case 1: case 2: return fVectorPart(i); case 3: return fRealPart; default: Error("operator()(i)", "bad index (%d) returning 0",i); } return 0.; } //////////////////////////////////////////////////////////////////////////////// ///dereferencing operator Double_t & TQuaternion::operator () (int i) { switch(i) { case 0: case 1: case 2: return fVectorPart(i); case 3: return fRealPart; default: Error("operator()(i)", "bad index (%d) returning &fRealPart",i); } return fRealPart; } //////////////////////////////////////////////////////////////////////////////// /// Get angle of quaternion (rad) /// N.B : this angle is half of the corresponding rotation angle Double_t TQuaternion::GetQAngle() const { if (fRealPart == 0) return TMath::PiOver2(); Double_t denominator = fVectorPart.Mag(); return atan(denominator/fRealPart); } //////////////////////////////////////////////////////////////////////////////// /// Set angle of quaternion (rad) - keep quaternion norm /// N.B : this angle is half of the corresponding rotation angle TQuaternion& TQuaternion::SetQAngle(Double_t angle) { Double_t norm = Norm(); Double_t normSinV = fVectorPart.Mag(); if (normSinV != 0) fVectorPart *= (sin(angle)*norm/normSinV); fRealPart = cos(angle)*norm; return (*this); } //////////////////////////////////////////////////////////////////////////////// /// set quaternion from vector and angle (rad) /// quaternion is set as unitary /// N.B : this angle is half of the corresponding rotation angle TQuaternion& TQuaternion::SetAxisQAngle(TVector3& v,Double_t QAngle) { fVectorPart = v; double norm = v.Mag(); if (norm>0) fVectorPart*=(1./norm); fVectorPart*=sin(QAngle); fRealPart = cos(QAngle); return (*this); } /**************** REAL TO QUATERNION ALGEBRA ****************************************/ //////////////////////////////////////////////////////////////////////////////// /// sum of quaternion with a real TQuaternion TQuaternion::operator+(Double_t real) const { return TQuaternion(fVectorPart, fRealPart + real); } //////////////////////////////////////////////////////////////////////////////// /// substraction of real to quaternion TQuaternion TQuaternion::operator-(Double_t real) const { return TQuaternion(fVectorPart, fRealPart - real); } //////////////////////////////////////////////////////////////////////////////// /// product of quaternion with a real TQuaternion TQuaternion::operator*(Double_t real) const { return TQuaternion(fRealPart*real,fVectorPart.x()*real,fVectorPart.y()*real,fVectorPart.z()*real); } //////////////////////////////////////////////////////////////////////////////// /// division by a real TQuaternion TQuaternion::operator/(Double_t real) const { if (real !=0 ) { return TQuaternion(fRealPart/real,fVectorPart.x()/real,fVectorPart.y()/real,fVectorPart.z()/real); } else { Error("operator/(Double_t)", "bad value (%f) ignored",real); } return (*this); } TQuaternion operator + (Double_t r, const TQuaternion & q) { return (q+r); } TQuaternion operator - (Double_t r, const TQuaternion & q) { return (-q+r); } TQuaternion operator * (Double_t r, const TQuaternion & q) { return (q*r); } TQuaternion operator / (Double_t r, const TQuaternion & q) { return (q.Invert()*r); } /**************** VECTOR TO QUATERNION ALGEBRA ****************************************/ //////////////////////////////////////////////////////////////////////////////// /// sum of quaternion with a real TQuaternion TQuaternion::operator+(const TVector3 &vect) const { return TQuaternion(fVectorPart + vect, fRealPart); } //////////////////////////////////////////////////////////////////////////////// /// substraction of real to quaternion TQuaternion TQuaternion::operator-(const TVector3 &vect) const { return TQuaternion(fVectorPart - vect, fRealPart); } //////////////////////////////////////////////////////////////////////////////// /// left multitplication TQuaternion& TQuaternion::MultiplyLeft(const TVector3 &vect) { Double_t savedRealPart = fRealPart; fRealPart = - (fVectorPart * vect); fVectorPart = vect.Cross(fVectorPart); fVectorPart += (vect * savedRealPart); return (*this); } //////////////////////////////////////////////////////////////////////////////// /// right multiplication TQuaternion& TQuaternion::operator*=(const TVector3 &vect) { Double_t savedRealPart = fRealPart; fRealPart = -(fVectorPart * vect); fVectorPart = fVectorPart.Cross(vect); fVectorPart += (vect * savedRealPart ); return (*this); } //////////////////////////////////////////////////////////////////////////////// /// left product TQuaternion TQuaternion::LeftProduct(const TVector3 &vect) const { return TQuaternion(vect * fRealPart + vect.Cross(fVectorPart), -(fVectorPart * vect)); } //////////////////////////////////////////////////////////////////////////////// /// right product TQuaternion TQuaternion::operator*(const TVector3 &vect) const { return TQuaternion(vect * fRealPart + fVectorPart.Cross(vect), -(fVectorPart * vect)); } //////////////////////////////////////////////////////////////////////////////// /// left division TQuaternion& TQuaternion::DivideLeft(const TVector3 &vect) { Double_t norm2 = vect.Mag2(); MultiplyLeft(vect); if (norm2 > 0 ) { // use (1./nom2) to be numericaly compliant with LeftQuotient(const TVector3 &) (*this) *= -(1./norm2); // minus <- using conjugate of vect } else { Error("DivideLeft(const TVector3)", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// right division TQuaternion& TQuaternion::operator/=(const TVector3 &vect) { Double_t norm2 = vect.Mag2(); (*this) *= vect; if (norm2 > 0 ) { // use (1./real) to be numericaly compliant with operator/(const TVector3 &) (*this) *= - (1./norm2); // minus <- using conjugate of vect } else { Error("operator/=(const TVector3 &)", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// left quotient TQuaternion TQuaternion::LeftQuotient(const TVector3 &vect) const { Double_t norm2 = vect.Mag2(); if (norm2>0) { double invNorm2 = 1./norm2; return TQuaternion((vect * -fRealPart - vect.Cross(fVectorPart))*invNorm2, (fVectorPart * vect ) * invNorm2 ); } else { Error("LeftQuotient(const TVector3 &)", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// right quotient TQuaternion TQuaternion::operator/(const TVector3 &vect) const { Double_t norm2 = vect.Mag2(); if (norm2>0) { double invNorm2 = 1./norm2; return TQuaternion((vect * -fRealPart - fVectorPart.Cross(vect)) * invNorm2, (fVectorPart * vect) * invNorm2 ); } else { Error("operator/(const TVector3 &)", "bad norm2 (%f) ignored",norm2); } return (*this); } TQuaternion operator + (const TVector3 &V, const TQuaternion &Q) { return (Q+V); } TQuaternion operator - (const TVector3 &V, const TQuaternion &Q) { return (-Q+V); } TQuaternion operator * (const TVector3 &V, const TQuaternion &Q) { return Q.LeftProduct(V); } TQuaternion operator / (const TVector3 &vect, const TQuaternion &quat) { //divide operator TQuaternion res(vect); res /= quat; return res; } /**************** QUATERNION ALGEBRA ****************************************/ //////////////////////////////////////////////////////////////////////////////// /// right multiplication TQuaternion& TQuaternion::operator*=(const TQuaternion &quaternion) { Double_t saveRP = fRealPart; TVector3 cross(fVectorPart.Cross(quaternion.fVectorPart)); fRealPart = fRealPart * quaternion.fRealPart - fVectorPart * quaternion.fVectorPart; fVectorPart *= quaternion.fRealPart; fVectorPart += quaternion.fVectorPart * saveRP; fVectorPart += cross; return (*this); } //////////////////////////////////////////////////////////////////////////////// /// left multiplication TQuaternion& TQuaternion::MultiplyLeft(const TQuaternion &quaternion) { Double_t saveRP = fRealPart; TVector3 cross(quaternion.fVectorPart.Cross(fVectorPart)); fRealPart = fRealPart * quaternion.fRealPart - fVectorPart * quaternion.fVectorPart; fVectorPart *= quaternion.fRealPart; fVectorPart += quaternion.fVectorPart * saveRP; fVectorPart += cross; return (*this); } //////////////////////////////////////////////////////////////////////////////// /// left product TQuaternion TQuaternion::LeftProduct(const TQuaternion &quaternion) const { return TQuaternion( fVectorPart*quaternion.fRealPart + quaternion.fVectorPart*fRealPart + quaternion.fVectorPart.Cross(fVectorPart), fRealPart*quaternion.fRealPart - fVectorPart*quaternion.fVectorPart ); } //////////////////////////////////////////////////////////////////////////////// /// right product TQuaternion TQuaternion::operator*(const TQuaternion &quaternion) const { return TQuaternion(fVectorPart*quaternion.fRealPart + quaternion.fVectorPart*fRealPart + fVectorPart.Cross(quaternion.fVectorPart), fRealPart*quaternion.fRealPart - fVectorPart*quaternion.fVectorPart ); } //////////////////////////////////////////////////////////////////////////////// /// left division TQuaternion& TQuaternion::DivideLeft(const TQuaternion &quaternion) { Double_t norm2 = quaternion.Norm2(); if (norm2 > 0 ) { MultiplyLeft(quaternion.Conjugate()); (*this) *= (1./norm2); } else { Error("DivideLeft(const TQuaternion &)", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// right division TQuaternion& TQuaternion::operator/=(const TQuaternion& quaternion) { Double_t norm2 = quaternion.Norm2(); if (norm2 > 0 ) { (*this) *= quaternion.Conjugate(); // use (1./norm2) top be numericaly compliant with operator/(const TQuaternion&) (*this) *= (1./norm2); } else { Error("operator/=(const TQuaternion&)", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// left quotient TQuaternion TQuaternion::LeftQuotient(const TQuaternion& quaternion) const { Double_t norm2 = quaternion.Norm2(); if (norm2 > 0 ) { double invNorm2 = 1./norm2; return TQuaternion( (fVectorPart*quaternion.fRealPart - quaternion.fVectorPart*fRealPart - quaternion.fVectorPart.Cross(fVectorPart)) * invNorm2, (fRealPart*quaternion.fRealPart + fVectorPart*quaternion.fVectorPart)*invNorm2 ); } else { Error("LeftQuotient(const TQuaternion&)", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// right quotient TQuaternion TQuaternion::operator/(const TQuaternion &quaternion) const { Double_t norm2 = quaternion.Norm2(); if (norm2 > 0 ) { double invNorm2 = 1./norm2; return TQuaternion( (fVectorPart*quaternion.fRealPart - quaternion.fVectorPart*fRealPart - fVectorPart.Cross(quaternion.fVectorPart)) * invNorm2, (fRealPart*quaternion.fRealPart + fVectorPart*quaternion.fVectorPart) * invNorm2 ); } else { Error("operator/(const TQuaternion &)", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// invert TQuaternion TQuaternion::Invert() const { double norm2 = Norm2(); if (norm2 > 0 ) { double invNorm2 = 1./norm2; return TQuaternion(fVectorPart*(-invNorm2), fRealPart*invNorm2 ); } else { Error("Invert()", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// rotate vect by current quaternion void TQuaternion::Rotate(TVector3 & vect) const { vect = Rotation(vect); } //////////////////////////////////////////////////////////////////////////////// /// rotation of vect by current quaternion TVector3 TQuaternion::Rotation(const TVector3 & vect) const { // Vres = (*this) * vect * (this->Invert()); double norm2 = Norm2(); if (norm2>0) { TQuaternion quat(*this); quat *= vect; // only compute vect part : (real part has to be 0 ) : // VECT [ quat * ( this->Conjugate() ) ] = quat.fRealPart * -this->fVectorPart // + this->fRealPart * quat.fVectorPart // + quat.fVectorPart X (-this->fVectorPart) TVector3 cross(fVectorPart.Cross(quat.fVectorPart)); quat.fVectorPart *= fRealPart; quat.fVectorPart -= fVectorPart * quat.fRealPart; quat.fVectorPart += cross; return quat.fVectorPart*(1./norm2); } else { Error("Rotation()", "bad norm2 (%f) ignored",norm2); } return vect; } //////////////////////////////////////////////////////////////////////////////// ///Print Quaternion parameters void TQuaternion::Print(Option_t*) const { Printf("%s %s (r,x,y,z)=(%f,%f,%f,%f) \n (alpha,rho,theta,phi)=(%f,%f,%f,%f)",GetName(),GetTitle(), fRealPart,fVectorPart.X(),fVectorPart.Y(),fVectorPart.Z(), GetQAngle()*TMath::RadToDeg(),fVectorPart.Mag(),fVectorPart.Theta()*TMath::RadToDeg(),fVectorPart.Phi()*TMath::RadToDeg()); }
33 // </p>
34 // <p> Therefore, the inverse of a quaternion is Q<sup>-1</sup> = Q_bar /|Q|²// </p> // <p> "unit" quaternion is a quaternion of magnitude 1 : |Q|² = 1. // <br> Unit quaternions are a subset of the quaternions set. // </p> // // <p> <u>Quaternion and rotations :</u> // </p> // // <p> A rotation of angle <font face="Symbol">f</font> around a given axis, is represented by a unit quaternion Q : // <br> - The axis of the rotation is given by the vector part of Q. // <br> - The ratio between the magnitude of the vector part and the real part of Q equals tan(<font face="Symbol">f</font>/2). // </p> // <p> In other words : Q = Q|<sub>r</sub> + Q|<sub>V</sub> = cos(<font face="Symbol">f</font>/2) + sin(<font face="Symbol">f</font>/2). // <br> (where u is a unit vector // to the rotation axis, // cos(<font face="Symbol">f</font>/2) is the real part, sin(<font face="Symbol">f</font>/2).u is the vector part) // <br> Note : The quaternion of identity is Q<sub>I</sub> = cos(0) + sin(0)*(any vector) = 1. // </p> // <p> The composition of two rotations is described by the product of the two corresponding quaternions. // <br> As for 3-space rotations, quaternion multiplication is not commutative ! // <br> // <br> Q = Q<sub>1</sub>.Q<sub>2</sub> represents the composition of the successive rotation R1 and R2 expressed in the <b>current</b> frame (the axis of rotation hold by Q<sub>2</sub> is expressed in the frame as it is after R1 rotation). // <br> Q = Q<sub>2</sub>.Q<sub>1</sub> represents the composition of the successive rotation R1 and R2 expressed in the <b>initial</b> reference frame. // </p> // <p> The inverse of a rotation is a rotation about the same axis but of opposite angle, thus if Q is a unit quaternion, // <br> Q = cos(<font face="Symbol">f</font>/2) + sin(<font face="Symbol">f</font>/2).u = Q|<sub>r</sub> + Q|<sub>V</sub>, then : // <br> Q<sup>-1</sup> =cos(-<font face="Symbol">f</font>/2) + sin(-<font face="Symbol">f</font>/2).u = cos(<font face="Symbol">f</font>/2) - sin(<font face="Symbol">f</font>/2).u = Q|<sub>r</sub> -Q|<sub>V</sub> is its inverse quaternion. // </p> // <p> One verifies that : // <br> Q.Q<sup>-1</sup> = Q<sup>-1</sup>.Q = Q|<sub>r</sub>*Q|<sub>r</sub> + Q|<sub>V</sub>*Q|<sub>V</sub> + Q|<sub>r</sub>*Q|<sub>V</sub> -Q|<sub>r</sub>*Q|<sub>V</sub> + Q|<sub>V</sub>XQ|<sub>V</sub> // <br> = Q²|<sub>r</sub> + Q²|<sub>V</sub> = 1 // </p> // <br> // <p> The rotation of a vector V by the rotation described by a unit quaternion Q is obtained by the following operation : V' = Q*V*Q<sup>-1</sup>, considering V as a quaternion whose real part is null. // </p> // <p> <u>Numeric computation considerations :</u> // </p> // <p> Numerically, the quaternion multiplication involves 12 additions and 16 multiplications. // <br> It is therefore faster than 3x3 matrixes multiplication involving 18 additions and 27 multiplications. // <br> // <br> On the contrary, rotation of a vector by the above formula ( Q*V*Q<sup>-1</sup> ) involves 18 additions and 24 multiplications, whereas multiplication of a 3-vector by a 3x3 matrix involves only 6 additions and 9 multiplications. // <br> // <br> When dealing with numerous composition of space rotation, it is therefore faster to use quaternion product. On the other hand if a huge set of vectors must be rotated by a given quaternion, it is more optimized to convert the quaternion into a rotation matrix once, and then use that later to rotate the set of vectors. // </p> // <p> <u>More information :</u> // </p> // <p> // <A HREF="http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation"> // en.wikipedia.org/wiki/Quaternions_and_spatial_rotation </A>. // <br> <br> // <A HREF="http://en.wikipedia.org/wiki/Quaternion"> // en.wikipedia.org/wiki/Quaternion </A>. // </p> // <p> _______________________________________________ // <br> // <p> This Class represents all quaternions (unit or non-unit) // <br> It possesses a Normalize() method to make a given quaternion unit // <br> The Rotate(TVector3&) and Rotation(TVector3&) methods can be used even for a non-unit quaternion, in that case, the proper normalization is applied to perform the rotation. // <br> // <br> A TRotation constructor exists than takes a quaternion for parameter (even non-unit), in that cas the proper normalisation is applied. // </p> // End_html #include "TMath.h" #include "TQuaternion.h" ClassImp(TQuaternion) /****************** CONSTRUCTORS ****************************************************/ //////////////////////////////////////////////////////////////////////////////// TQuaternion::TQuaternion(const TQuaternion & q) : TObject(q), fRealPart(q.fRealPart), fVectorPart(q.fVectorPart) {} TQuaternion::TQuaternion(const TVector3 & vect, Double_t real) : fRealPart(real), fVectorPart(vect) {} TQuaternion::TQuaternion(const Double_t * x0) : fRealPart(x0[3]), fVectorPart(x0) {} TQuaternion::TQuaternion(const Float_t * x0) : fRealPart(x0[3]), fVectorPart(x0) {} TQuaternion::TQuaternion(Double_t real, Double_t X, Double_t Y, Double_t Z) : fRealPart(real), fVectorPart(X,Y,Z) {} TQuaternion::~TQuaternion() {} //////////////////////////////////////////////////////////////////////////////// ///dereferencing operator const Double_t TQuaternion::operator () (int i) const { switch(i) { case 0: case 1: case 2: return fVectorPart(i); case 3: return fRealPart; default: Error("operator()(i)", "bad index (%d) returning 0",i); } return 0.; } //////////////////////////////////////////////////////////////////////////////// ///dereferencing operator Double_t & TQuaternion::operator () (int i) { switch(i) { case 0: case 1: case 2: return fVectorPart(i); case 3: return fRealPart; default: Error("operator()(i)", "bad index (%d) returning &fRealPart",i); } return fRealPart; } //////////////////////////////////////////////////////////////////////////////// /// Get angle of quaternion (rad) /// N.B : this angle is half of the corresponding rotation angle Double_t TQuaternion::GetQAngle() const { if (fRealPart == 0) return TMath::PiOver2(); Double_t denominator = fVectorPart.Mag(); return atan(denominator/fRealPart); } //////////////////////////////////////////////////////////////////////////////// /// Set angle of quaternion (rad) - keep quaternion norm /// N.B : this angle is half of the corresponding rotation angle TQuaternion& TQuaternion::SetQAngle(Double_t angle) { Double_t norm = Norm(); Double_t normSinV = fVectorPart.Mag(); if (normSinV != 0) fVectorPart *= (sin(angle)*norm/normSinV); fRealPart = cos(angle)*norm; return (*this); } //////////////////////////////////////////////////////////////////////////////// /// set quaternion from vector and angle (rad) /// quaternion is set as unitary /// N.B : this angle is half of the corresponding rotation angle TQuaternion& TQuaternion::SetAxisQAngle(TVector3& v,Double_t QAngle) { fVectorPart = v; double norm = v.Mag(); if (norm>0) fVectorPart*=(1./norm); fVectorPart*=sin(QAngle); fRealPart = cos(QAngle); return (*this); } /**************** REAL TO QUATERNION ALGEBRA ****************************************/ //////////////////////////////////////////////////////////////////////////////// /// sum of quaternion with a real TQuaternion TQuaternion::operator+(Double_t real) const { return TQuaternion(fVectorPart, fRealPart + real); } //////////////////////////////////////////////////////////////////////////////// /// substraction of real to quaternion TQuaternion TQuaternion::operator-(Double_t real) const { return TQuaternion(fVectorPart, fRealPart - real); } //////////////////////////////////////////////////////////////////////////////// /// product of quaternion with a real TQuaternion TQuaternion::operator*(Double_t real) const { return TQuaternion(fRealPart*real,fVectorPart.x()*real,fVectorPart.y()*real,fVectorPart.z()*real); } //////////////////////////////////////////////////////////////////////////////// /// division by a real TQuaternion TQuaternion::operator/(Double_t real) const { if (real !=0 ) { return TQuaternion(fRealPart/real,fVectorPart.x()/real,fVectorPart.y()/real,fVectorPart.z()/real); } else { Error("operator/(Double_t)", "bad value (%f) ignored",real); } return (*this); } TQuaternion operator + (Double_t r, const TQuaternion & q) { return (q+r); } TQuaternion operator - (Double_t r, const TQuaternion & q) { return (-q+r); } TQuaternion operator * (Double_t r, const TQuaternion & q) { return (q*r); } TQuaternion operator / (Double_t r, const TQuaternion & q) { return (q.Invert()*r); } /**************** VECTOR TO QUATERNION ALGEBRA ****************************************/ //////////////////////////////////////////////////////////////////////////////// /// sum of quaternion with a real TQuaternion TQuaternion::operator+(const TVector3 &vect) const { return TQuaternion(fVectorPart + vect, fRealPart); } //////////////////////////////////////////////////////////////////////////////// /// substraction of real to quaternion TQuaternion TQuaternion::operator-(const TVector3 &vect) const { return TQuaternion(fVectorPart - vect, fRealPart); } //////////////////////////////////////////////////////////////////////////////// /// left multitplication TQuaternion& TQuaternion::MultiplyLeft(const TVector3 &vect) { Double_t savedRealPart = fRealPart; fRealPart = - (fVectorPart * vect); fVectorPart = vect.Cross(fVectorPart); fVectorPart += (vect * savedRealPart); return (*this); } //////////////////////////////////////////////////////////////////////////////// /// right multiplication TQuaternion& TQuaternion::operator*=(const TVector3 &vect) { Double_t savedRealPart = fRealPart; fRealPart = -(fVectorPart * vect); fVectorPart = fVectorPart.Cross(vect); fVectorPart += (vect * savedRealPart ); return (*this); } //////////////////////////////////////////////////////////////////////////////// /// left product TQuaternion TQuaternion::LeftProduct(const TVector3 &vect) const { return TQuaternion(vect * fRealPart + vect.Cross(fVectorPart), -(fVectorPart * vect)); } //////////////////////////////////////////////////////////////////////////////// /// right product TQuaternion TQuaternion::operator*(const TVector3 &vect) const { return TQuaternion(vect * fRealPart + fVectorPart.Cross(vect), -(fVectorPart * vect)); } //////////////////////////////////////////////////////////////////////////////// /// left division TQuaternion& TQuaternion::DivideLeft(const TVector3 &vect) { Double_t norm2 = vect.Mag2(); MultiplyLeft(vect); if (norm2 > 0 ) { // use (1./nom2) to be numericaly compliant with LeftQuotient(const TVector3 &) (*this) *= -(1./norm2); // minus <- using conjugate of vect } else { Error("DivideLeft(const TVector3)", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// right division TQuaternion& TQuaternion::operator/=(const TVector3 &vect) { Double_t norm2 = vect.Mag2(); (*this) *= vect; if (norm2 > 0 ) { // use (1./real) to be numericaly compliant with operator/(const TVector3 &) (*this) *= - (1./norm2); // minus <- using conjugate of vect } else { Error("operator/=(const TVector3 &)", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// left quotient TQuaternion TQuaternion::LeftQuotient(const TVector3 &vect) const { Double_t norm2 = vect.Mag2(); if (norm2>0) { double invNorm2 = 1./norm2; return TQuaternion((vect * -fRealPart - vect.Cross(fVectorPart))*invNorm2, (fVectorPart * vect ) * invNorm2 ); } else { Error("LeftQuotient(const TVector3 &)", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// right quotient TQuaternion TQuaternion::operator/(const TVector3 &vect) const { Double_t norm2 = vect.Mag2(); if (norm2>0) { double invNorm2 = 1./norm2; return TQuaternion((vect * -fRealPart - fVectorPart.Cross(vect)) * invNorm2, (fVectorPart * vect) * invNorm2 ); } else { Error("operator/(const TVector3 &)", "bad norm2 (%f) ignored",norm2); } return (*this); } TQuaternion operator + (const TVector3 &V, const TQuaternion &Q) { return (Q+V); } TQuaternion operator - (const TVector3 &V, const TQuaternion &Q) { return (-Q+V); } TQuaternion operator * (const TVector3 &V, const TQuaternion &Q) { return Q.LeftProduct(V); } TQuaternion operator / (const TVector3 &vect, const TQuaternion &quat) { //divide operator TQuaternion res(vect); res /= quat; return res; } /**************** QUATERNION ALGEBRA ****************************************/ //////////////////////////////////////////////////////////////////////////////// /// right multiplication TQuaternion& TQuaternion::operator*=(const TQuaternion &quaternion) { Double_t saveRP = fRealPart; TVector3 cross(fVectorPart.Cross(quaternion.fVectorPart)); fRealPart = fRealPart * quaternion.fRealPart - fVectorPart * quaternion.fVectorPart; fVectorPart *= quaternion.fRealPart; fVectorPart += quaternion.fVectorPart * saveRP; fVectorPart += cross; return (*this); } //////////////////////////////////////////////////////////////////////////////// /// left multiplication TQuaternion& TQuaternion::MultiplyLeft(const TQuaternion &quaternion) { Double_t saveRP = fRealPart; TVector3 cross(quaternion.fVectorPart.Cross(fVectorPart)); fRealPart = fRealPart * quaternion.fRealPart - fVectorPart * quaternion.fVectorPart; fVectorPart *= quaternion.fRealPart; fVectorPart += quaternion.fVectorPart * saveRP; fVectorPart += cross; return (*this); } //////////////////////////////////////////////////////////////////////////////// /// left product TQuaternion TQuaternion::LeftProduct(const TQuaternion &quaternion) const { return TQuaternion( fVectorPart*quaternion.fRealPart + quaternion.fVectorPart*fRealPart + quaternion.fVectorPart.Cross(fVectorPart), fRealPart*quaternion.fRealPart - fVectorPart*quaternion.fVectorPart ); } //////////////////////////////////////////////////////////////////////////////// /// right product TQuaternion TQuaternion::operator*(const TQuaternion &quaternion) const { return TQuaternion(fVectorPart*quaternion.fRealPart + quaternion.fVectorPart*fRealPart + fVectorPart.Cross(quaternion.fVectorPart), fRealPart*quaternion.fRealPart - fVectorPart*quaternion.fVectorPart ); } //////////////////////////////////////////////////////////////////////////////// /// left division TQuaternion& TQuaternion::DivideLeft(const TQuaternion &quaternion) { Double_t norm2 = quaternion.Norm2(); if (norm2 > 0 ) { MultiplyLeft(quaternion.Conjugate()); (*this) *= (1./norm2); } else { Error("DivideLeft(const TQuaternion &)", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// right division TQuaternion& TQuaternion::operator/=(const TQuaternion& quaternion) { Double_t norm2 = quaternion.Norm2(); if (norm2 > 0 ) { (*this) *= quaternion.Conjugate(); // use (1./norm2) top be numericaly compliant with operator/(const TQuaternion&) (*this) *= (1./norm2); } else { Error("operator/=(const TQuaternion&)", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// left quotient TQuaternion TQuaternion::LeftQuotient(const TQuaternion& quaternion) const { Double_t norm2 = quaternion.Norm2(); if (norm2 > 0 ) { double invNorm2 = 1./norm2; return TQuaternion( (fVectorPart*quaternion.fRealPart - quaternion.fVectorPart*fRealPart - quaternion.fVectorPart.Cross(fVectorPart)) * invNorm2, (fRealPart*quaternion.fRealPart + fVectorPart*quaternion.fVectorPart)*invNorm2 ); } else { Error("LeftQuotient(const TQuaternion&)", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// right quotient TQuaternion TQuaternion::operator/(const TQuaternion &quaternion) const { Double_t norm2 = quaternion.Norm2(); if (norm2 > 0 ) { double invNorm2 = 1./norm2; return TQuaternion( (fVectorPart*quaternion.fRealPart - quaternion.fVectorPart*fRealPart - fVectorPart.Cross(quaternion.fVectorPart)) * invNorm2, (fRealPart*quaternion.fRealPart + fVectorPart*quaternion.fVectorPart) * invNorm2 ); } else { Error("operator/(const TQuaternion &)", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// invert TQuaternion TQuaternion::Invert() const { double norm2 = Norm2(); if (norm2 > 0 ) { double invNorm2 = 1./norm2; return TQuaternion(fVectorPart*(-invNorm2), fRealPart*invNorm2 ); } else { Error("Invert()", "bad norm2 (%f) ignored",norm2); } return (*this); } //////////////////////////////////////////////////////////////////////////////// /// rotate vect by current quaternion void TQuaternion::Rotate(TVector3 & vect) const { vect = Rotation(vect); } //////////////////////////////////////////////////////////////////////////////// /// rotation of vect by current quaternion TVector3 TQuaternion::Rotation(const TVector3 & vect) const { // Vres = (*this) * vect * (this->Invert()); double norm2 = Norm2(); if (norm2>0) { TQuaternion quat(*this); quat *= vect; // only compute vect part : (real part has to be 0 ) : // VECT [ quat * ( this->Conjugate() ) ] = quat.fRealPart * -this->fVectorPart // + this->fRealPart * quat.fVectorPart // + quat.fVectorPart X (-this->fVectorPart) TVector3 cross(fVectorPart.Cross(quat.fVectorPart)); quat.fVectorPart *= fRealPart; quat.fVectorPart -= fVectorPart * quat.fRealPart; quat.fVectorPart += cross; return quat.fVectorPart*(1./norm2); } else { Error("Rotation()", "bad norm2 (%f) ignored",norm2); } return vect; } //////////////////////////////////////////////////////////////////////////////// ///Print Quaternion parameters void TQuaternion::Print(Option_t*) const { Printf("%s %s (r,x,y,z)=(%f,%f,%f,%f) \n (alpha,rho,theta,phi)=(%f,%f,%f,%f)",GetName(),GetTitle(), fRealPart,fVectorPart.X(),fVectorPart.Y(),fVectorPart.Z(), GetQAngle()*TMath::RadToDeg(),fVectorPart.Mag(),fVectorPart.Theta()*TMath::RadToDeg(),fVectorPart.Phi()*TMath::RadToDeg()); }
35 // </p>
36 // <p> "unit" quaternion is a quaternion of magnitude 1 : |Q|² = 1.
37 // <br> Unit quaternions are a subset of the quaternions set.
38 // </p>
39 //
40 // <p> <u>Quaternion and rotations :</u>
41 // </p>
42 //
43 // <p> A rotation of angle <font face="Symbol">f</font> around a given axis, is represented by a unit quaternion Q :
44 // <br> - The axis of the rotation is given by the vector part of Q.
45 // <br> - The ratio between the magnitude of the vector part and the real part of Q equals tan(<font face="Symbol">f</font>/2).
46 // </p>
47 // <p> In other words : Q = Q|<sub>r</sub> + Q|<sub>V</sub> = cos(<font face="Symbol">f</font>/2) + sin(<font face="Symbol">f</font>/2).
48 // <br> (where u is a unit vector // to the rotation axis,
49 // cos(<font face="Symbol">f</font>/2) is the real part, sin(<font face="Symbol">f</font>/2).u is the vector part)
50 // <br> Note : The quaternion of identity is Q<sub>I</sub> = cos(0) + sin(0)*(any vector) = 1.
51 // </p>
52 // <p> The composition of two rotations is described by the product of the two corresponding quaternions.
53 // <br> As for 3-space rotations, quaternion multiplication is not commutative !
54 // <br>
55 // <br> Q = Q<sub>1</sub>.Q<sub>2</sub> represents the composition of the successive rotation R1 and R2 expressed in the <b>current</b> frame (the axis of rotation hold by Q<sub>2</sub> is expressed in the frame as it is after R1 rotation).
56 // <br> Q = Q<sub>2</sub>.Q<sub>1</sub> represents the composition of the successive rotation R1 and R2 expressed in the <b>initial</b> reference frame.
57 // </p>
58 // <p> The inverse of a rotation is a rotation about the same axis but of opposite angle, thus if Q is a unit quaternion,
59 // <br> Q = cos(<font face="Symbol">f</font>/2) + sin(<font face="Symbol">f</font>/2).u = Q|<sub>r</sub> + Q|<sub>V</sub>, then :
60 // <br> Q<sup>-1</sup> =cos(-<font face="Symbol">f</font>/2) + sin(-<font face="Symbol">f</font>/2).u = cos(<font face="Symbol">f</font>/2) - sin(<font face="Symbol">f</font>/2).u = Q|<sub>r</sub> -Q|<sub>V</sub> is its inverse quaternion.
61 // </p>
62 // <p> One verifies that :
63 // <br> Q.Q<sup>-1</sup> = Q<sup>-1</sup>.Q = Q|<sub>r</sub>*Q|<sub>r</sub> + Q|<sub>V</sub>*Q|<sub>V</sub> + Q|<sub>r</sub>*Q|<sub>V</sub> -Q|<sub>r</sub>*Q|<sub>V</sub> + Q|<sub>V</sub>XQ|<sub>V</sub>
64 // <br> = Q²|<sub>r</sub> + Q²|<sub>V</sub> = 1
65 // </p>
66 // <br>
67 // <p> The rotation of a vector V by the rotation described by a unit quaternion Q is obtained by the following operation : V' = Q*V*Q<sup>-1</sup>, considering V as a quaternion whose real part is null.
68 // </p>
69 // <p> <u>Numeric computation considerations :</u>
70 // </p>
71 // <p> Numerically, the quaternion multiplication involves 12 additions and 16 multiplications.
72 // <br> It is therefore faster than 3x3 matrixes multiplication involving 18 additions and 27 multiplications.
73 // <br>
74 // <br> On the contrary, rotation of a vector by the above formula ( Q*V*Q<sup>-1</sup> ) involves 18 additions and 24 multiplications, whereas multiplication of a 3-vector by a 3x3 matrix involves only 6 additions and 9 multiplications.
75 // <br>
76 // <br> When dealing with numerous composition of space rotation, it is therefore faster to use quaternion product. On the other hand if a huge set of vectors must be rotated by a given quaternion, it is more optimized to convert the quaternion into a rotation matrix once, and then use that later to rotate the set of vectors.
77 // </p>
78 // <p> <u>More information :</u>
79 // </p>
80 // <p>
81 // <A HREF="http://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation">
82 // en.wikipedia.org/wiki/Quaternions_and_spatial_rotation </A>.
83 // <br> <br>
84 // <A HREF="http://en.wikipedia.org/wiki/Quaternion">
85 // en.wikipedia.org/wiki/Quaternion </A>.
86 // </p>
87 // <p> _______________________________________________
88 // <br>
89 // <p> This Class represents all quaternions (unit or non-unit)
90 // <br> It possesses a Normalize() method to make a given quaternion unit
91 // <br> The Rotate(TVector3&) and Rotation(TVector3&) methods can be used even for a non-unit quaternion, in that case, the proper normalization is applied to perform the rotation.
92 // <br>
93 // <br> A TRotation constructor exists than takes a quaternion for parameter (even non-unit), in that cas the proper normalisation is applied.
94 // </p>
95 // End_html
96 
97 #include "TMath.h"
98 #include "TQuaternion.h"
99 
101 
102 /****************** CONSTRUCTORS ****************************************************/
103 ////////////////////////////////////////////////////////////////////////////////
104 
106  fRealPart(q.fRealPart), fVectorPart(q.fVectorPart) {}
107 
109  : fRealPart(real), fVectorPart(vect) {}
110 
112  : fRealPart(x0[3]), fVectorPart(x0) {}
113 
115  : fRealPart(x0[3]), fVectorPart(x0) {}
116 
118  : fRealPart(real), fVectorPart(X,Y,Z) {}
119 
121 
122 ////////////////////////////////////////////////////////////////////////////////
123 ///dereferencing operator const
124 
126  switch(i) {
127  case 0:
128  case 1:
129  case 2:
130  return fVectorPart(i);
131  case 3:
132  return fRealPart;
133  default:
134  Error("operator()(i)", "bad index (%d) returning 0",i);
135  }
136  return 0.;
137 }
138 
139 ////////////////////////////////////////////////////////////////////////////////
140 ///dereferencing operator
141 
143  switch(i) {
144  case 0:
145  case 1:
146  case 2:
147  return fVectorPart(i);
148  case 3:
149  return fRealPart;
150  default:
151  Error("operator()(i)", "bad index (%d) returning &fRealPart",i);
152  }
153  return fRealPart;
154 }
155 ////////////////////////////////////////////////////////////////////////////////
156 /// Get angle of quaternion (rad)
157 /// N.B : this angle is half of the corresponding rotation angle
158 
160  if (fRealPart == 0) return TMath::PiOver2();
161  Double_t denominator = fVectorPart.Mag();
162  return atan(denominator/fRealPart);
163 }
164 
165 ////////////////////////////////////////////////////////////////////////////////
166 /// Set angle of quaternion (rad) - keep quaternion norm
167 /// N.B : this angle is half of the corresponding rotation angle
168 
170  Double_t norm = Norm();
171  Double_t normSinV = fVectorPart.Mag();
172  if (normSinV != 0) fVectorPart *= (sin(angle)*norm/normSinV);
173  fRealPart = cos(angle)*norm;
174 
175  return (*this);
176 }
177 
178 ////////////////////////////////////////////////////////////////////////////////
179 /// set quaternion from vector and angle (rad)
180 /// quaternion is set as unitary
181 /// N.B : this angle is half of the corresponding rotation angle
182 
184  fVectorPart = v;
185  double norm = v.Mag();
186  if (norm>0) fVectorPart*=(1./norm);
187  fVectorPart*=sin(QAngle);
188  fRealPart = cos(QAngle);
189 
190  return (*this);
191 }
192 
193 /**************** REAL TO QUATERNION ALGEBRA ****************************************/
194 
195 ////////////////////////////////////////////////////////////////////////////////
196 /// sum of quaternion with a real
197 
199  return TQuaternion(fVectorPart, fRealPart + real);
200 }
201 
202 ////////////////////////////////////////////////////////////////////////////////
203 /// substraction of real to quaternion
204 
206  return TQuaternion(fVectorPart, fRealPart - real);
207 }
208 
209 ////////////////////////////////////////////////////////////////////////////////
210 /// product of quaternion with a real
211 
213  return TQuaternion(fRealPart*real,fVectorPart.x()*real,fVectorPart.y()*real,fVectorPart.z()*real);
214 }
215 
216 
217 ////////////////////////////////////////////////////////////////////////////////
218 /// division by a real
219 
221  if (real !=0 ) {
222  return TQuaternion(fRealPart/real,fVectorPart.x()/real,fVectorPart.y()/real,fVectorPart.z()/real);
223  } else {
224  Error("operator/(Double_t)", "bad value (%f) ignored",real);
225  }
226 
227  return (*this);
228 }
229 
230 TQuaternion operator + (Double_t r, const TQuaternion & q) { return (q+r); }
231 TQuaternion operator - (Double_t r, const TQuaternion & q) { return (-q+r); }
232 TQuaternion operator * (Double_t r, const TQuaternion & q) { return (q*r); }
233 TQuaternion operator / (Double_t r, const TQuaternion & q) { return (q.Invert()*r); }
234 
235 /**************** VECTOR TO QUATERNION ALGEBRA ****************************************/
236 
237 ////////////////////////////////////////////////////////////////////////////////
238 /// sum of quaternion with a real
239 
241  return TQuaternion(fVectorPart + vect, fRealPart);
242 }
243 
244 ////////////////////////////////////////////////////////////////////////////////
245 /// substraction of real to quaternion
246 
248  return TQuaternion(fVectorPart - vect, fRealPart);
249 }
250 
251 ////////////////////////////////////////////////////////////////////////////////
252 /// left multitplication
253 
255  Double_t savedRealPart = fRealPart;
256  fRealPart = - (fVectorPart * vect);
257  fVectorPart = vect.Cross(fVectorPart);
258  fVectorPart += (vect * savedRealPart);
259 
260  return (*this);
261 }
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 /// right multiplication
265 
267  Double_t savedRealPart = fRealPart;
268  fRealPart = -(fVectorPart * vect);
269  fVectorPart = fVectorPart.Cross(vect);
270  fVectorPart += (vect * savedRealPart );
271 
272  return (*this);
273 }
274 
275 ////////////////////////////////////////////////////////////////////////////////
276 /// left product
277 
279  return TQuaternion(vect * fRealPart + vect.Cross(fVectorPart), -(fVectorPart * vect));
280 }
281 
282 ////////////////////////////////////////////////////////////////////////////////
283 /// right product
284 
286  return TQuaternion(vect * fRealPart + fVectorPart.Cross(vect), -(fVectorPart * vect));
287 }
288 
289 ////////////////////////////////////////////////////////////////////////////////
290 /// left division
291 
293  Double_t norm2 = vect.Mag2();
294  MultiplyLeft(vect);
295  if (norm2 > 0 ) {
296  // use (1./nom2) to be numericaly compliant with LeftQuotient(const TVector3 &)
297  (*this) *= -(1./norm2); // minus <- using conjugate of vect
298  } else {
299  Error("DivideLeft(const TVector3)", "bad norm2 (%f) ignored",norm2);
300  }
301  return (*this);
302 }
303 
304 ////////////////////////////////////////////////////////////////////////////////
305 /// right division
306 
308  Double_t norm2 = vect.Mag2();
309  (*this) *= vect;
310  if (norm2 > 0 ) {
311  // use (1./real) to be numericaly compliant with operator/(const TVector3 &)
312  (*this) *= - (1./norm2); // minus <- using conjugate of vect
313  } else {
314  Error("operator/=(const TVector3 &)", "bad norm2 (%f) ignored",norm2);
315  }
316  return (*this);
317 }
318 
319 ////////////////////////////////////////////////////////////////////////////////
320 /// left quotient
321 
323  Double_t norm2 = vect.Mag2();
324 
325  if (norm2>0) {
326  double invNorm2 = 1./norm2;
327  return TQuaternion((vect * -fRealPart - vect.Cross(fVectorPart))*invNorm2,
328  (fVectorPart * vect ) * invNorm2 );
329  } else {
330  Error("LeftQuotient(const TVector3 &)", "bad norm2 (%f) ignored",norm2);
331  }
332  return (*this);
333 }
334 
335 ////////////////////////////////////////////////////////////////////////////////
336 /// right quotient
337 
339  Double_t norm2 = vect.Mag2();
340 
341  if (norm2>0) {
342  double invNorm2 = 1./norm2;
343  return TQuaternion((vect * -fRealPart - fVectorPart.Cross(vect)) * invNorm2,
344  (fVectorPart * vect) * invNorm2 );
345  } else {
346  Error("operator/(const TVector3 &)", "bad norm2 (%f) ignored",norm2);
347  }
348  return (*this);
349 }
350 
351 TQuaternion operator + (const TVector3 &V, const TQuaternion &Q) { return (Q+V); }
352 TQuaternion operator - (const TVector3 &V, const TQuaternion &Q) { return (-Q+V); }
353 TQuaternion operator * (const TVector3 &V, const TQuaternion &Q) { return Q.LeftProduct(V); }
354 
355 TQuaternion operator / (const TVector3 &vect, const TQuaternion &quat) {
356  //divide operator
357  TQuaternion res(vect);
358  res /= quat;
359  return res;
360 }
361 
362 /**************** QUATERNION ALGEBRA ****************************************/
363 
364 ////////////////////////////////////////////////////////////////////////////////
365 /// right multiplication
366 
368  Double_t saveRP = fRealPart;
370 
371  fRealPart = fRealPart * quaternion.fRealPart - fVectorPart * quaternion.fVectorPart;
372 
373  fVectorPart *= quaternion.fRealPart;
374  fVectorPart += quaternion.fVectorPart * saveRP;
375  fVectorPart += cross;
376  return (*this);
377 }
378 
379 ////////////////////////////////////////////////////////////////////////////////
380 /// left multiplication
381 
383  Double_t saveRP = fRealPart;
385 
386  fRealPart = fRealPart * quaternion.fRealPart - fVectorPart * quaternion.fVectorPart;
387 
388  fVectorPart *= quaternion.fRealPart;
389  fVectorPart += quaternion.fVectorPart * saveRP;
390  fVectorPart += cross;
391 
392  return (*this);
393 }
394 
395 ////////////////////////////////////////////////////////////////////////////////
396 /// left product
397 
399  return TQuaternion( fVectorPart*quaternion.fRealPart + quaternion.fVectorPart*fRealPart
400  + quaternion.fVectorPart.Cross(fVectorPart),
401  fRealPart*quaternion.fRealPart - fVectorPart*quaternion.fVectorPart );
402 }
403 
404 ////////////////////////////////////////////////////////////////////////////////
405 /// right product
406 
408  return TQuaternion(fVectorPart*quaternion.fRealPart + quaternion.fVectorPart*fRealPart
409  + fVectorPart.Cross(quaternion.fVectorPart),
410  fRealPart*quaternion.fRealPart - fVectorPart*quaternion.fVectorPart );
411 }
412 
413 ////////////////////////////////////////////////////////////////////////////////
414 /// left division
415 
417  Double_t norm2 = quaternion.Norm2();
418 
419  if (norm2 > 0 ) {
420  MultiplyLeft(quaternion.Conjugate());
421  (*this) *= (1./norm2);
422  } else {
423  Error("DivideLeft(const TQuaternion &)", "bad norm2 (%f) ignored",norm2);
424  }
425  return (*this);
426 }
427 
428 ////////////////////////////////////////////////////////////////////////////////
429 /// right division
430 
432  Double_t norm2 = quaternion.Norm2();
433 
434  if (norm2 > 0 ) {
435  (*this) *= quaternion.Conjugate();
436  // use (1./norm2) top be numericaly compliant with operator/(const TQuaternion&)
437  (*this) *= (1./norm2);
438  } else {
439  Error("operator/=(const TQuaternion&)", "bad norm2 (%f) ignored",norm2);
440  }
441  return (*this);
442 }
443 
444 ////////////////////////////////////////////////////////////////////////////////
445 /// left quotient
446 
448  Double_t norm2 = quaternion.Norm2();
449 
450  if (norm2 > 0 ) {
451  double invNorm2 = 1./norm2;
452  return TQuaternion(
453  (fVectorPart*quaternion.fRealPart - quaternion.fVectorPart*fRealPart
454  - quaternion.fVectorPart.Cross(fVectorPart)) * invNorm2,
455  (fRealPart*quaternion.fRealPart + fVectorPart*quaternion.fVectorPart)*invNorm2 );
456  } else {
457  Error("LeftQuotient(const TQuaternion&)", "bad norm2 (%f) ignored",norm2);
458  }
459  return (*this);
460 }
461 
462 ////////////////////////////////////////////////////////////////////////////////
463 /// right quotient
464 
466  Double_t norm2 = quaternion.Norm2();
467 
468  if (norm2 > 0 ) {
469  double invNorm2 = 1./norm2;
470  return TQuaternion(
471  (fVectorPart*quaternion.fRealPart - quaternion.fVectorPart*fRealPart
472  - fVectorPart.Cross(quaternion.fVectorPart)) * invNorm2,
473  (fRealPart*quaternion.fRealPart + fVectorPart*quaternion.fVectorPart) * invNorm2 );
474  } else {
475  Error("operator/(const TQuaternion &)", "bad norm2 (%f) ignored",norm2);
476  }
477  return (*this);
478 }
479 
480 ////////////////////////////////////////////////////////////////////////////////
481 /// invert
482 
484  double norm2 = Norm2();
485  if (norm2 > 0 ) {
486  double invNorm2 = 1./norm2;
487  return TQuaternion(fVectorPart*(-invNorm2), fRealPart*invNorm2 );
488  } else {
489  Error("Invert()", "bad norm2 (%f) ignored",norm2);
490  }
491  return (*this);
492 }
493 
494 ////////////////////////////////////////////////////////////////////////////////
495 /// rotate vect by current quaternion
496 
497 void TQuaternion::Rotate(TVector3 & vect) const {
498  vect = Rotation(vect);
499 }
500 
501 ////////////////////////////////////////////////////////////////////////////////
502 /// rotation of vect by current quaternion
503 
505  // Vres = (*this) * vect * (this->Invert());
506  double norm2 = Norm2();
507 
508  if (norm2>0) {
509  TQuaternion quat(*this);
510  quat *= vect;
511 
512  // only compute vect part : (real part has to be 0 ) :
513  // VECT [ quat * ( this->Conjugate() ) ] = quat.fRealPart * -this->fVectorPart
514  // + this->fRealPart * quat.fVectorPart
515  // + quat.fVectorPart X (-this->fVectorPart)
517  quat.fVectorPart *= fRealPart;
518  quat.fVectorPart -= fVectorPart * quat.fRealPart;
519  quat.fVectorPart += cross;
520 
521  return quat.fVectorPart*(1./norm2);
522  } else {
523  Error("Rotation()", "bad norm2 (%f) ignored",norm2);
524  }
525  return vect;
526 }
527 
528 ////////////////////////////////////////////////////////////////////////////////
529 ///Print Quaternion parameters
530 
532 {
533  Printf("%s %s (r,x,y,z)=(%f,%f,%f,%f) \n (alpha,rho,theta,phi)=(%f,%f,%f,%f)",GetName(),GetTitle(),
536 }
Double_t y() const
Definition: TVector3.h:218
Double_t Phi() const
return the azimuth angle. returns phi from -pi to pi
Definition: TVector3.cxx:282
TQuaternion LeftQuotient(const TVector3 &vector) const
left quotient
Double_t Z() const
Definition: TVector3.h:222
Double_t z() const
Definition: TVector3.h:219
TVector3 cross(const TVector3 &v1, const TVector3 &v2)
Definition: CsgOps.cxx:816
float Float_t
Definition: RtypesCore.h:53
const char Option_t
Definition: RtypesCore.h:62
Double_t Theta() const
return the polar angle
Definition: TVector3.cxx:290
TVector3 fVectorPart
Definition: TQuaternion.h:115
TQuaternion operator-() const
Definition: TQuaternion.h:283
TQuaternion operator*(Double_t real) const
product of quaternion with a real
TQuaternion operator+(Double_t real) const
sum of quaternion with a real
void Rotate(TVector3 &vect) const
rotate vect by current quaternion
Double_t RadToDeg()
Definition: TMath.h:49
TQuaternion & SetQAngle(Double_t angle)
Set angle of quaternion (rad) - keep quaternion norm N.B : this angle is half of the corresponding ro...
double cos(double)
Double_t Norm() const
Definition: TQuaternion.h:269
Double_t Mag() const
return the magnitude (rho in spherical coordinate system)
Definition: TVector3.cxx:257
TQuaternion operator/(Double_t r, const TQuaternion &q)
TQuaternion & operator/=(Double_t real)
Definition: TQuaternion.h:180
virtual ~TQuaternion()
TQuaternion operator/(Double_t real) const
division by a real
TQuaternion LeftProduct(const TVector3 &vector) const
left product
TQuaternion & DivideLeft(const TVector3 &vector)
left division
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:918
double sin(double)
void Print(Option_t *option="") const
Print Quaternion parameters.
TQuaternion operator+(Double_t r, const TQuaternion &q)
TQuaternion & operator*=(Double_t real)
Definition: TQuaternion.h:174
TQuaternion Conjugate() const
Definition: TQuaternion.h:287
ROOT::R::TRInterface & r
Definition: Object.C:4
SVector< double, 2 > v
Definition: Dict.h:5
TQuaternion(Double_t real=0, Double_t X=0, Double_t Y=0, Double_t Z=0)
TQuaternion & SetAxisQAngle(TVector3 &v, Double_t QAngle)
set quaternion from vector and angle (rad) quaternion is set as unitary N.B : this angle is half of t...
Double_t X() const
Definition: TVector3.h:220
Double_t x() const
Definition: TVector3.h:217
Double_t Mag2() const
Definition: TVector3.h:298
Double_t operator()(int) const
dereferencing operator const
#define Printf
Definition: TGeoToOCC.h:18
TQuaternion operator-(Double_t r, const TQuaternion &q)
TQuaternion & MultiplyLeft(const TVector3 &vector)
left multitplication
TVector3 Rotation(const TVector3 &vect) const
rotation of vect by current quaternion
virtual const char * GetName() const
Returns name of object.
Definition: TObject.cxx:415
double Double_t
Definition: RtypesCore.h:55
double atan(double)
Double_t GetQAngle() const
Get angle of quaternion (rad) N.B : this angle is half of the corresponding rotation angle...
ClassImp(TQuaternion) TQuaternion
Mother of all ROOT objects.
Definition: TObject.h:58
Double_t PiOver2()
Definition: TMath.h:46
TQuaternion Invert() const
invert
Double_t fRealPart
Definition: TQuaternion.h:114
TVector3 Cross(const TVector3 &) const
Definition: TVector3.h:294
Double_t Y() const
Definition: TVector3.h:221
std::complex< float_v > Z
Definition: main.cpp:120
float * q
Definition: THbookFile.cxx:87
virtual const char * GetTitle() const
Returns title of object.
Definition: TObject.cxx:459
double norm(double *x, double *p)
Definition: unuranDistr.cxx:40
TQuaternion operator*(Double_t r, const TQuaternion &q)
Double_t Norm2() const
Definition: TQuaternion.h:273
static double Q[]