Isis 3 Programmer Reference
Affine.cpp
Go to the documentation of this file.
1 
22 #include "Affine.h"
23 
24 #include <vector>
25 #include <iostream>
26 #include <sstream>
27 #include <string>
28 
29 #include <jama/jama_svd.h>
30 
31 #include "Constants.h"
32 #include "IException.h"
33 #include "IString.h"
34 #include "LeastSquares.h"
35 #include "PolynomialBivariate.h"
36 
37 using namespace std;
38 
39 namespace Isis {
44  Affine::Affine() {
45  Identity();
46  p_x = p_y = p_xp = p_yp = 0.0;
47  }
48 
60  Affine::Affine(const Affine::AMatrix &a) {
61  checkDims(a);
62  p_matrix = a.copy();
63  p_invmat = invert(p_matrix);
64  p_x = p_y = p_xp = p_yp = 0.0;
65  }
66 
68  Affine::~Affine() {}
69 
75  Affine::AMatrix Affine::getIdentity() {
76  AMatrix ident(3, 3, 0.0);
77  for(int i = 0 ; i < ident.dim2() ; i++) {
78  ident[i][i] = 1.0;
79  }
80  return (ident);
81  }
82 
87  void Affine::Identity() {
88  p_matrix = getIdentity();
89  p_invmat = getIdentity();
90  }
91 
106  void Affine::Solve(const double x[], const double y[],
107  const double xp[], const double yp[], int n) {
108  // We must solve two least squares equations
109  PolynomialBivariate xpFunc(1);
110  PolynomialBivariate ypFunc(1);
111  LeastSquares xpLSQ(xpFunc);
112  LeastSquares ypLSQ(ypFunc);
113 
114  // Push the knowns into the least squares class
115  for(int i = 0; i < n; i++) {
116  vector<double> coord(2);
117  coord[0] = x[i];
118  coord[1] = y[i];
119  xpLSQ.AddKnown(coord, xp[i]);
120  ypLSQ.AddKnown(coord, yp[i]);
121  }
122 
123  // Solve for A,B,C,D,E,F
124  xpLSQ.Solve();
125  ypLSQ.Solve();
126 
127  // Construct our affine matrix
128  p_matrix[0][0] = xpFunc.Coefficient(1); // A
129  p_matrix[0][1] = xpFunc.Coefficient(2); // B
130  p_matrix[0][2] = xpFunc.Coefficient(0); // C
131  p_matrix[1][0] = ypFunc.Coefficient(1); // D
132  p_matrix[1][1] = ypFunc.Coefficient(2); // E
133  p_matrix[1][2] = ypFunc.Coefficient(0); // F
134  p_matrix[2][0] = 0.0;
135  p_matrix[2][1] = 0.0;
136  p_matrix[2][2] = 1.0;
137 
138  // invert the matrix
139  p_invmat = invert(p_matrix);
140  }
141 
148  void Affine::Translate(double tx, double ty) {
149  AMatrix trans = getIdentity();
150 
151  trans[0][2] = tx;
152  trans[1][2] = ty;
153  p_matrix = TNT::matmult(trans, p_matrix);
154 
155  trans[0][2] = -tx;
156  trans[1][2] = -ty;
157  p_invmat = TNT::matmult(p_invmat, trans);
158  }
159 
165  void Affine::Rotate(double angle) {
166  AMatrix rot = getIdentity();
167 
168  double angleRadians = angle * Isis::PI / 180.0;
169  rot[0][0] = cos(angleRadians);
170  rot[0][1] = -sin(angleRadians);
171  rot[1][0] = sin(angleRadians);
172  rot[1][1] = cos(angleRadians);
173  p_matrix = TNT::matmult(rot, p_matrix);
174 
175  angleRadians = -angleRadians;
176  rot[0][0] = cos(angleRadians);
177  rot[0][1] = -sin(angleRadians);
178  rot[1][0] = sin(angleRadians);
179  rot[1][1] = cos(angleRadians);
180  p_invmat = TNT::matmult(p_invmat, rot);
181  }
182 
188  void Affine::Scale(double scaleFactor) {
189  AMatrix scale = getIdentity();
190  scale[0][0] = scaleFactor;
191  scale[1][1] = scaleFactor;
192  p_matrix = TNT::matmult(scale, p_matrix);
193 
194  // Invert for inverse translation
195  p_invmat = invert(p_matrix);
196  }
197 
205  void Affine::Compute(double x, double y) {
206  p_x = x;
207  p_y = y;
208  p_xp = p_matrix[0][0] * x + p_matrix[0][1] * y + p_matrix[0][2];
209  p_yp = p_matrix[1][0] * x + p_matrix[1][1] * y + p_matrix[1][2];
210  }
211 
219  void Affine::ComputeInverse(double xp, double yp) {
220  p_xp = xp;
221  p_yp = yp;
222  p_x = p_invmat[0][0] * xp + p_invmat[0][1] * yp + p_invmat[0][2];
223  p_y = p_invmat[1][0] * xp + p_invmat[1][1] * yp + p_invmat[1][2];
224  }
225 
234  vector<double> Affine::Coefficients(int var) {
235  int index = var - 1;
236  vector <double> coef;
237  coef.push_back(p_matrix[index][0]);
238  coef.push_back(p_matrix[index][1]);
239  coef.push_back(p_matrix[index][2]);
240  return coef;
241  }
242 
251  vector<double> Affine::InverseCoefficients(int var) {
252  int index = var - 1;
253  vector <double> coef;
254  coef.push_back(p_invmat[index][0]);
255  coef.push_back(p_invmat[index][1]);
256  coef.push_back(p_invmat[index][2]);
257  return coef;
258  }
259 
265  void Affine::checkDims(const AMatrix &am) const {
266  if((am.dim1() != 3) && (am.dim2() != 3)) {
267  ostringstream mess;
268  mess << "Affine matrices must be 3x3 - this one is " << am.dim1()
269  << "x" << am.dim2();
270  throw IException(IException::Programmer, mess.str(), _FILEINFO_);
271  }
272  return;
273  }
274 
285  Affine::AMatrix Affine::invert(const AMatrix &a) const {
286  // Now compute the inverse affine matrix using singular value
287  // decomposition A = USV'. So invA = V invS U'. Where ' represents
288  // the transpose of a matrix and invS is S with the recipricol of the
289  // diagonal elements
290  JAMA::SVD<double> svd(a);
291 
292  AMatrix V;
293  svd.getV(V);
294 
295  // The inverse of S is 1 over each diagonal element of S
296  AMatrix invS;
297  svd.getS(invS);
298  for(int i = 0; i < invS.dim1(); i++) {
299  if(invS[i][i] == 0.0) {
300  string msg = "Affine transform not invertible";
301  throw IException(IException::Unknown, msg, _FILEINFO_);
302  }
303  invS[i][i] = 1.0 / invS[i][i];
304  }
305 
306  // Transpose U
307  AMatrix U;
308  svd.getU(U);
309  AMatrix transU(U.dim2(), U.dim1());
310  for(int r = 0; r < U.dim1(); r++) {
311  for(int c = 0; c < U.dim2(); c++) {
312  transU[c][r] = U[r][c];
313  }
314  }
315 
316  // Multiply stuff together to get the inverse of the affine
317  AMatrix VinvS = TNT::matmult(V, invS);
318  return (TNT::matmult(VinvS, transU));
319  }
320 
321 } // end namespace isis
const double PI
The mathematical constant PI.
Definition: Constants.h:56
Nth degree Polynomial with two variables.
Namespace for the standard library.
TNT::Array2D< double > AMatrix
Affine Matrix.
Definition: Affine.h:82
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
Generic least square fitting class.
Definition: LeastSquares.h:115
void AddKnown(const std::vector< double > &input, double expected, double weight=1.0)
Invoke this method for each set of knowns.
double Coefficient(int i) const
Returns the ith coefficient.
Isis exception class.
Definition: IException.h:107
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
int Solve(Isis::LeastSquares::SolveMethod method=SVD)
After all the data has been registered through AddKnown, invoke this method to solve the system of eq...