USGS

Isis 3.0 Object Programmers' Reference

Home

Affine.cpp
Go to the documentation of this file.
1 
22 #include "Affine.h"
23 
24 #include <vector>
25 #include <iostream>
26 #include <string>
27 
28 #include <jama/jama_svd.h>
29 
30 #include "Constants.h"
31 #include "IException.h"
32 #include "IString.h"
33 #include "LeastSquares.h"
34 #include "PolynomialBivariate.h"
35 
36 using namespace std;
37 
38 namespace Isis {
43  Affine::Affine() {
44  Identity();
45  p_x = p_y = p_xp = p_yp = 0.0;
46  }
47 
59  Affine::Affine(const Affine::AMatrix &a) {
60  checkDims(a);
61  p_matrix = a.copy();
62  p_invmat = invert(p_matrix);
63  p_x = p_y = p_xp = p_yp = 0.0;
64  }
65 
67  Affine::~Affine() {}
68 
74  Affine::AMatrix Affine::getIdentity() {
75  AMatrix ident(3, 3, 0.0);
76  for(int i = 0 ; i < ident.dim2() ; i++) {
77  ident[i][i] = 1.0;
78  }
79  return (ident);
80  }
81 
86  void Affine::Identity() {
87  p_matrix = getIdentity();
88  p_invmat = getIdentity();
89  }
90 
105  void Affine::Solve(const double x[], const double y[],
106  const double xp[], const double yp[], int n) {
107  // We must solve two least squares equations
108  PolynomialBivariate xpFunc(1);
109  PolynomialBivariate ypFunc(1);
110  LeastSquares xpLSQ(xpFunc);
111  LeastSquares ypLSQ(ypFunc);
112 
113  // Push the knowns into the least squares class
114  for(int i = 0; i < n; i++) {
115  vector<double> coord(2);
116  coord[0] = x[i];
117  coord[1] = y[i];
118  xpLSQ.AddKnown(coord, xp[i]);
119  ypLSQ.AddKnown(coord, yp[i]);
120  }
121 
122  // Solve for A,B,C,D,E,F
123  xpLSQ.Solve();
124  ypLSQ.Solve();
125 
126  // Construct our affine matrix
127  p_matrix[0][0] = xpFunc.Coefficient(1); // A
128  p_matrix[0][1] = xpFunc.Coefficient(2); // B
129  p_matrix[0][2] = xpFunc.Coefficient(0); // C
130  p_matrix[1][0] = ypFunc.Coefficient(1); // D
131  p_matrix[1][1] = ypFunc.Coefficient(2); // E
132  p_matrix[1][2] = ypFunc.Coefficient(0); // F
133  p_matrix[2][0] = 0.0;
134  p_matrix[2][1] = 0.0;
135  p_matrix[2][2] = 1.0;
136 
137  // invert the matrix
138  p_invmat = invert(p_matrix);
139  }
140 
147  void Affine::Translate(double tx, double ty) {
148  AMatrix trans = getIdentity();
149 
150  trans[0][2] = tx;
151  trans[1][2] = ty;
152  p_matrix = TNT::matmult(trans, p_matrix);
153 
154  trans[0][2] = -tx;
155  trans[1][2] = -ty;
156  p_invmat = TNT::matmult(p_invmat, trans);
157  }
158 
164  void Affine::Rotate(double angle) {
165  AMatrix rot = getIdentity();
166 
167  double angleRadians = angle * Isis::PI / 180.0;
168  rot[0][0] = cos(angleRadians);
169  rot[0][1] = -sin(angleRadians);
170  rot[1][0] = sin(angleRadians);
171  rot[1][1] = cos(angleRadians);
172  p_matrix = TNT::matmult(rot, p_matrix);
173 
174  angleRadians = -angleRadians;
175  rot[0][0] = cos(angleRadians);
176  rot[0][1] = -sin(angleRadians);
177  rot[1][0] = sin(angleRadians);
178  rot[1][1] = cos(angleRadians);
179  p_invmat = TNT::matmult(p_invmat, rot);
180  }
181 
187  void Affine::Scale(double scaleFactor) {
188  AMatrix scale = getIdentity();
189  scale[0][0] = scaleFactor;
190  scale[1][1] = scaleFactor;
191  p_matrix = TNT::matmult(scale, p_matrix);
192 
193  // Invert for inverse translation
194  p_invmat = invert(p_matrix);
195  }
196 
204  void Affine::Compute(double x, double y) {
205  p_x = x;
206  p_y = y;
207  p_xp = p_matrix[0][0] * x + p_matrix[0][1] * y + p_matrix[0][2];
208  p_yp = p_matrix[1][0] * x + p_matrix[1][1] * y + p_matrix[1][2];
209  }
210 
218  void Affine::ComputeInverse(double xp, double yp) {
219  p_xp = xp;
220  p_yp = yp;
221  p_x = p_invmat[0][0] * xp + p_invmat[0][1] * yp + p_invmat[0][2];
222  p_y = p_invmat[1][0] * xp + p_invmat[1][1] * yp + p_invmat[1][2];
223  }
224 
231  vector<double> Affine::Coefficients(int var) {
232  int index = var - 1;
233  vector <double> coef;
234  coef.push_back(p_matrix[index][0]);
235  coef.push_back(p_matrix[index][1]);
236  coef.push_back(p_matrix[index][2]);
237  return coef;
238  }
239 
246  vector<double> Affine::InverseCoefficients(int var) {
247  int index = var - 1;
248  vector <double> coef;
249  coef.push_back(p_invmat[index][0]);
250  coef.push_back(p_invmat[index][1]);
251  coef.push_back(p_invmat[index][2]);
252  return coef;
253  }
254 
260  void Affine::checkDims(const AMatrix &am) const {
261  if((am.dim1() != 3) && (am.dim2() != 3)) {
262  ostringstream mess;
263  mess << "Affine matrices must be 3x3 - this one is " << am.dim1()
264  << "x" << am.dim2();
265  throw IException(IException::Programmer, mess.str(), _FILEINFO_);
266  }
267  return;
268  }
269 
280  Affine::AMatrix Affine::invert(const AMatrix &a) const {
281  // Now compute the inverse affine matrix using singular value
282  // decomposition A = USV'. So invA = V invS U'. Where ' represents
283  // the transpose of a matrix and invS is S with the recipricol of the
284  // diagonal elements
285  JAMA::SVD<double> svd(a);
286 
287  AMatrix V;
288  svd.getV(V);
289 
290  // The inverse of S is 1 over each diagonal element of S
291  AMatrix invS;
292  svd.getS(invS);
293  for(int i = 0; i < invS.dim1(); i++) {
294  if(invS[i][i] == 0.0) {
295  string msg = "Affine transform not invertible";
296  throw IException(IException::Unknown, msg, _FILEINFO_);
297  }
298  invS[i][i] = 1.0 / invS[i][i];
299  }
300 
301  // Transpose U
302  AMatrix U;
303  svd.getU(U);
304  AMatrix transU(U.dim2(), U.dim1());
305  for(int r = 0; r < U.dim1(); r++) {
306  for(int c = 0; c < U.dim2(); c++) {
307  transU[c][r] = U[r][c];
308  }
309  }
310 
311  // Multiply stuff together to get the inverse of the affine
312  AMatrix VinvS = TNT::matmult(V, invS);
313  return (TNT::matmult(VinvS, transU));
314  }
315 
316 } // end namespace isis