cmtkMatrix3x3.cxx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2009 Torsten Rohlfing
00004 //
00005 //  Copyright 2004-2010 SRI International
00006 //
00007 //  This file is part of the Computational Morphometry Toolkit.
00008 //
00009 //  http://www.nitrc.org/projects/cmtk/
00010 //
00011 //  The Computational Morphometry Toolkit is free software: you can
00012 //  redistribute it and/or modify it under the terms of the GNU General Public
00013 //  License as published by the Free Software Foundation, either version 3 of
00014 //  the License, or (at your option) any later version.
00015 //
00016 //  The Computational Morphometry Toolkit is distributed in the hope that it
00017 //  will be useful, but WITHOUT ANY WARRANTY; without even the implied
00018 //  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 //  GNU General Public License for more details.
00020 //
00021 //  You should have received a copy of the GNU General Public License along
00022 //  with the Computational Morphometry Toolkit.  If not, see
00023 //  <http://www.gnu.org/licenses/>.
00024 //
00025 //  $Revision: 2398 $
00026 //
00027 //  $LastChangedDate: 2010-10-05 14:54:37 -0700 (Tue, 05 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include "cmtkMatrix3x3.h"
00034 
00035 #include <System/cmtkConsole.h>
00036 #include <Base/cmtkMathUtil.h>
00037 
00038 #include <string.h>
00039 #include <math.h>
00040 
00041 namespace
00042 cmtk
00043 {
00044 
00047 
00048 template<class T>
00049 Matrix3x3<T>::Matrix3x3()
00050 {
00051   memset( Matrix, 0, sizeof( Matrix ) );
00052   Matrix[0][0] = Matrix[1][1] = Matrix[2][2] = 1.0;
00053 }
00054 
00055 template<class T>
00056 Matrix3x3<T>::Matrix3x3( const Self& other )
00057 {
00058   memcpy( this->Matrix, other.Matrix, sizeof( this->Matrix ) );
00059 }
00060 
00061 template<class T>
00062 Matrix3x3<T>&
00063 Matrix3x3<T>::Set( const T *const values )
00064 {
00065   memcpy( this->Matrix, values, sizeof( this->Matrix ) );
00066   return *this;
00067 }
00068 
00069 template<class T>
00070 Matrix3x3<T>&
00071 Matrix3x3<T>::Fill( const T value )
00072 {
00073   for ( int i = 0; i < 3; ++i )
00074     for ( int j = 0; j < 3; ++j )
00075       this->Matrix[i][j] = value;
00076   return *this;
00077 }
00078 
00079 template<class T>
00080 Matrix3x3<T>&
00081 Matrix3x3<T>::Compose( const Types::Coordinate params[8] )
00082 {
00083   const Units::Radians alpha = Units::Degrees( params[2] );
00084 
00085   this->Matrix[0][0] = static_cast<T>(  MathUtil::Cos( alpha ) * params[3] );
00086   this->Matrix[0][1] = static_cast<T>( -MathUtil::Sin( alpha ) * params[3] );
00087   this->Matrix[0][2] = static_cast<T>( 0.0 );
00088   this->Matrix[1][0] = static_cast<T>(  MathUtil::Sin( alpha ) * params[4] );
00089   this->Matrix[1][1] = static_cast<T>(  MathUtil::Cos( alpha ) * params[4] );
00090   this->Matrix[1][2] = static_cast<T>( 0.0 );
00091   this->Matrix[2][0] = static_cast<T>( 0.0 );
00092   this->Matrix[2][1] = static_cast<T>( 0.0 );
00093   this->Matrix[2][2] = static_cast<T>( 1.0 );
00094 
00095   // generate shears
00096   Self shearMatrix;
00097   shearMatrix[0][1] = static_cast<T>( params[5] );
00098   *this *= shearMatrix;
00099 
00100   // transform rotation center
00101   Types::Coordinate cM[2] = 
00102     {
00103       params[6]*this->Matrix[0][0] + params[7]*this->Matrix[1][0],
00104       params[6]*this->Matrix[0][1] + params[7]*this->Matrix[1][1],
00105     };
00106   
00107   // set translations
00108   this->Matrix[2][0] = static_cast<T>( params[0] - cM[0] + params[6] );
00109   this->Matrix[2][1] = static_cast<T>( params[1] - cM[1] + params[7] );
00110 
00111   return *this;
00112 }
00113 
00120 template<class T>
00121 bool
00122 Matrix3x3<T>::Decompose
00123 ( Types::Coordinate params[8], const Types::Coordinate *center ) const
00124 {
00125   // make a working copy of the matrix for step-by-step decomposition
00126   Types::Coordinate matrix[3][3];
00127   memcpy( matrix, Matrix, sizeof( matrix ) );
00128 
00129   // translation entries
00130   params[0] = matrix[2][0];
00131   params[1] = matrix[2][1];
00132 
00133   if ( center ) 
00134     {
00135     Types::Coordinate cM[2] = { center[0]*matrix[0][0] + center[1]*matrix[1][0], center[0]*matrix[0][1] + center[1]*matrix[1][1] };
00136   
00137     params[0] += cM[0] - center[0];
00138     params[1] += cM[1] - center[1];
00139 
00140     memcpy( params+6, center, 2*sizeof( Types::Coordinate ) );
00141     }
00142   else
00143     {
00144     memset( params+6, 0, 2*sizeof( Types::Coordinate ) );
00145     }
00146 
00147 #define IGS_EPSILON 0.001
00148   for ( int i=0; i<2; ++i ) 
00149     {
00150     // scale
00151     params[3+i] = sqrt( MathUtil::Square( matrix[i][0] ) + MathUtil::Square( matrix[i][1] ) );
00152 
00153     // report error on singular matrices.
00154     if ( fabs(params[3+i]) < IGS_EPSILON ) 
00155       {
00156       StdErr <<"igsMatrxi3x3::Decompose encountered singular matrix.";
00157       return false;
00158       }
00159     }
00160 
00161   // rotation
00162   // first rotate about y axis
00163   double x2 = matrix[0][0] / params[3];
00164   double y2 = -matrix[0][1] / params[3];
00165     
00166   double dot = x2 * x2 + y2 * y2;
00167   double d1 = sqrt (dot);
00168 
00169   double cosTheta, sinTheta;
00170   if (d1 < IGS_EPSILON) 
00171     {
00172     cosTheta = 1.0;
00173     sinTheta = 0.0;
00174     }
00175   else 
00176     {
00177     cosTheta = x2 / d1;
00178     sinTheta = y2 / d1;
00179     }
00180     
00181   params[2] = static_cast<T>( Units::Degrees( MathUtil::ArcTan2 (sinTheta, cosTheta) ).Value() );
00182     
00183   return true;
00184 #undef IGS_EPSILON
00185 }
00186 
00187 template<class T>
00188 Matrix3x3<T>
00189 Matrix3x3<T>::GetTranspose() const
00190 {
00191   Self transpose;
00192   for ( int i = 0; i < 3; ++i ) 
00193     {
00194     for ( int j = 0; j < 3; ++j )
00195       transpose[i][j] = this->Matrix[j][i];
00196     }
00197   return transpose;
00198 }
00199   
00200 template<class T>
00201 Matrix3x3<T>&
00202 Matrix3x3<T>::Invert2x2()
00203 {
00204   Self inverse;
00205   
00206   T rowBuff[3];
00207   for ( int col = 0; col<3; ++col ) 
00208     {    
00209     int pivIdx = col;
00210     T pivAbs = fabs( this->Matrix[col][col] );
00211 
00212     for ( int row = col+1; row<2; ++row ) // 2 to exclude last row!
00213       {
00214       T nextAbs = fabs( this->Matrix[row][col] );
00215       if (nextAbs > pivAbs ) 
00216         {
00217         pivIdx = row;
00218         pivAbs = nextAbs;
00219         }
00220       }
00221     
00222     if ( col != pivIdx )
00223       {
00224       memcpy( rowBuff, this->Matrix[col], sizeof(rowBuff) );
00225       memcpy( this->Matrix[col], this->Matrix[pivIdx], sizeof(rowBuff) );
00226       memcpy( this->Matrix[pivIdx], rowBuff, sizeof(rowBuff) );
00227       
00228       memcpy( rowBuff, inverse[col],sizeof(rowBuff));
00229       memcpy( inverse[col], inverse[pivIdx], sizeof(rowBuff) );
00230       memcpy( inverse[pivIdx], rowBuff, sizeof(rowBuff) );
00231       }
00232     
00233     for ( int c=0; c<3; ++c ) 
00234       {
00235       if (c>col )
00236         this->Matrix[col][c] /= this->Matrix[col][col];
00237       inverse[col][c] /= this->Matrix[col][col];
00238       }
00239     this->Matrix[col][col] = 1.0;
00240     
00241     for ( int row = 0; row<3; ++row ) 
00242       {
00243       if (row != col ) 
00244         {
00245         for ( int c=0; c<3; ++c ) 
00246           {
00247           if ( c>col ) 
00248             this->Matrix[row][c] -= 
00249               this->Matrix[row][col] * this->Matrix[col][c];
00250           inverse[row][c] -= this->Matrix[row][col] * inverse[col][c];
00251           }
00252         this->Matrix[row][col] = 0;
00253         }
00254       }
00255     }
00256   
00257   // finally copy inverse into this object.
00258   return (*this = inverse);
00259 }
00260 
00261 template<class T>
00262 Matrix3x3<T>&
00263 Matrix3x3<T>::Invert3x3()
00264 {
00265   Self inverse;
00266   
00267   T rowBuff[3];
00268   for ( int col = 0; col<3; ++col ) {
00269 
00270     int pivIdx = col;
00271     T pivAbs = fabs( this->Matrix[col][col] );
00272 
00273     for ( int row = col+1; row<3; ++row ) {
00274       T nextAbs = fabs( this->Matrix[row][col] );
00275       if (nextAbs > pivAbs ) {
00276         pivIdx = row;
00277         pivAbs = nextAbs;
00278       }
00279     }
00280 
00281     if ( col != pivIdx )
00282       {
00283       memcpy( rowBuff, this->Matrix[col], sizeof(rowBuff) );
00284       memcpy( this->Matrix[col], this->Matrix[pivIdx], sizeof(rowBuff) );
00285       memcpy( this->Matrix[pivIdx], rowBuff, sizeof(rowBuff) );
00286 
00287       memcpy( rowBuff, inverse[col],sizeof(rowBuff));
00288       memcpy( inverse[col], inverse[pivIdx], sizeof(rowBuff) );
00289       memcpy( inverse[pivIdx], rowBuff, sizeof(rowBuff) );
00290       }
00291     
00292     for ( int c=0; c<3; ++c ) 
00293       {
00294       if (c>col )
00295         this->Matrix[col][c] /= this->Matrix[col][col];
00296       inverse[col][c] /= this->Matrix[col][col];
00297       }
00298     this->Matrix[col][col] = 1.0;
00299     
00300     for ( int row = 0; row<3; ++row ) 
00301       {
00302       if (row != col ) 
00303         {
00304         for ( int c=0; c<3; ++c ) 
00305           {
00306           if ( c>col ) 
00307             this->Matrix[row][c] -= this->Matrix[row][col] * this->Matrix[col][c];
00308           inverse[row][c] -= this->Matrix[row][col] * inverse[col][c];
00309           }
00310         this->Matrix[row][col] = 0;
00311         }
00312       }
00313   }
00314   
00315   // finally copy inverse into this object.
00316   return (*this = inverse);
00317 }
00318 
00319 template<class T>
00320 Matrix3x3<T>& 
00321 Matrix3x3<T>::operator*=( const Self& other )
00322 {
00323   return (*this = ((*this) * other));
00324 }
00325 
00326 template<class T>
00327 Matrix3x3<T>& 
00328 Matrix3x3<T>::operator*=( const T scalar )
00329 {
00330   for ( int j=0; j<3; ++j ) 
00331     {
00332     for ( int i=0; i<3; ++i ) 
00333       {
00334       this->Matrix[i][j] *= scalar;
00335       }
00336     }
00337   return *this;
00338 }
00339 
00340 template<class T>
00341 const Matrix3x3<T>
00342 Matrix3x3<T>::operator*
00343 ( const Self& other ) const
00344 {
00345   Self result( NULL );
00346 
00347   for ( int j=0; j<3; ++j ) 
00348     {
00349     for ( int i=0; i<3; ++i ) 
00350       {
00351       result[i][j] = 0;
00352       for ( int k=0; k<3; ++k )
00353         result[i][j] += this->Matrix[i][k] * other.Matrix[k][j];
00354       }
00355     }
00356   
00357   return result;
00358 }
00359 
00360 template<class T>
00361 Matrix3x3<T>& 
00362 Matrix3x3<T>::operator=( const Self& other )
00363 {
00364   memcpy( this->Matrix, other.Matrix, sizeof( this->Matrix ) );
00365   return *this;
00366 }
00367 
00368 template<class T>
00369 T
00370 Matrix3x3<T>::FrobeniusNorm() const
00371 {
00372   T norm = 0.0;
00373   for ( int i = 0; i < 3; ++i ) 
00374     {
00375     for ( int j = 0; j < 3; ++j )
00376       norm += MathUtil::Square( this->Matrix[i][j] );
00377     }
00378   return sqrt( norm );
00379 }
00380 
00381 template<class T>
00382 void
00383 Matrix3x3<T>::ComputeEigenvalues( T (&lambda)[3] ) const
00384 {
00385   const double M11 = this->Matrix[0][0];
00386   const double M12 = this->Matrix[0][1];
00387   const double M13 = this->Matrix[0][2];
00388   const double M22 = this->Matrix[1][1];
00389   const double M23 = this->Matrix[1][2];
00390   const double M33 = this->Matrix[2][2];
00391 
00392 // <begin copyright notice>
00393 // ---------------------------------------------------------------------------
00394 //
00395 //                Copyright (c) 2000-2003 TargetJr Consortium
00396 //               GE Corporate Research and Development (GE CRD)
00397 //                             1 Research Circle
00398 //                            Niskayuna, NY 12309
00399 //                            All Rights Reserved
00400 //              Reproduction rights limited as described below.
00401 //
00402 //      Permission to use, copy, modify, distribute, and sell this software
00403 //      and its documentation for any purpose is hereby granted without fee,
00404 //      provided that (i) the above copyright notice and this permission
00405 //      notice appear in all copies of the software and related documentation,
00406 //      (ii) the name TargetJr Consortium (represented by GE CRD), may not be
00407 //      used in any advertising or publicity relating to the software without
00408 //      the specific, prior written permission of GE CRD, and (iii) any
00409 //      modifications are clearly marked and summarized in a change history
00410 //      log.
00411 //
00412 //      THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
00413 //      EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
00414 //      WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
00415 //      IN NO EVENT SHALL THE TARGETJR CONSORTIUM BE LIABLE FOR ANY SPECIAL,
00416 //      INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND OR ANY
00417 //      DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00418 //      WHETHER OR NOT ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR ON
00419 //      ANY THEORY OF LIABILITY ARISING OUT OF OR IN CONNECTION WITH THE
00420 //      USE OR PERFORMANCE OF THIS SOFTWARE.
00421 //
00422 // ---------------------------------------------------------------------------
00423 // <end copyright notice>
00424 
00425   // Characteristic eqtn |M - xI| = 0
00426   // x^3 + b x^2 + c x + d = 0
00427   const double b = -M11-M22-M33;
00428   const double c =  M11*M22 +M11*M33 +M22*M33  -M12*M12 -M13*M13 -M23*M23;
00429   const double d = M11*M23*M23 +M12*M12*M33 +M13*M13*M22 -2.0*M12*M13*M23 -M11*M22*M33;
00430   // Using a numerically tweaked version of the real cubic solver http://www.1728.com/cubic2.htm
00431   const double b_3 = b/3.0;
00432   const double f = b_3*b_3 -  c/3.0 ;
00433   const double g = b*c/6.0 - b_3*b_3*b_3 - 0.5*d;
00434   
00435   if (f == 0.0 && g == 0.0)
00436     {
00437     lambda[0] = lambda[1] = lambda[2] = static_cast<T>( - b_3 );
00438     return;
00439     }
00440   
00441   const double f3 = f*f*f;
00442   const double g2 = g*g;
00443   const double sqrt_f = -sqrt(f);
00444        
00445    // deal explicitly with repeated root and treat
00446    // complex conjugate roots as numerically inaccurate repeated roots.
00447    
00448    // first check we are not too numerically innacurate
00449 //  assert((g2 - f3) / vnl_math_sqr(b*b*b) < 1e-8);  
00450    
00451   if (g2 >= f3)
00452     {
00453     if (g < 0.0)
00454       {
00455       lambda[0] = static_cast<T>( 2.0 * sqrt_f  - b_3 );
00456       lambda[1] = lambda[2] = static_cast<T>( - sqrt_f - b_3 );
00457       }
00458     else
00459       {
00460       lambda[0] = lambda[1] = static_cast<T>( sqrt_f  - b_3 );
00461       lambda[2] = static_cast<T>( -2.0 * sqrt_f - b_3 );
00462       }
00463     return;
00464     }
00465    
00466  
00467   const double sqrt_f3 = sqrt_f * sqrt_f * sqrt_f;
00468   const double k = acos(g / sqrt_f3) / 3.0;
00469   const double j = 2.0 * sqrt_f;
00470   lambda[0] = static_cast<T>( j * cos(k) - b_3 );
00471   lambda[1] = static_cast<T>( j * cos(k + M_PI * 2.0 / 3.0) - b_3 );
00472   lambda[2] = static_cast<T>( j * cos(k - M_PI * 2.0 / 3.0) - b_3 );
00473 
00474   T tmp;
00475   if (lambda[1] < lambda[0]) 
00476     {
00477     tmp = lambda[1]; lambda[1] = lambda[0]; lambda[0] = tmp;
00478     }
00479 
00480   if (lambda[2] < lambda[1])
00481     {
00482     tmp = lambda[1]; lambda[1] = lambda[2]; lambda[2] = tmp;
00483     if (lambda[1] < lambda[0]) 
00484       {
00485       tmp = lambda[1]; lambda[1] = lambda[0]; lambda[0] = tmp;
00486       }
00487     }
00488 }
00489 
00490 template class Matrix3x3<float>;
00491 template class Matrix3x3<double>;
00492 
00493 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines