cmtkMatrix4x4.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: 2676 $
00026 //
00027 //  $LastChangedDate: 2010-12-15 14:50:13 -0800 (Wed, 15 Dec 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include "cmtkMatrix4x4.h"
00034 
00035 #include <Base/cmtkMathUtil.h>
00036 #include <Base/cmtkMatrix.h>
00037 #include <Base/cmtkQRDecomposition.h>
00038 
00039 #include <System/cmtkConsole.h>
00040 
00041 #include <string.h>
00042 #include <math.h>
00043 #include <vector>
00044 
00045 namespace
00046 cmtk
00047 {
00048 
00051 
00052 template<class T>
00053 Matrix4x4<T>::Matrix4x4()
00054 {
00055   memset( Matrix, 0, sizeof( Matrix ) );
00056   Matrix[0][0] = Matrix[1][1] = Matrix[2][2] = Matrix[3][3] = 1.0;
00057 }
00058 
00059 template<class T>
00060 Matrix4x4<T>::Matrix4x4( const Matrix3x3<T>& other )
00061 {
00062   for ( int j=0; j<3; ++j ) 
00063     {
00064     for ( int i=0; i<3; ++i ) 
00065       {
00066       this->Matrix[i][j] = other[i][j];
00067       }
00068     }
00069 
00070   for ( int j=0; j<3; ++j ) 
00071     {
00072     this->Matrix[3][j] = this->Matrix[j][3] = 0.0;
00073     }
00074   this->Matrix[3][3] = 1.0;
00075 }
00076 
00077 template<class T>
00078 Matrix4x4<T>&
00079 Matrix4x4<T>::Set( const T *const values )
00080 {
00081   memcpy( this->Matrix, values, sizeof( this->Matrix ) );
00082   return *this;
00083 }
00084 
00085 template<class T>
00086 Matrix4x4<T>
00087 Matrix4x4<T>::GetTranspose() const
00088 {
00089   Self transpose;
00090   for ( int i = 0; i < 4; ++i ) 
00091     {
00092     for ( int j = 0; j < 4; ++j )
00093       transpose[i][j] = this->Matrix[j][i];
00094     }
00095   return transpose;
00096 }
00097   
00098 template<class T>
00099 Matrix4x4<T>&
00100 Matrix4x4<T>::Compose
00101 ( const Types::Coordinate params[15], const bool logScaleFactors )
00102 {
00103   const Units::Radians alpha = Units::Degrees( params[3] );
00104   const Units::Radians theta = Units::Degrees( params[4] );
00105   const Units::Radians   phi = Units::Degrees( params[5] );
00106 
00107   const double cos0 = MathUtil::Cos(alpha), sin0 = MathUtil::Sin(alpha);
00108   const double cos1 = MathUtil::Cos(theta), sin1 = MathUtil::Sin(theta);
00109   const double cos2 = MathUtil::Cos(  phi), sin2 = MathUtil::Sin(  phi);
00110 
00111   const double sin0xsin1 = sin0 * sin1;
00112   const double cos0xsin1 = cos0 * sin1;
00113 
00114   const double scaleX = (logScaleFactors) ? exp( params[6] ) : params[6];
00115   const double scaleY = (logScaleFactors) ? exp( params[7] ) : params[7];
00116   const double scaleZ = (logScaleFactors) ? exp( params[8] ) : params[8];
00117 
00118   Matrix[0][0] = static_cast<T>( cos1*cos2 * scaleX );
00119   Matrix[0][1] = static_cast<T>( -cos1*sin2 * scaleX );                     
00120   Matrix[0][2] = static_cast<T>( -sin1 * scaleX );
00121   Matrix[0][3] = static_cast<T>( 0 );
00122   Matrix[1][0] = static_cast<T>(  (sin0xsin1*cos2 + cos0*sin2) * scaleY );
00123   Matrix[1][1] = static_cast<T>( (-sin0xsin1*sin2 + cos0*cos2) * scaleY ); 
00124   Matrix[1][2] = static_cast<T>(  sin0*cos1 * scaleY );
00125   Matrix[1][3] = static_cast<T>( 0 );
00126   Matrix[2][0] = static_cast<T>(  (cos0xsin1*cos2 - sin0*sin2) * scaleZ );
00127   Matrix[2][1] = static_cast<T>( (-cos0xsin1*sin2 - sin0*cos2) * scaleZ );
00128   Matrix[2][2] = static_cast<T>(  cos0*cos1 * scaleZ );
00129   Matrix[2][3] = static_cast<T>( 0 );
00130 
00131   Matrix[3][0] = Matrix[3][1] = Matrix[3][2] = static_cast<T>( 0 );
00132   Matrix[3][3] = static_cast<T>( 1.0 );
00133 
00134   // generate shears
00135   for ( int i = 2; i >= 0; --i )
00136     {
00137     Self shear;
00138     shear[i/2][(i/2)+(i%2)+1] = params[9+i];
00139     *this *= shear;
00140     }
00141   
00142   // transform rotation center
00143   const Types::Coordinate cM[3] = 
00144     {
00145       params[12]*Matrix[0][0] + params[13]*Matrix[1][0] + params[14]*Matrix[2][0],
00146       params[12]*Matrix[0][1] + params[13]*Matrix[1][1] + params[14]*Matrix[2][1],
00147       params[12]*Matrix[0][2] + params[13]*Matrix[1][2] + params[14]*Matrix[2][2]
00148     };
00149   
00150   // set translations
00151   Matrix[3][0] = params[0] - cM[0] + params[12];
00152   Matrix[3][1] = params[1] - cM[1] + params[13];
00153   Matrix[3][2] = params[2] - cM[2] + params[14];
00154   
00155   return *this;
00156 }
00157 
00158 template<class T>
00159 bool
00160 Matrix4x4<T>::Decompose
00161 ( Types::Coordinate params[12], const Types::Coordinate *center, const bool logScaleFactor ) const
00162 {
00163   // make a working copy of the matrix for step-by-step decomposition
00164   Self matrix( *this );
00165 
00166   // translation entries
00167   params[0] = matrix[3][0];
00168   params[1] = matrix[3][1];
00169   params[2] = matrix[3][2];
00170 
00171   if ( center )
00172     {
00173     const Types::Coordinate cM[3] = 
00174       {
00175         center[0]*matrix[0][0] + center[1]*matrix[1][0] + center[2]*matrix[2][0],
00176         center[0]*matrix[0][1] + center[1]*matrix[1][1] + center[2]*matrix[2][1],
00177         center[0]*matrix[0][2] + center[1]*matrix[1][2] + center[2]*matrix[2][2],
00178       };
00179     
00180     params[0] += cM[0] - center[0];
00181     params[1] += cM[1] - center[1];
00182     params[2] += cM[2] - center[2];
00183     
00184     if ( center != params+12)
00185       {
00186       // sometimes we may get a pointer to our own parameters
00187       memcpy( params+12, center, 3*sizeof( Types::Coordinate ) );
00188       }
00189     } 
00190   else
00191     {
00192     memset( params+12, 0, 3*sizeof( Types::Coordinate ) );
00193     }
00194 
00195   // use QR decomposition to get shears (gets the scales, too, but we'll discard those 
00196   // and do them explicitly later.
00197   Matrix2D<T> matrix2d( 3, 3 );
00198   for ( int i = 0; i < 3; ++i )
00199     for ( int j = 0; j < 3; ++j )
00200       matrix2d[i][j] = matrix[i][j];
00201 
00202   QRDecomposition<T> qr( matrix2d );
00203   const Matrix2D<T> R = qr.GetR();
00204 
00205   // shear
00206   for ( int k = 0; k<3; ++k ) 
00207     {
00208     const int i = k / 2;           // i.e. i := { 0, 0, 1 }
00209     const int j = i + (k%2) + 1;   // i.e. j := { 0, 1, 2 } -- so i,j index the upper triangle of aMat, which is R from QR
00210     params[9+k] = R[i][j] / R[i][i];
00211 
00212     // remove contribution from transformation matrix
00213     Self shear;
00214     shear[i][j] = params[9+k];
00215     matrix *= shear.GetInverse();
00216     }
00217   
00218 /*=========================================================================
00219 
00220 THE FOLLOWING CODE WAS ADOPTED AND MODIFIED FROM VTK, The Visualization
00221 Toolkit.
00222 
00223   Program:   Visualization Toolkit
00224   Language:  C++
00225   Thanks:    Thanks to David G. Gobbi who developed this class.
00226 
00227 Copyright (c) 1993-2001 Ken Martin, Will Schroeder, Bill Lorensen 
00228 All rights reserved.
00229 
00230 Redistribution and use in source and binary forms, with or without
00231 modification, are permitted provided that the following conditions are met:
00232 
00233  * Redistributions of source code must retain the above copyright notice,
00234    this list of conditions and the following disclaimer.
00235 
00236  * Redistributions in binary form must reproduce the above copyright notice,
00237    this list of conditions and the following disclaimer in the documentation
00238    and/or other materials provided with the distribution.
00239 
00240  * Neither name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names
00241    of any contributors may be used to endorse or promote products derived
00242    from this software without specific prior written permission.
00243 
00244  * Modified source versions must be plainly marked as such, and must not be
00245    misrepresented as being the original software.
00246 
00247 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00248 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00249 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00250 ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
00251 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00252 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00253 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00254 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00255 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00256 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00257 
00258 =========================================================================*/
00259 
00260 #define VTK_AXIS_EPSILON 0.001
00261   double   d;
00262   double   d1;
00263   double   d2;
00264   double   dot;
00265   double   cosPhi, sinPhi;
00266   double   cosTheta, sinTheta;
00267   double   cosAlpha, sinAlpha;
00268   double   x2, y2, z2;
00269   double   x3, y3, z3;
00270   double   x3p, y3p;
00271     
00272   for ( int i=0; i<3; ++i ) 
00273     {
00274     // scale
00275     params[6 + i] = sqrt( MathUtil::Square( matrix[i][0] ) + MathUtil::Square( matrix[i][1] ) + MathUtil::Square( matrix[i][2] ) );
00276     
00277     // report error on singular matrices.
00278     if ( fabs(params[6+i]) < VTK_AXIS_EPSILON ) 
00279       {
00280       StdErr <<"Matrxi4x4::Decompose encountered singular matrix.";
00281       return false;
00282       }
00283     }
00284 
00285   // if negative determinant, negate x scale
00286   const Types::Coordinate determinant = 
00287     this->Matrix[0][0]*this->Matrix[1][1]*this->Matrix[2][2] + 
00288     this->Matrix[0][1]*this->Matrix[1][2]*this->Matrix[2][0] + 
00289     this->Matrix[0][2]*this->Matrix[1][0]*this->Matrix[2][1] - 
00290     this->Matrix[0][2]*this->Matrix[1][1]*this->Matrix[2][0] - 
00291     this->Matrix[0][0]*this->Matrix[1][2]*this->Matrix[2][1] - 
00292     this->Matrix[0][1]*this->Matrix[1][0]*this->Matrix[2][2];
00293 
00294   if ( determinant < 0 )
00295     params[6] = -params[6];
00296   
00297   // rotation
00298   // first rotate about y axis
00299   x2 = matrix[0][1] / params[6];
00300   y2 = matrix[0][2] / params[6];
00301   z2 = matrix[0][0] / params[6];
00302     
00303   x3 = matrix[2][1] / params[8];
00304   y3 = matrix[2][2] / params[8];
00305   z3 = matrix[2][0] / params[8];
00306     
00307   dot = x2 * x2 + z2 * z2;
00308   d1 = sqrt (dot);
00309     
00310   if (d1 < VTK_AXIS_EPSILON) 
00311     {
00312     cosTheta = 1.0;
00313     sinTheta = 0.0;
00314     } 
00315   else 
00316     {
00317     cosTheta = z2 / d1;
00318     sinTheta = x2 / d1;
00319     }
00320   
00321   params[5] = Units::Degrees( -MathUtil::ArcTan2( sinTheta, cosTheta ) ).Value(); // theta
00322     
00323     // now rotate about x axis
00324   dot = x2 * x2 + y2 * y2 + z2 * z2;
00325   d = sqrt (dot);
00326     
00327   if (d < VTK_AXIS_EPSILON) 
00328     {    
00329     sinPhi = 0.0;
00330     cosPhi = 1.0;
00331     } 
00332   else 
00333     if (d1 < VTK_AXIS_EPSILON) 
00334       {
00335       sinPhi = y2 / d;
00336       cosPhi = z2 / d;
00337       } 
00338     else 
00339       {
00340       sinPhi = y2 / d;
00341       cosPhi = ( x2 * x2 + z2 * z2) / (d1 * d);
00342       }
00343   
00344   params[4] = Units::Degrees( -MathUtil::ArcTan2( sinPhi, cosPhi ) ).Value(); // phi 
00345   
00346   // finally, rotate about z
00347   x3p = x3 * cosTheta - z3 * sinTheta;
00348   y3p = - sinPhi * sinTheta * x3 + cosPhi * y3 - sinPhi * cosTheta * z3;
00349   dot = x3p * x3p + y3p * y3p;
00350   
00351   d2 = sqrt (dot);
00352   if (d2 < VTK_AXIS_EPSILON) 
00353     {
00354     cosAlpha = 1.0;
00355     sinAlpha = 0.0;
00356     } 
00357   else
00358     {
00359     cosAlpha = y3p / d2;
00360     sinAlpha = x3p / d2;
00361     }
00362   
00363   params[3] = Units::Degrees( -MathUtil::ArcTan2( sinAlpha, cosAlpha ) ).Value(); // alpha
00364   
00365   if ( logScaleFactor )
00366     {
00367     for ( int i = 6; i < 9; ++i )
00368       params[i] = log( params[i] );
00369     }
00370   
00371   return true;
00372   
00374 }
00375 
00376 template<class T>
00377 const Matrix4x4<T>
00378 Matrix4x4<T>::GetInverse() const
00379 {
00380   Self inverse;
00381   Self temp = *this;
00382   
00383   T rowBuff[4];
00384   for ( int col = 0; col<4; ++col ) 
00385     {    
00386     int pivIdx = col;
00387     T pivAbs = fabs( temp.Matrix[col][col] );
00388 
00389     for ( int row = col+1; row<3; ++row )  // 3 to exclude last row!
00390       {
00391       T nextAbs = fabs( temp.Matrix[row][col] );
00392       if (nextAbs > pivAbs ) 
00393         {
00394         pivIdx = row;
00395         pivAbs = nextAbs;
00396         }
00397       }
00398     
00399     if ( col != pivIdx )
00400       {
00401       memcpy( rowBuff, temp.Matrix[col], sizeof(rowBuff) );
00402       memcpy( temp.Matrix[col], temp.Matrix[pivIdx], sizeof(rowBuff) );
00403       memcpy( temp.Matrix[pivIdx], rowBuff, sizeof(rowBuff) );
00404       
00405       memcpy( rowBuff, inverse.Matrix[col],sizeof(rowBuff));
00406       memcpy( inverse.Matrix[col], inverse.Matrix[pivIdx], sizeof(rowBuff) );
00407       memcpy( inverse.Matrix[pivIdx], rowBuff, sizeof(rowBuff) );
00408       }
00409     
00410     for ( int c=0; c<4; ++c ) 
00411       {
00412       if (c>col )
00413         temp.Matrix[col][c] /= temp.Matrix[col][col];
00414       inverse.Matrix[col][c] /= temp.Matrix[col][col];
00415       }
00416     temp.Matrix[col][col] = 1.0;
00417     
00418     for ( int row = 0; row<4; ++row ) 
00419       {
00420       if (row != col ) 
00421         {
00422         for ( int c=0; c<4; ++c ) 
00423           {
00424           if ( c>col ) 
00425             temp.Matrix[row][c] -= temp.Matrix[row][col] * temp.Matrix[col][c];
00426           inverse.Matrix[row][c] -= temp.Matrix[row][col] * inverse.Matrix[col][c];
00427           }
00428         temp.Matrix[row][col] = 0;
00429         }
00430       }
00431     }
00432   
00433   return inverse;
00434 }
00435 
00436 template<class T>
00437 Matrix4x4<T>& 
00438 Matrix4x4<T>::operator*=( const Self& other )
00439 {
00440   return (*this = ((*this) * other));
00441 }
00442 
00443 template<class T>
00444 const Matrix4x4<T>
00445 Matrix4x4<T>::operator*
00446 ( const Self& other ) const
00447 {
00448   Self result( NULL );
00449 
00450   for ( int j=0; j<4; ++j ) 
00451     {
00452     for ( int i=0; i<4; ++i ) 
00453       {
00454       result[i][j] = 0;
00455       for ( int k=0; k<4; ++k )
00456         result[i][j] += this->Matrix[i][k] * other.Matrix[k][j];
00457       }
00458     }
00459 
00460   return result;
00461 }
00462 
00463 template<class T>
00464 Matrix4x4<T>& 
00465 Matrix4x4<T>::operator=( const Matrix3x3<T>& other )
00466 {
00467   for ( int j=0; j<3; ++j ) 
00468     {
00469     for ( int i=0; i<3; ++i ) 
00470       {
00471       this->Matrix[i][j] = other[i][j];
00472       }
00473     }
00474 
00475   for ( int j=0; j<3; ++j ) 
00476     {
00477     this->Matrix[3][j] = this->Matrix[j][3] = 0.0;
00478     }
00479   this->Matrix[3][3] = 1.0;
00480   
00481   return *this;
00482 }
00483 
00484 template<class T>
00485 Matrix4x4<T>& 
00486 Matrix4x4<T>::ChangeCoordinateSystem
00487 ( const FixedVector<3,T>& newX, const FixedVector<3,T>& newY )
00488 {
00489   // rotate x axis to match new coordinate system
00490   Self rotate = RotateX( -atan2( newX[1], newX[2] ) );
00491   rotate *= RotateY( acos( newX[0] ) );
00492 
00493   // rotate previously rotated y axis further to match new coordinate system
00494   const FixedVector<3,T> newYrot = newY * rotate;
00495   rotate *= RotateX( atan2( newYrot[2], newYrot[1] ) );
00496 
00497   // z axis now matches automatically
00498 
00499   // apply rotation matrix to previous transformation to apply change of
00500   // coordinate systems.
00501   *this *= rotate;
00502   *this = rotate.GetInverse() * *this;
00503 
00504   return *this;
00505 }
00506 
00507 
00508 template<class T>
00509 Matrix4x4<T>
00510 Matrix4x4<T>::RotateX( const T angle )
00511 {
00512   Self rot;
00513   rot[1][1] = rot[2][2] = cos( angle );
00514   rot[1][2] = -1.0 * (rot[2][1] = sin( angle ) );
00515 
00516   return rot;
00517 }
00518   
00519 template<class T>
00520 Matrix4x4<T> 
00521 Matrix4x4<T>::RotateY( const T angle )
00522 {
00523   Self rot;
00524   rot[0][0] = rot[2][2] = cos( angle );
00525   rot[0][2] = -1.0 * (rot[2][0] = sin( angle ) );
00526 
00527   return rot;
00528 }
00529   
00530 template<class T>
00531 Matrix4x4<T> 
00532 Matrix4x4<T>::RotateZ( const T angle )
00533 {
00534   Self rot;
00535   rot[0][0] = rot[1][1] = cos( angle );
00536   rot[0][1] = -1.0 * (rot[1][0] = sin( angle ) );
00537 
00538   return rot;
00539 }
00540 
00541 template<class T>
00542 T
00543 Matrix4x4<T>::FrobeniusNorm() const
00544 {
00545   T norm = 0.0;
00546   for ( int i = 0; i < 4; ++i ) 
00547     {
00548     for ( int j = 0; j < 4; ++j )
00549       norm += MathUtil::Square( this->Matrix[i][j] );
00550     }
00551   return sqrt( norm );
00552 }
00553 
00554 template class Matrix4x4<Types::Coordinate>;
00555 
00556 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines