00001 // @(#)root/mathcore:$Id: Rotation3D.cxx 22516 2008-03-07 15:14:26Z moneta $ 00002 // Authors: W. Brown, M. Fischler, L. Moneta 2005 00003 00004 /********************************************************************** 00005 * * 00006 * Copyright (c) 2005 , LCG ROOT FNAL MathLib Team * 00007 * * 00008 * * 00009 **********************************************************************/ 00010 00011 // Header file for class Rotation in 3 dimensions, represented by 3x3 matrix 00012 // 00013 // Created by: Mark Fischler Tues July 5 2005 00014 // 00015 #include "Math/GenVector/Rotation3D.h" 00016 00017 #include <cmath> 00018 #include <algorithm> 00019 00020 #include "Math/GenVector/Cartesian3D.h" 00021 #include "Math/GenVector/DisplacementVector3D.h" 00022 00023 namespace ROOT { 00024 00025 namespace Math { 00026 00027 // ========== Constructors and Assignment ===================== 00028 00029 Rotation3D::Rotation3D() 00030 { 00031 // constructor of a identity rotation 00032 fM[kXX] = 1.0; fM[kXY] = 0.0; fM[kXZ] = 0.0; 00033 fM[kYX] = 0.0; fM[kYY] = 1.0; fM[kYZ] = 0.0; 00034 fM[kZX] = 0.0; fM[kZY] = 0.0; fM[kZZ] = 1.0; 00035 } 00036 00037 00038 void Rotation3D::Rectify() 00039 { 00040 // rectify rotation matrix (make orthogonal) 00041 // The "nearest" orthogonal matrix X to a nearly-orthogonal matrix A 00042 // (in the sense that X is exaclty orthogonal and the sum of the squares 00043 // of the element differences X-A is as small as possible) is given by 00044 // X = A * inverse(sqrt(A.transpose()*A.inverse())). 00045 00046 // Step 1 -- form symmetric M = A.transpose * A 00047 00048 double m11 = fM[kXX]*fM[kXX] + fM[kYX]*fM[kYX] + fM[kZX]*fM[kZX]; 00049 double m12 = fM[kXX]*fM[kXY] + fM[kYX]*fM[kYY] + fM[kZX]*fM[kZY]; 00050 double m13 = fM[kXX]*fM[kXZ] + fM[kYX]*fM[kYZ] + fM[kZX]*fM[kZZ]; 00051 double m22 = fM[kXY]*fM[kXY] + fM[kYY]*fM[kYY] + fM[kZY]*fM[kZY]; 00052 double m23 = fM[kXY]*fM[kXZ] + fM[kYY]*fM[kYZ] + fM[kZY]*fM[kZZ]; 00053 double m33 = fM[kXZ]*fM[kXZ] + fM[kYZ]*fM[kYZ] + fM[kZZ]*fM[kZZ]; 00054 00055 // Step 2 -- find lower-triangular U such that U * U.transpose = M 00056 00057 double u11 = std::sqrt(m11); 00058 double u21 = m12/u11; 00059 double u31 = m13/u11; 00060 double u22 = std::sqrt(m22-u21*u21); 00061 double u32 = (m23-m12*m13/m11)/u22; 00062 double u33 = std::sqrt(m33 - u31*u31 - u32*u32); 00063 00064 00065 // Step 3 -- find V such that V*V = U. U is also lower-triangular 00066 00067 double v33 = 1/u33; 00068 double v32 = -v33*u32/u22; 00069 double v31 = -(v32*u21+v33*u31)/u11; 00070 double v22 = 1/u22; 00071 double v21 = -v22*u21/u11; 00072 double v11 = 1/u11; 00073 00074 00075 // Step 4 -- N = V.transpose * V is inverse(sqrt(A.transpose()*A.inverse())) 00076 00077 double n11 = v11*v11 + v21*v21 + v31*v31; 00078 double n12 = v11*v21 + v21*v22 + v31*v32; 00079 double n13 = v11*v31 + v21*v32 + v31*v33; 00080 double n22 = v21*v21 + v22*v22 + v32*v32; 00081 double n23 = v21*v31 + v22*v32 + v32*v33; 00082 double n33 = v31*v31 + v32*v32 + v33*v33; 00083 00084 00085 // Step 5 -- The new matrix is A * N 00086 00087 double mA[9]; 00088 std::copy(fM, &fM[9], mA); 00089 00090 fM[kXX] = mA[kXX]*n11 + mA[kXY]*n12 + mA[kXZ]*n13; 00091 fM[kXY] = mA[kXX]*n12 + mA[kXY]*n22 + mA[kXZ]*n23; 00092 fM[kXZ] = mA[kXX]*n13 + mA[kXY]*n23 + mA[kXZ]*n33; 00093 fM[kYX] = mA[kYX]*n11 + mA[kYY]*n12 + mA[kYZ]*n13; 00094 fM[kYY] = mA[kYX]*n12 + mA[kYY]*n22 + mA[kYZ]*n23; 00095 fM[kYZ] = mA[kYX]*n13 + mA[kYY]*n23 + mA[kYZ]*n33; 00096 fM[kZX] = mA[kZX]*n11 + mA[kZY]*n12 + mA[kZZ]*n13; 00097 fM[kZY] = mA[kZX]*n12 + mA[kZY]*n22 + mA[kZZ]*n23; 00098 fM[kZZ] = mA[kZX]*n13 + mA[kZY]*n23 + mA[kZZ]*n33; 00099 00100 00101 } // Rectify() 00102 00103 00104 static inline void swap(double & a, double & b) { 00105 // swap two values 00106 double t=b; b=a; a=t; 00107 } 00108 00109 void Rotation3D::Invert() { 00110 // invert a rotation 00111 swap (fM[kXY], fM[kYX]); 00112 swap (fM[kXZ], fM[kZX]); 00113 swap (fM[kYZ], fM[kZY]); 00114 } 00115 00116 00117 Rotation3D Rotation3D::operator * (const AxisAngle & a) const { 00118 // combine with an AxisAngle rotation 00119 return operator* ( Rotation3D(a) ); 00120 } 00121 00122 Rotation3D Rotation3D::operator * (const EulerAngles & e) const { 00123 // combine with an EulerAngles rotation 00124 return operator* ( Rotation3D(e) ); 00125 } 00126 00127 Rotation3D Rotation3D::operator * (const Quaternion & q) const { 00128 // combine with a Quaternion rotation 00129 return operator* ( Rotation3D(q) ); 00130 } 00131 00132 Rotation3D Rotation3D::operator * (const RotationZYX & r) const { 00133 // combine with a RotastionZYX rotation 00134 return operator* ( Rotation3D(r) ); 00135 } 00136 00137 std::ostream & operator<< (std::ostream & os, const Rotation3D & r) { 00138 // TODO - this will need changing for machine-readable issues 00139 // and even the human readable form needs formatting improvements 00140 double m[9]; 00141 r.GetComponents(m, m+9); 00142 os << "\n" << m[0] << " " << m[1] << " " << m[2]; 00143 os << "\n" << m[3] << " " << m[4] << " " << m[5]; 00144 os << "\n" << m[6] << " " << m[7] << " " << m[8] << "\n"; 00145 return os; 00146 } 00147 00148 } //namespace Math 00149 } //namespace ROOT