src/vamos/geometry/Three_Matrix.cc

Go to the documentation of this file.
00001 //  Vamos Automotive Simulator
00002 //  Copyright (C) 2001--2002 Sam Varner
00003 //
00004 //  This program is free software; you can redistribute it and/or modify
00005 //  it under the terms of the GNU General Public License as published by
00006 //  the Free Software Foundation; either version 2 of the License, or
00007 //  (at your option) any later version.
00008 //
00009 //  This program is distributed in the hope that it will be useful,
00010 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 //  GNU General Public License for more details.
00013 //
00014 //  You should have received a copy of the GNU General Public License
00015 //  along with this program; if not, write to the Free Software
00016 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 #include <vamos/geometry/Three_Matrix.h>
00019 
00020 #include <cmath>
00021 
00022 namespace Vamos_Geometry
00023 {
00024   void rotate_elements (double mat [3][3], int i, int j, int k, int l, 
00025                         double h, double s, double tau);
00026 
00027   void swap (double& a, double& b);
00028 }
00029 
00030 Vamos_Geometry::
00031 Three_Matrix::Three_Matrix (double diag)
00032 {
00033   zero ();
00034   set_diagonal (diag);
00035 }
00036 
00037 Vamos_Geometry::
00038 Three_Matrix::Three_Matrix (const double mat_in [3][3])
00039 {
00040   for (int i = 0; i < 3; i++)
00041     {
00042       for (int j = 0; j < 3; j++)
00043         {
00044           m_mat [i][j] = mat_in [i][j];
00045         }
00046     }
00047 }
00048 
00049 Vamos_Geometry::
00050 Three_Matrix::Three_Matrix (const Three_Matrix& mat)
00051 {
00052   copy_in (mat);
00053 }
00054 
00055 Vamos_Geometry::Three_Matrix& Vamos_Geometry::
00056 Three_Matrix::operator = (const Three_Matrix& mat)
00057 {
00058   if (&mat != this)
00059     {
00060       copy_in (mat);
00061     }
00062   return *this;
00063 }
00064 
00065 void Vamos_Geometry::
00066 Three_Matrix::copy_in (const Three_Matrix& mat)
00067 {
00068   for (int i = 0; i < 3; i++)
00069     {
00070       for (int j = 0; j < 3; j++)
00071         {
00072           m_mat [i][j] = mat [i][j];
00073         }
00074     }
00075 }
00076 
00077 Vamos_Geometry::Three_Vector Vamos_Geometry::
00078 Three_Matrix::unit (int index) const
00079 {
00080   return Three_Vector (m_mat [0][index], m_mat [1][index], m_mat [2][index]);
00081 }
00082 
00083 void Vamos_Geometry::
00084 Three_Matrix::set_diagonal (double diag)
00085 {
00086   for (int i = 0; i < 3; i++)
00087     {
00088       m_mat [i][i] = diag;
00089     }
00090 }
00091 
00092 void Vamos_Geometry::
00093 Three_Matrix::identity ()
00094 {
00095   zero ();
00096   set_diagonal (1.0);
00097 }
00098 
00099 void Vamos_Geometry::
00100 Three_Matrix::zero ()
00101 {
00102   for (int i = 0; i < 3; i++)
00103     {
00104       for (int j = 0; j < 3; j++)
00105         {
00106           m_mat [i][j] = 0.0;
00107         }
00108     }
00109 }
00110 
00111 void Vamos_Geometry::
00112 Three_Matrix::rotate (const Three_Vector& delta_theta)
00113 {
00114   double angle = delta_theta.abs (); // in radians
00115   if (angle == 0.0)
00116     return;
00117 
00118   Three_Vector unit = delta_theta / angle * sin (angle / 2.0);
00119   double w = cos (angle / 2.0);
00120 
00121   // This tranformation matrix is derived from quaternion analysis.
00122   Three_Matrix q_rot;
00123   double x = unit [0];
00124   double y = unit [1];
00125   double z = unit [2];
00126 
00127   q_rot [0][0] = 1.0 - 2.0 * (y*y + z*z);
00128   q_rot [0][1] = 2.0 * (x*y - w*z);
00129   q_rot [0][2] = 2.0 * (x*z + w*y);
00130 
00131   q_rot [1][0] = 2.0 * (x*y + w*z);
00132   q_rot [1][1] = 1.0 - 2.0 * (x*x + z*z);
00133   q_rot [1][2] = 2.0 * (y*z - w*x);
00134 
00135   q_rot [2][0] = 2.0 * (x*z - w*y);
00136   q_rot [2][1] = 2.0 * (y*z + w*x);
00137   q_rot [2][2] = 1.0 - 2.0 * (x*x + y*y);
00138   // Note that the matrix is not symmetric.  However, since x, y, and
00139   // z are imaginary (although we treat them as real here) and w is
00140   // real, the transformation matrix is Hermetian (equal to its
00141   // complex conjugate transpose).
00142 
00143   *this *= q_rot;
00144 }
00145 
00146 void Vamos_Geometry::
00147 Three_Matrix::diagonalize ()
00148 {
00149   const int dim = 3; 
00150 
00151   int rotations = 0;
00152   double array_z [dim] = {0.0};
00153   double array_b [dim];
00154   double mat [dim][dim];
00155   
00156   for (int i = 0; i < dim; i++)
00157     {
00158       for (int j = 0; j < dim; j++)
00159         {
00160           mat [i][j] = m_mat [i][j];
00161           m_e_vec [i][j] = 0.0;
00162         }
00163       array_b [i] = m_mat [i][i];
00164       m_e_val [i] = m_mat [i][i];
00165       m_e_vec [i][i] = 1.0;
00166     }
00167 
00168   for (int iter = 0; iter < 50; iter++)
00169     {
00170       double off_diag = 0.0;
00171       for (int i = 0; i < (dim - 1); i++)
00172         {
00173           for (int j = i + 1; j < dim; j++)
00174             {
00175               off_diag += mat [i][j];
00176             }
00177         }
00178       if (off_diag == 0.0)
00179         break;
00180 
00181       double thresh = (iter < 4) ? (0.2 * off_diag / (dim * dim)) : 0.0;
00182 
00183       for (int row = 0; row < (dim - 1); row++)
00184         {
00185           for (int col = row + 1; col < dim; col++) 
00186             {
00187               double smalln = 100.0 * std::abs (mat [row][col]);
00188               if ((iter > 4) 
00189                   && (std::abs (m_e_val [row] + smalln) 
00190                       == std::abs (m_e_val [row]))
00191                   && (std::abs (m_e_val [col] + smalln) 
00192                       == std::abs (m_e_val [col])))
00193                 {
00194                   mat [row][col] = 0.0;
00195                 }
00196               else if (std::abs (mat [row][col]) > thresh)
00197                 {
00198                   double param_h = m_e_val [col] - m_e_val [row];
00199                   double param_t;
00200                   if (std::abs (param_h) + smalln == std::abs (param_h))
00201                     {
00202                       param_t = mat [row][col] / param_h;
00203                     }
00204                   else
00205                     {
00206                       double theta = 0.5 * param_h / mat [row][col];
00207                       param_t = 1.0 / (std::abs (theta) + 
00208                                        sqrt (1.0 + theta * theta));
00209                       if (theta < 0.0)
00210                         param_t = -param_t;
00211                     }
00212                   double param_c = 1.0 / sqrt (1.0 + param_t * param_t);
00213                   double param_s = param_t * param_c;
00214                   double tau = param_s / (1.0 + param_c);
00215 
00216                   param_h = param_t * mat [row][col];
00217                   array_z [row] -= param_h;
00218                   array_z [col] += param_h;
00219                   m_e_val [row] -= param_h;
00220                   m_e_val [col] += param_h;
00221                   mat [row][col] = 0.0;
00222 
00223                   // Rotate the matrix.
00224                   for (int j = 0; j < row; j++)
00225                     rotate_elements (mat, j, row, j, col, 
00226                                      param_h, param_s, tau);
00227                   for (int j = row + 1; j < col; j++)
00228                     rotate_elements (mat, row, j, j, col, 
00229                                      param_h, param_s, tau);
00230                   for (int j = col + 1; j < dim; j++)
00231                     rotate_elements (mat, row, j, col, j, 
00232                                      param_h, param_s, tau);
00233                   // Rotate the eigenvectors.
00234                   for (int j = 0; j < dim; j++)
00235                     rotate_elements (m_e_vec, j, row, j, col, 
00236                                      param_h, param_s, tau);
00237 
00238                   rotations++;
00239                 }
00240             }
00241         }
00242       for (int i = 0; i < dim; i++)
00243         {
00244           array_b [i] += array_z [i];
00245           m_e_val [i] = array_b [i];
00246           array_z [i] = 0.0;
00247         }
00248     }
00249 }
00250     
00251 void 
00252 Vamos_Geometry::rotate_elements (double mat [3][3], int i, int j, int k, int l, 
00253                                  double param_h, double param_s, double tau)
00254 {
00255   double param_g = mat [i][j];
00256   param_h = mat [k][l];
00257   mat [i][j] = param_g - param_s * (param_h + param_g * tau);
00258   mat [k][l] = param_h + param_s * (param_g - param_h * tau);
00259 }
00260 
00261 Vamos_Geometry::Three_Matrix Vamos_Geometry::
00262 Three_Matrix::eigen (Three_Vector* out_vec)
00263 {
00264   diagonalize ();
00265   if (out_vec)
00266     *out_vec = Three_Vector (m_e_val);
00267   return Three_Matrix (m_e_vec).transpose ();
00268 }
00269 
00270 Vamos_Geometry::Three_Matrix& Vamos_Geometry::
00271 Three_Matrix::operator *= (double factor)
00272 {
00273   for (int i = 0; i < 3; i++)
00274     {
00275       for (int j = 0; j < 3; j++)
00276         {
00277           m_mat [i][j] *= factor;
00278         }
00279     }
00280   return *this;
00281 }
00282 
00283 Vamos_Geometry::Three_Matrix& Vamos_Geometry::
00284 Three_Matrix::operator *= (const Three_Matrix& mat2)
00285 {
00286   double temp_mat [3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};
00287   for (int i = 0; i < 3; i++)
00288     {
00289       for (int j = 0; j < 3; j++)
00290         {
00291           for (int k = 0; k < 3; k++)
00292             {
00293               temp_mat [i][j] += m_mat [i][k] * mat2 [k][j];
00294             }
00295         }
00296     }
00297   for (int i = 0; i < 3; i++)
00298     {
00299       for (int j = 0; j < 3; j++)
00300         {
00301           m_mat [i][j] = temp_mat [i][j];
00302         }
00303     }
00304   return *this;
00305 }
00306 
00307 const Vamos_Geometry::Three_Vector 
00308 Vamos_Geometry::operator * (const Three_Vector& vec, const Three_Matrix& mat)
00309 {
00310   double out_vec [3] = {0.0, 0.0, 0.0};
00311   for (int i = 0; i < 3; i++)
00312     {
00313       for (int j = 0; j < 3; j++)
00314         {
00315           out_vec [i] += vec [j] * mat [j][i];
00316         }
00317     }
00318   return Three_Vector (out_vec);
00319 }
00320 
00321 const Vamos_Geometry::Three_Matrix 
00322 Vamos_Geometry::operator * (const Three_Matrix& mat1, const Three_Matrix& mat2)
00323 {
00324   double out_mat [3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};
00325   for (int i = 0; i < 3; i++)
00326     {
00327       for (int j = 0; j < 3; j++)
00328         {
00329           for (int k = 0; k < 3; k++)
00330             {
00331               out_mat [i][j] += mat1 [i][k] * mat2 [k][j];
00332             }
00333         }
00334     }
00335   return Three_Matrix (out_mat);
00336 }
00337 
00338 const Vamos_Geometry::Three_Matrix 
00339 Vamos_Geometry::operator * (double factor, const Three_Matrix& mat)
00340 {
00341   Three_Matrix out_mat = mat;
00342   return out_mat *= factor;
00343 }
00344 
00345 const Vamos_Geometry::Three_Matrix 
00346 Vamos_Geometry::operator * (const Three_Matrix& mat, double factor)
00347 {
00348   return factor * mat;
00349 }
00350 
00351 // Stream operators.
00352 std::ostream& 
00353 Vamos_Geometry::operator << (std::ostream& os, Three_Matrix mat)
00354 {
00355   os << "[[ " << mat [0][0] 
00356      << ",\t" << mat [0][1]
00357      << ",\t" << mat [0][2] << "]\n"
00358      << " [ " << mat [1][0] 
00359      << ",\t" << mat [1][1]
00360      << ",\t" << mat [1][2] << "]\n"
00361      << " [ " << mat [2][0] 
00362      << ",\t" << mat [2][1]
00363      << ",\t" << mat [2][2] << "]]";
00364   return os;
00365 }
00366 
00367 Vamos_Geometry::Three_Matrix Vamos_Geometry::
00368 Three_Matrix::transpose () const
00369 {
00370   Three_Matrix out_mat (m_mat);
00371   out_mat [0][1] = m_mat [1][0];
00372   out_mat [1][0] = m_mat [0][1];
00373   out_mat [0][2] = m_mat [2][0];
00374   out_mat [2][0] = m_mat [0][2];
00375   out_mat [1][2] = m_mat [2][1];
00376   out_mat [2][1] = m_mat [1][2];
00377   return out_mat;
00378 }
00379 
00380 void 
00381 Vamos_Geometry::swap (double& a, double& b)
00382 {
00383   double temp = a;
00384   a = b;
00385   b = temp;
00386 }
00387 
00388 Vamos_Geometry::Three_Matrix Vamos_Geometry::
00389 Three_Matrix::invert () const
00390 {
00391   double det
00392     = m_mat [0][0] * m_mat [1][1] * m_mat [2][2]
00393     + m_mat [0][1] * m_mat [1][2] * m_mat [2][0]
00394     + m_mat [0][2] * m_mat [1][0] * m_mat [2][1]
00395     - m_mat [0][2] * m_mat [1][1] * m_mat [2][0]
00396     - m_mat [0][1] * m_mat [1][0] * m_mat [2][2]
00397     - m_mat [0][0] * m_mat [1][2] * m_mat [2][1];
00398   
00399   if (det == 0.0)
00400     {
00401       throw Singular_Matrix ();
00402     }
00403   
00404   // A^{-1} = C^T / det(A)
00405   // A^{-1}_{ij} = C_{ji} / det(A)
00406   // where C_{ji} is the cofactor of the A_{ji}.
00407   // See Boas p.122-123.
00408   Three_Matrix out_mat;
00409   out_mat [0][0] =
00410     (m_mat [1][1] * m_mat [2][2] - m_mat [1][2] * m_mat [2][1]) / det;
00411   out_mat [1][0] =
00412     (m_mat [1][2] * m_mat [2][0] - m_mat [1][0] * m_mat [2][2]) / det;
00413   out_mat [2][0] =
00414     (m_mat [1][0] * m_mat [2][1] - m_mat [1][1] * m_mat [2][0]) / det;
00415   out_mat [0][1] =
00416     (m_mat [2][1] * m_mat [0][2] - m_mat [2][2] * m_mat [0][1]) / det;
00417   out_mat [1][1] =
00418     (m_mat [2][2] * m_mat [0][0] - m_mat [2][0] * m_mat [0][2]) / det;
00419   out_mat [2][1] =
00420     (m_mat [2][0] * m_mat [0][1] - m_mat [2][1] * m_mat [0][0]) / det;
00421   out_mat [0][2] =
00422     (m_mat [0][1] * m_mat [1][2] - m_mat [0][2] * m_mat [1][1]) / det;
00423   out_mat [1][2] =
00424     (m_mat [0][2] * m_mat [1][0] - m_mat [0][0] * m_mat [1][2]) / det;
00425   out_mat [2][2] = 
00426     (m_mat [0][0] * m_mat [1][1] - m_mat [0][1] * m_mat [1][0]) / det;
00427   
00428   return out_mat;
00429 }
00430 
00431 // Return the Euler angles about the x (PHI), y (THETA), and z (PSI)
00432 // axes for the orientation matrix MAT.
00433 void
00434 Vamos_Geometry::euler_angles (const Three_Matrix& mat, 
00435                               double* phi, double* theta, double* psi)
00436 {
00437   *theta = asin (mat [2][0]);
00438 
00439   if (std::abs (*theta) > 0.00001)
00440     {
00441       double cos_theta = cos (*theta);
00442       double tr_x = mat [2][2] / cos_theta;
00443       double tr_y = -mat [2][1] / cos_theta;
00444       
00445       *phi = atan2 (tr_y, tr_x);
00446       
00447       tr_x = mat [0][0] / cos_theta;
00448       tr_y = mat [1][0] / cos_theta;
00449       
00450       *psi = atan2 (tr_y, tr_x);
00451     }
00452   else
00453     {
00454       *phi = 0.0;
00455       
00456       double tr_x = mat [1][1];
00457       double tr_y = -mat [0][1];
00458         
00459       *psi = atan2 (tr_y, tr_x);
00460     }
00461 }

Generated on Thu Oct 19 04:05:55 2006 by  doxygen 1.4.6