|
Isis 3.0 Object Programmers' Reference |
Home |
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