Isis 3 Programmer Reference
Affine.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7
8#include "Affine.h"
9
10#include <vector>
11#include <iostream>
12#include <sstream>
13#include <string>
14
15#include <jama/jama_svd.h>
16
17#include "Constants.h"
18#include "IException.h"
19#include "IString.h"
20#include "LeastSquares.h"
21#include "PolynomialBivariate.h"
22
23using namespace std;
24
25namespace Isis {
31 Identity();
32 p_x = p_y = p_xp = p_yp = 0.0;
33 }
34
47 checkDims(a);
48 p_matrix = a.copy();
50 p_x = p_y = p_xp = p_yp = 0.0;
51 }
52
55
62 AMatrix ident(3, 3, 0.0);
63 for(int i = 0 ; i < ident.dim2() ; i++) {
64 ident[i][i] = 1.0;
65 }
66 return (ident);
67 }
68
77
92 void Affine::Solve(const double x[], const double y[],
93 const double xp[], const double yp[], int n) {
94 // We must solve two least squares equations
95 PolynomialBivariate xpFunc(1);
96 PolynomialBivariate ypFunc(1);
97 LeastSquares xpLSQ(xpFunc);
98 LeastSquares ypLSQ(ypFunc);
99
100 // Push the knowns into the least squares class
101 for(int i = 0; i < n; i++) {
102 vector<double> coord(2);
103 coord[0] = x[i];
104 coord[1] = y[i];
105 xpLSQ.AddKnown(coord, xp[i]);
106 ypLSQ.AddKnown(coord, yp[i]);
107 }
108
109 // Solve for A,B,C,D,E,F
110 xpLSQ.Solve();
111 ypLSQ.Solve();
112
113 // Construct our affine matrix
114 p_matrix[0][0] = xpFunc.Coefficient(1); // A
115 p_matrix[0][1] = xpFunc.Coefficient(2); // B
116 p_matrix[0][2] = xpFunc.Coefficient(0); // C
117 p_matrix[1][0] = ypFunc.Coefficient(1); // D
118 p_matrix[1][1] = ypFunc.Coefficient(2); // E
119 p_matrix[1][2] = ypFunc.Coefficient(0); // F
120 p_matrix[2][0] = 0.0;
121 p_matrix[2][1] = 0.0;
122 p_matrix[2][2] = 1.0;
123
124 // invert the matrix
126 }
127
134 void Affine::Translate(double tx, double ty) {
135 AMatrix trans = getIdentity();
136
137 trans[0][2] = tx;
138 trans[1][2] = ty;
139 p_matrix = TNT::matmult(trans, p_matrix);
140
141 trans[0][2] = -tx;
142 trans[1][2] = -ty;
143 p_invmat = TNT::matmult(p_invmat, trans);
144 }
145
151 void Affine::Rotate(double angle) {
152 AMatrix rot = getIdentity();
153
154 double angleRadians = angle * Isis::PI / 180.0;
155 rot[0][0] = cos(angleRadians);
156 rot[0][1] = -sin(angleRadians);
157 rot[1][0] = sin(angleRadians);
158 rot[1][1] = cos(angleRadians);
159 p_matrix = TNT::matmult(rot, p_matrix);
160
161 angleRadians = -angleRadians;
162 rot[0][0] = cos(angleRadians);
163 rot[0][1] = -sin(angleRadians);
164 rot[1][0] = sin(angleRadians);
165 rot[1][1] = cos(angleRadians);
166 p_invmat = TNT::matmult(p_invmat, rot);
167 }
168
174 void Affine::Scale(double scaleFactor) {
175 AMatrix scale = getIdentity();
176 scale[0][0] = scaleFactor;
177 scale[1][1] = scaleFactor;
178 p_matrix = TNT::matmult(scale, p_matrix);
179
180 // Invert for inverse translation
182 }
183
191 void Affine::Compute(double x, double y) {
192 p_x = x;
193 p_y = y;
194 p_xp = p_matrix[0][0] * x + p_matrix[0][1] * y + p_matrix[0][2];
195 p_yp = p_matrix[1][0] * x + p_matrix[1][1] * y + p_matrix[1][2];
196 }
197
205 void Affine::ComputeInverse(double xp, double yp) {
206 p_xp = xp;
207 p_yp = yp;
208 p_x = p_invmat[0][0] * xp + p_invmat[0][1] * yp + p_invmat[0][2];
209 p_y = p_invmat[1][0] * xp + p_invmat[1][1] * yp + p_invmat[1][2];
210 }
211
220 vector<double> Affine::Coefficients(int var) {
221 int index = var - 1;
222 vector <double> coef;
223 coef.push_back(p_matrix[index][0]);
224 coef.push_back(p_matrix[index][1]);
225 coef.push_back(p_matrix[index][2]);
226 return coef;
227 }
228
237 vector<double> Affine::InverseCoefficients(int var) {
238 int index = var - 1;
239 vector <double> coef;
240 coef.push_back(p_invmat[index][0]);
241 coef.push_back(p_invmat[index][1]);
242 coef.push_back(p_invmat[index][2]);
243 return coef;
244 }
245
251 void Affine::checkDims(const AMatrix &am) const {
252 if((am.dim1() != 3) && (am.dim2() != 3)) {
253 ostringstream mess;
254 mess << "Affine matrices must be 3x3 - this one is " << am.dim1()
255 << "x" << am.dim2();
256 throw IException(IException::Programmer, mess.str(), _FILEINFO_);
257 }
258 return;
259 }
260
272 // Now compute the inverse affine matrix using singular value
273 // decomposition A = USV'. So invA = V invS U'. Where ' represents
274 // the transpose of a matrix and invS is S with the recipricol of the
275 // diagonal elements
276 JAMA::SVD<double> svd(a);
277
278 AMatrix V;
279 svd.getV(V);
280
281 // The inverse of S is 1 over each diagonal element of S
282 AMatrix invS;
283 svd.getS(invS);
284 for(int i = 0; i < invS.dim1(); i++) {
285 if(invS[i][i] == 0.0) {
286 string msg = "Affine transform not invertible";
287 throw IException(IException::Unknown, msg, _FILEINFO_);
288 }
289 invS[i][i] = 1.0 / invS[i][i];
290 }
291
292 // Transpose U
293 AMatrix U;
294 svd.getU(U);
295 AMatrix transU(U.dim2(), U.dim1());
296 for(int r = 0; r < U.dim1(); r++) {
297 for(int c = 0; c < U.dim2(); c++) {
298 transU[c][r] = U[r][c];
299 }
300 }
301
302 // Multiply stuff together to get the inverse of the affine
303 AMatrix VinvS = TNT::matmult(V, invS);
304 return (TNT::matmult(VinvS, transU));
305 }
306
307} // end namespace isis
std::vector< double > Coefficients(int var)
Return the affine coeffients for the entered variable (1 or 2).
Definition Affine.cpp:220
void ComputeInverse(double xp, double yp)
Compute (x,y) given (xp,yp).
Definition Affine.cpp:205
double xp() const
Returns the computed x'.
Definition Affine.h:86
double p_xp
x' value of the (x',y') coordinate
Definition Affine.h:146
double y() const
Returns the computed y.
Definition Affine.h:115
AMatrix p_matrix
Affine forward matrix.
Definition Affine.h:141
AMatrix p_invmat
Affine inverse matrix.
Definition Affine.h:142
void Translate(double tx, double ty)
Apply a translation to the current affine transform.
Definition Affine.cpp:134
static AMatrix getIdentity()
Return an Affine identity matrix.
Definition Affine.cpp:61
double yp() const
Returns the computed y'.
Definition Affine.h:95
double p_yp
y' value of the (x',y') coordinate
Definition Affine.h:147
TNT::Array2D< double > AMatrix
Affine Matrix.
Definition Affine.h:67
void Scale(double scaleFactor)
Apply a scale to the current affine transform.
Definition Affine.cpp:174
AMatrix invert(const AMatrix &a) const
Compute the inverse of a matrix.
Definition Affine.cpp:271
double p_y
y value of the (x,y) coordinate
Definition Affine.h:145
void Compute(double x, double y)
Compute (xp,yp) given (x,y).
Definition Affine.cpp:191
~Affine()
Destroys the Affine object.
Definition Affine.cpp:54
double p_x
x value of the (x,y) coordinate
Definition Affine.h:144
Affine()
Constructs an Affine transform.
Definition Affine.cpp:30
void Identity()
Set the forward and inverse affine transform to the identity.
Definition Affine.cpp:73
void Solve(const double x[], const double y[], const double xp[], const double yp[], int n)
Given a set of coordinate pairs (n >= 3), compute the affine transform that best fits the points.
Definition Affine.cpp:92
void checkDims(const AMatrix &am) const
Checks affine matrix to ensure it is a 3x3 standard form transform.
Definition Affine.cpp:251
std::vector< double > InverseCoefficients(int var)
Return the inverse affine coeffients for the entered variable (1 or 2).
Definition Affine.cpp:237
void Rotate(double rot)
Apply a translation to the current affine transform.
Definition Affine.cpp:151
double x() const
Returns the computed x.
Definition Affine.h:106
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
Generic least square fitting class.
Nth degree Polynomial with two variables.
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
const double PI
The mathematical constant PI.
Definition Constants.h:40
Namespace for the standard library.