USGS

Isis 3.0 Object Programmers' Reference

Home

Affine.cpp

Go to the documentation of this file.
00001 
00023 #include <vector>
00024 #include <iostream>
00025 #include <string>
00026 #include "jama_svd.h"
00027 
00028 #include "Affine.h"
00029 #include "PolynomialBivariate.h"
00030 #include "LeastSquares.h"
00031 #include "iException.h"
00032 #include "Constants.h"
00033 
00034 using namespace std;
00035 
00036 namespace Isis {
00041   Affine::Affine () {
00042     Identity();
00043     p_x = p_y = p_xp = p_yp = 0.0;
00044   }
00045 
00057   Affine::Affine(const Affine::AMatrix &a) {
00058     checkDims(a);
00059     p_matrix = a.copy();
00060     p_invmat = invert(p_matrix);
00061     p_x = p_y = p_xp = p_yp = 0.0;
00062   }
00063 
00065   Affine::~Affine() {}
00066 
00072   Affine::AMatrix Affine::getIdentity() {
00073     AMatrix ident(3,3, 0.0);
00074     for (int i = 0 ; i < ident.dim2() ; i++) {
00075       ident[i][i] = 1.0;
00076     }
00077     return (ident);
00078   }
00079 
00084   void Affine::Identity() {
00085     p_matrix = getIdentity();
00086     p_invmat = getIdentity();
00087   }
00088 
00103   void Affine::Solve (const double x[], const double y[], 
00104                       const double xp[], const double yp[], int n) {
00105     // We must solve two least squares equations
00106     PolynomialBivariate xpFunc(1);
00107     PolynomialBivariate ypFunc(1);
00108     LeastSquares xpLSQ(xpFunc);
00109     LeastSquares ypLSQ(ypFunc);
00110 
00111     // Push the knowns into the least squares class
00112     for (int i=0; i<n; i++) {
00113       vector<double> coord(2);
00114       coord[0] = x[i];
00115       coord[1] = y[i];
00116       xpLSQ.AddKnown(coord,xp[i]);
00117       ypLSQ.AddKnown(coord,yp[i]);
00118     }
00119 
00120     // Solve for A,B,C,D,E,F
00121     xpLSQ.Solve();
00122     ypLSQ.Solve();
00123 
00124     // Construct our affine matrix
00125     p_matrix[0][0] = xpFunc.Coefficient(1); // A
00126     p_matrix[0][1] = xpFunc.Coefficient(2); // B
00127     p_matrix[0][2] = xpFunc.Coefficient(0); // C
00128     p_matrix[1][0] = ypFunc.Coefficient(1); // D
00129     p_matrix[1][1] = ypFunc.Coefficient(2); // E
00130     p_matrix[1][2] = ypFunc.Coefficient(0); // F
00131     p_matrix[2][0] = 0.0;
00132     p_matrix[2][1] = 0.0;
00133     p_matrix[2][2] = 1.0;
00134 
00135     // invert the matrix
00136     p_invmat = invert(p_matrix);
00137   }
00138 
00145   void Affine::Translate (double tx, double ty) {
00146     AMatrix trans = getIdentity();
00147 
00148     trans[0][2] = tx;
00149     trans[1][2] = ty;
00150     p_matrix = TNT::matmult(trans,p_matrix);
00151     
00152     trans[0][2] = -tx;
00153     trans[1][2] = -ty;
00154     p_invmat = TNT::matmult(p_invmat,trans);
00155   }
00156 
00162   void Affine::Rotate(double angle) {
00163     AMatrix rot = getIdentity();
00164 
00165     double angleRadians = angle * Isis::PI / 180.0;
00166     rot[0][0] = cos(angleRadians);
00167     rot[0][1] = -sin(angleRadians);
00168     rot[1][0] = sin(angleRadians);
00169     rot[1][1] = cos(angleRadians);
00170     p_matrix = TNT::matmult(rot,p_matrix);
00171 
00172     angleRadians = -angleRadians;
00173     rot[0][0] = cos(angleRadians);
00174     rot[0][1] = -sin(angleRadians);
00175     rot[1][0] = sin(angleRadians);
00176     rot[1][1] = cos(angleRadians);
00177     p_invmat = TNT::matmult(p_invmat,rot);
00178   }
00179 
00185   void Affine::Scale (double scaleFactor) {
00186     AMatrix scale = getIdentity();
00187     scale[0][0] = scaleFactor;
00188     scale[1][1] = scaleFactor;
00189     p_matrix = TNT::matmult(scale,p_matrix);
00190     
00191     scale[0][0] = scaleFactor;
00192     scale[1][1] = scaleFactor;
00193     p_invmat = TNT::matmult(p_invmat,scale);
00194   }
00195 
00203   void Affine::Compute(double x, double y) {
00204     p_x = x;
00205     p_y = y;
00206     p_xp = p_matrix[0][0] * x + p_matrix[0][1] * y + p_matrix[0][2];
00207     p_yp = p_matrix[1][0] * x + p_matrix[1][1] * y + p_matrix[1][2];
00208   }
00209 
00217   void Affine::ComputeInverse(double xp, double yp) {
00218     p_xp = xp;
00219     p_yp = yp;
00220     p_x = p_invmat[0][0] * xp + p_invmat[0][1] * yp + p_invmat[0][2];
00221     p_y = p_invmat[1][0] * xp + p_invmat[1][1] * yp + p_invmat[1][2];
00222   }
00223    
00230   vector<double> Affine::Coefficients( int var ) {
00231     int index = var-1;
00232     vector <double> coef;
00233     coef.push_back(p_matrix[index][0]);
00234     coef.push_back(p_matrix[index][1]);
00235     coef.push_back(p_matrix[index][2]);
00236     return coef;
00237   }
00238 
00245   vector<double> Affine::InverseCoefficients( int var ) {
00246      int index = var-1;
00247      vector <double> coef;
00248      coef.push_back(p_invmat[index][0]);
00249      coef.push_back(p_invmat[index][1]);
00250      coef.push_back(p_invmat[index][2]);
00251      return coef;
00252    }
00253 
00259   void Affine::checkDims(const AMatrix &am) const throw (iException &) {
00260     if ((am.dim1() != 3) && (am.dim2() != 3)) {
00261       ostringstream mess;
00262       mess << "Affine matrices must be 3x3 - this one is " << am.dim1()
00263            << "x" << am.dim2();
00264       throw iException::Message(iException::Programmer, mess.str(), _FILEINFO_);
00265     }
00266     return;
00267   }
00268 
00279   Affine::AMatrix Affine::invert(const AMatrix &a) const throw (iException &) {
00280    // Now compute the inverse affine matrix using singular value
00281     // decomposition A = USV'.  So invA = V invS U'.  Where ' represents
00282     // the transpose of a matrix and invS is S with the recipricol of the
00283     // diagonal elements
00284     JAMA::SVD<double> svd(a);
00285 
00286     AMatrix V;
00287     svd.getV(V);
00288 
00289     // The inverse of S is 1 over each diagonal element of S
00290     AMatrix invS;
00291     svd.getS(invS);
00292     for (int i=0; i<invS.dim1(); i++) {
00293       if (invS[i][i] == 0.0) {
00294         string msg = "Affine transform not invertible";
00295         throw iException::Message(iException::Math,msg,_FILEINFO_);
00296       }
00297       invS[i][i] = 1.0 / invS[i][i];
00298     }
00299 
00300     // Transpose U
00301     AMatrix U;
00302     svd.getU(U);
00303     AMatrix transU(U.dim2(),U.dim1());
00304     for (int r=0; r<U.dim1(); r++) {
00305       for (int c=0; c<U.dim2(); c++) {
00306         transU[c][r] = U[r][c];
00307       }
00308     }
00309 
00310     // Multiply stuff together to get the inverse of the affine
00311     AMatrix VinvS = TNT::matmult(V,invS);
00312     return (TNT::matmult(VinvS,transU));
00313   }
00314 
00315 } // end namespace isis