00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <Base/cmtkAffineXform.h>
00034
00035 #include <Base/cmtkMathUtil.h>
00036 #include <Base/cmtkUniformVolume.h>
00037
00038 #include <System/cmtkConsole.h>
00039
00040 #include <algorithm>
00041
00042 namespace
00043 cmtk
00044 {
00045
00048
00049 void
00050 AffineXform::MakeIdentityXform ()
00051 {
00052 this->m_ParameterVector->Clear();
00053 Types::Coordinate* scales = this->RetScales();
00054 if ( ! m_LogScaleFactors )
00055 scales[0] = scales[1] = scales[2] = 1;
00056 this->ComposeMatrix();
00057 }
00058
00059 AffineXform::AffineXform ( const AffineXform& other ) :
00060 Xform( other ),
00061 Matrix( NULL ),
00062 m_LogScaleFactors( false ),
00063 InverseXform( NULL )
00064 {
00065 this->AllocateParameterVector( TotalNumberOfParameters );
00066 (*this->m_ParameterVector) = (*other.m_ParameterVector);
00067 this->m_LogScaleFactors = other.m_LogScaleFactors;
00068 this->NumberDOFs = other.NumberDOFs;
00069 this->ComposeMatrix();
00070 }
00071
00072 AffineXform::AffineXform
00073 ( const Types::Coordinate matrix[4][4], const Types::Coordinate* center ) :
00074 Matrix( &matrix[0][0] ),
00075 m_LogScaleFactors( false ),
00076 InverseXform( NULL )
00077 {
00078 this->AllocateParameterVector( TotalNumberOfParameters );
00079 this->NumberDOFs = this->DefaultNumberOfDOFs();
00080 if ( center )
00081 memcpy( this->RetCenter(), center, 3 * sizeof( Types::Coordinate ) );
00082 else
00083 memset( this->RetCenter(), 0, 3 * sizeof( Types::Coordinate ) );
00084 this->DecomposeMatrix();
00085 }
00086
00087 AffineXform::AffineXform
00088 ( const MatrixType& matrix, const Types::Coordinate* center ) :
00089 Matrix( matrix ),
00090 m_LogScaleFactors( false ),
00091 InverseXform( NULL )
00092 {
00093 this->AllocateParameterVector( TotalNumberOfParameters );
00094 this->NumberDOFs = this->DefaultNumberOfDOFs();
00095 if ( center )
00096 memcpy( this->RetCenter(), center, 3 * sizeof( Types::Coordinate ) );
00097 else
00098 memset( this->RetCenter(), 0, 3 * sizeof( Types::Coordinate ) );
00099 this->DecomposeMatrix();
00100 }
00101
00102 AffineXform::AffineXform
00103 ( const Types::Coordinate matrix[4][4], const Types::Coordinate xlate[3],
00104 const Types::Coordinate center[3] ) :
00105 Matrix( &matrix[0][0] ),
00106 m_LogScaleFactors( false ),
00107 InverseXform( NULL )
00108 {
00109 this->AllocateParameterVector( TotalNumberOfParameters );
00110 this->NumberDOFs = this->DefaultNumberOfDOFs();
00111 Types::Coordinate cM[3] =
00112 {
00113 center[0]*Matrix[0][0] + center[1]*Matrix[1][0] + center[2]*Matrix[2][0],
00114 center[0]*Matrix[0][1] + center[1]*Matrix[1][1] + center[2]*Matrix[2][1],
00115 center[0]*Matrix[0][2] + center[1]*Matrix[1][2] + center[2]*Matrix[2][2]
00116 };
00117
00118 Matrix[3][0] = xlate[0] + center[0] - cM[0];
00119 Matrix[3][1] = xlate[1] + center[1] - cM[1];
00120 Matrix[3][2] = xlate[2] + center[2] - cM[2];
00121
00122 this->Matrix.Decompose( this->m_Parameters, center, this->m_LogScaleFactors );
00123 }
00124
00125 AffineXform&
00126 AffineXform::operator=( const AffineXform& other )
00127 {
00128 (*this->m_ParameterVector) = (*other.m_ParameterVector);
00129 this->NumberDOFs = other.NumberDOFs;
00130 this->m_LogScaleFactors = other.m_LogScaleFactors;
00131 this->ComposeMatrix();
00132 return *this;
00133 }
00134
00135 void
00136 AffineXform::SetNumberDOFs ( const int numberDOFs )
00137 {
00138 this->NumberDOFs = numberDOFs;
00139 if ( this->NumberDOFs == 7 )
00140 {
00141 this->m_Parameters[8] = (this->m_Parameters[7] = this->m_Parameters[6]);
00142 this->ComposeMatrix();
00143 }
00144 }
00145
00146 void
00147 AffineXform::SetUseLogScaleFactors( const bool logScaleFactors )
00148 {
00149 if ( logScaleFactors != this->m_LogScaleFactors )
00150 {
00151 if ( logScaleFactors )
00152 {
00153 for ( int i = 6; i < 9; ++i )
00154 this->m_Parameters[i] = log( this->m_Parameters[i] );
00155 }
00156 else
00157 {
00158 for ( int i = 6; i < 9; ++i )
00159 this->m_Parameters[i] = exp( this->m_Parameters[i] );
00160 }
00161 this->m_LogScaleFactors = logScaleFactors;
00162 }
00163 }
00164
00165 void
00166 AffineXform::ComposeMatrix ()
00167 {
00168
00169
00170 if ( this->NumberDOFs == 7 )
00171 this->m_Parameters[8] = (this->m_Parameters[7] = this->m_Parameters[6]);
00172
00173
00174 this->Matrix.Compose( this->m_Parameters, this->m_LogScaleFactors );
00175 this->UpdateInverse();
00176 }
00177
00178 bool
00179 AffineXform::DecomposeMatrix ()
00180 {
00181 return this->Matrix.Decompose( this->m_Parameters, this->RetCenter(), this->m_LogScaleFactors );
00182 }
00183
00184 AffineXform::SpaceVectorType
00185 AffineXform::RotateScaleShear
00186 ( const Self::SpaceVectorType& v ) const
00187 {
00188 Self::SpaceVectorType Mv;
00189 for ( size_t i = 0; i<3; ++i )
00190 {
00191 Mv[i] = v[0] * Matrix[0][i] + v[1] * Matrix[1][i] + v[2] * Matrix[2][i];
00192 }
00193 return Mv;
00194 }
00195
00196 AffineXform*
00197 AffineXform::MakeInverse () const
00198 {
00199 Self* inverseXform = new AffineXform();
00200 inverseXform->m_LogScaleFactors = this->m_LogScaleFactors;
00201 inverseXform->SetNumberDOFs( this->NumberDOFs );
00202 inverseXform->Matrix = this->Matrix.GetInverse();
00203 inverseXform->DecomposeMatrix();
00204
00205 const Self::SpaceVectorType newCenter = Self::SpaceVectorType( this->RetCenter() ) * this->Matrix;
00206 inverseXform->ChangeCenter( newCenter );
00207
00208 if ( this->NumberDOFs == 7 )
00209 {
00210 inverseXform->m_Parameters[8] = (inverseXform->m_Parameters[7] = inverseXform->m_Parameters[6]);
00211 inverseXform->Matrix.Compose( inverseXform->m_Parameters, this->m_LogScaleFactors );
00212 }
00213
00214 inverseXform->m_MetaInformation[META_SPACE] = this->m_MetaInformation[META_SPACE];
00215 inverseXform->m_MetaInformation[META_XFORM_FIXED_IMAGE_PATH] = this->m_MetaInformation[META_XFORM_FIXED_IMAGE_PATH];
00216 inverseXform->m_MetaInformation[META_XFORM_MOVING_IMAGE_PATH] = this->m_MetaInformation[META_XFORM_MOVING_IMAGE_PATH];
00217
00218 return inverseXform;
00219 }
00220
00221 void
00222 AffineXform::ChangeCenter ( const Self::SpaceVectorType& newCenter )
00223 {
00224 Types::Coordinate *const xlate = this->RetXlate();
00225 Types::Coordinate *const center = this->RetCenter();
00226 Self::SpaceVectorType deltaCenter = newCenter - Self::SpaceVectorType( center );
00227
00228 for ( size_t i = 0; i<3; ++i )
00229 xlate[i] -= deltaCenter[i];
00230
00231 deltaCenter = this->RotateScaleShear( deltaCenter );
00232
00233 for ( size_t i = 0; i<3; ++i )
00234 {
00235 xlate[i] += deltaCenter[i];
00236 center[i] = newCenter[i];
00237 }
00238 }
00239
00240 void
00241 AffineXform::SetMatrix( const MatrixType& matrix )
00242 {
00243 this->Matrix = matrix;
00244 this->DecomposeMatrix();
00245 this->UpdateInverse();
00246 }
00247
00248 void
00249 AffineXform::SetMatrix( const float matrix[4][4] )
00250 {
00251 for ( unsigned int j = 0; j < 4; ++j )
00252 for ( unsigned int i = 0; i < 4; ++i )
00253 Matrix[j][i] = matrix[j][i];
00254 this->DecomposeMatrix();
00255 this->UpdateInverse();
00256 }
00257
00258 void
00259 AffineXform::SetMatrix( const double matrix[4][4] )
00260 {
00261 for ( unsigned int j = 0; j < 4; ++j )
00262 for ( unsigned int i = 0; i < 4; ++i )
00263 Matrix[j][i] = matrix[j][i];
00264 this->DecomposeMatrix();
00265 this->UpdateInverse();
00266 }
00267
00268 template<>
00269 void
00270 AffineXform::GetMatrix( float (&matrix)[4][4] ) const
00271 {
00272 for ( unsigned int j = 0; j < 4; ++j )
00273 for ( unsigned int i = 0; i < 4; ++i )
00274 matrix[j][i] = static_cast<float>( Matrix[j][i] );
00275 }
00276
00277 template<>
00278 void
00279 AffineXform::GetMatrix( double (&matrix)[4][4] ) const
00280 {
00281 for ( unsigned int j = 0; j < 4; ++j )
00282 for ( unsigned int i = 0; i < 4; ++i )
00283 matrix[j][i] = static_cast<double>( Matrix[j][i] );
00284 }
00285
00286 void
00287 AffineXform::SetParamVector ( CoordinateVector& v )
00288 {
00289 Superclass::SetParamVector( v );
00290 this->CanonicalRotationRange();
00291 this->ComposeMatrix();
00292 v = (*this->m_ParameterVector);
00293 }
00294
00295 void
00296 AffineXform::SetParamVector ( const CoordinateVector& v )
00297 {
00298 Superclass::SetParamVector( v );
00299 this->CanonicalRotationRange();
00300 this->ComposeMatrix();
00301 }
00302
00303 void
00304 AffineXform::SetParameter ( const size_t idx, const Types::Coordinate p )
00305 {
00306 Superclass::SetParameter( idx, p );
00307 this->CanonicalRotationRange();
00308 this->ComposeMatrix();
00309 }
00310
00311
00312 Types::Coordinate
00313 AffineXform::GetParamStep
00314 ( const size_t idx, const Self::SpaceVectorType& volSize, const Types::Coordinate mmStep )
00315 const
00316 {
00317 if ( (int)idx >= this->NumberDOFs ) return 0.0;
00318
00319 switch ( idx )
00320 {
00321 case 0: case 1: case 2:
00322 return mmStep;
00323 case 3:
00324 return mmStep * 180 / (M_PI * sqrt( MathUtil::Square( volSize[1] ) + MathUtil::Square( volSize[2] ) ) );
00325 case 4:
00326 return mmStep * 180 / (M_PI * sqrt( MathUtil::Square( volSize[0] ) + MathUtil::Square( volSize[2] ) ) );
00327 case 5:
00328 return mmStep * 180 / (M_PI * sqrt( MathUtil::Square( volSize[0] ) + MathUtil::Square( volSize[1] ) ) );
00329 case 6:
00330 case 7:
00331 case 8:
00332 if ( this->NumberDOFs == 603 )
00333 {
00334 return 0;
00335 }
00336 else
00337 {
00338 if ( this->m_LogScaleFactors )
00339 return log( 1 + 0.5 * mmStep / volSize.MaxValue() );
00340 else
00341 return 0.5 * mmStep / volSize.MaxValue();
00342 }
00343 case 9:
00344 case 10:
00345 case 11:
00346 return 0.5 * mmStep / volSize.MaxValue();
00347 }
00348 return mmStep;
00349 }
00350
00351 AffineXform::SmartPtr
00352 AffineXform::GetDifference( const AffineXform& other ) const
00353 {
00354 Self::SmartPtr result( this->MakeInverse() );
00355 result->Concat( other );
00356 return result;
00357 }
00358
00359 void
00360 AffineXform::Concat( const AffineXform& other )
00361 {
00362 this->Matrix *= other.Matrix;
00363 this->DecomposeMatrix();
00364 }
00365
00366 void
00367 AffineXform::Insert( const AffineXform& other )
00368 {
00369 Self::MatrixType composed( other.Matrix );
00370 composed *= this->Matrix;
00371 this->Matrix = composed;
00372 this->DecomposeMatrix();
00373 }
00374
00375 void
00376 AffineXform::RotateWXYZ
00377 ( const Units::Radians angle, const Self::SpaceVectorType& direction,
00378 const Types::Coordinate* center, Self::MatrixType *const accumulate )
00379 {
00380 Self::SpaceVectorType unit( direction );
00381
00382 Self::SpaceVectorType center3D;
00383 if ( center )
00384 center3D = Self::SpaceVectorType( center );
00385 else
00386 center3D = Self::SpaceVectorType( this->RetCenter() );
00387
00388 if ( accumulate )
00389 {
00390 unit += center3D;
00391 unit *= *accumulate;
00392 center3D *= *accumulate;
00393 unit -= center3D;
00394 }
00395
00396
00397 Self::MatrixType xlate;
00398 for ( int dim = 0; dim < 3; ++dim )
00399 xlate[3][dim] = -center3D[dim];
00400
00401 if ( accumulate )
00402 {
00403 *accumulate *= xlate;
00404 }
00405
00406 this->Matrix *= xlate;
00407
00408 double x = unit[0];
00409 double y = unit[1];
00410 double z = unit[2];
00411
00412
00413 const double w = MathUtil::Cos(0.5*angle);
00414 const double f = MathUtil::Sin(0.5*angle)/sqrt(x*x+y*y+z*z);
00415 x *= f;
00416 y *= f;
00417 z *= f;
00418
00419
00420 Self::MatrixType matrix;
00421
00422 const double ww = w*w;
00423 const double wx = w*x;
00424 const double wy = w*y;
00425 const double wz = w*z;
00426
00427 const double xx = x*x;
00428 const double yy = y*y;
00429 const double zz = z*z;
00430
00431 const double xy = x*y;
00432 const double xz = x*z;
00433 const double yz = y*z;
00434
00435 const double s = ww - xx - yy - zz;
00436
00437 matrix[0][0] = xx*2 + s;
00438 matrix[1][0] = (xy + wz)*2;
00439 matrix[2][0] = (xz - wy)*2;
00440
00441 matrix[0][1] = (xy - wz)*2;
00442 matrix[1][1] = yy*2 + s;
00443 matrix[2][1] = (yz + wx)*2;
00444
00445 matrix[0][2] = (xz + wy)*2;
00446 matrix[1][2] = (yz - wx)*2;
00447 matrix[2][2] = zz*2 + s;
00448
00449 this->Matrix *= matrix;
00450
00451 xlate = xlate.GetInverse();
00452 this->Matrix *= xlate;
00453 this->DecomposeMatrix();
00454
00455 if ( accumulate )
00456 {
00457 *accumulate *= matrix;
00458 *accumulate *= xlate;
00459 }
00460 }
00461
00462 const AffineXform::SmartPtr
00463 AffineXform::GetInverse() const
00464 {
00465 if ( !InverseXform )
00466 {
00467 InverseXform = AffineXform::SmartPtr( this->MakeInverse() );
00468 }
00469 else
00470 {
00471 this->UpdateInverse();
00472 }
00473
00474 return InverseXform;
00475 }
00476
00477 void
00478 AffineXform::UpdateInverse() const
00479 {
00480 if ( InverseXform )
00481 {
00482 InverseXform->NumberDOFs = this->NumberDOFs;
00483 InverseXform->m_LogScaleFactors = this->m_LogScaleFactors;
00484 InverseXform->Matrix = this->Matrix.GetInverse();
00485 InverseXform->DecomposeMatrix();
00486 }
00487 }
00488
00489 void
00490 AffineXform::CanonicalRotationRange()
00491 {
00492 for ( int rotIdx = 0; rotIdx<3; ++rotIdx )
00493 {
00494 while ( this->m_Parameters[3+rotIdx] > 180 )
00495 this->m_Parameters[3+rotIdx] -= 360;
00496 while ( this->m_Parameters[3+rotIdx] < -180 )
00497 this->m_Parameters[3+rotIdx] += 360;
00498 }
00499 }
00500
00501 void
00502 AffineXform::Print() const
00503 {
00504 StdErr.printf( "AffineXform at %p:\n", this );
00505 StdErr.printf( "\tNumber DOFs: %d\n", NumberDOFs );
00506 StdErr.printf( "\tTranslation: [%f,%f,%f]\n", this->m_Parameters[0], this->m_Parameters[1], this->m_Parameters[2] );
00507 StdErr.printf( "\tRotation: [%f,%f,%f] around [%f,%f,%f]\n",
00508 this->m_Parameters[3], this->m_Parameters[4], this->m_Parameters[5],
00509 this->m_Parameters[12], this->m_Parameters[13], this->m_Parameters[14] );
00510 StdErr.printf( "\tScale: [%f,%f,%f]\n", this->m_Parameters[6], this->m_Parameters[7], this->m_Parameters[8] );
00511 StdErr.printf( "\tShear: [%f,%f,%f]\n", this->m_Parameters[9], this->m_Parameters[10], this->m_Parameters[11] );
00512
00513 this->Matrix.Print( StdErr );
00514 }
00515
00516 }