File failed to load: https://isis.astrogeology.usgs.gov/6.0.0/Object/assets/jax/output/NativeMML/config.js
Isis 3 Programmer Reference
LinearAlgebra.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "LinearAlgebra.h"
8 
9 // std library
10 #include <cmath>
11 
12 // Qt Library
13 #include <QDebug>
14 #include <QtDebug>
15 #include <QtGlobal>
16 
17 // boost library
18 #include <boost/assign/std/vector.hpp>
19 #include <boost/numeric/ublas/io.hpp>
20 #include <boost/numeric/ublas/matrix.hpp>
21 #include <boost/numeric/ublas/matrix_proxy.hpp>
22 
23 // Armadillo
24 #include <armadillo>
25 
26 // other Isis library
27 #include "Angle.h"
28 #include "Constants.h"
29 #include "IException.h"
30 #include "IString.h"
31 
32 
33 namespace Isis {
40  }
41 
42 
47  }
48 
49 
61  bool LinearAlgebra::isIdentity(const Matrix &matrix) {
62  if (matrix.size1() != matrix.size2()) return false;
63 
64  for (unsigned int row = 0; row < matrix.size1(); row++) {
65  for (unsigned int col = 0; col < matrix.size2(); col++) {
66  if (row == col) {
67  if (!qFuzzyCompare(matrix(row, col), 1.0)) return false;
68  }
69  else {
70  // When using qFuzzy compare against a number that is zero
71  // you must offset the number per Qt documentation
72  if (!qFuzzyCompare(1.0 + matrix(row, col), 1.0)) return false;
73  }
74  }
75  }
76  return true;
77  }
78 
79 
89  bool LinearAlgebra::isOrthogonal(const Matrix &matrix) {
90  if (matrix.size1() != matrix.size2()) return false;
92  if (isIdentity(test)) {
93  // no need to test that transpose is both left and right inverse since the matrix is square
94  return true;
95  }
96  return false;
97  }
98 
99 
112  // derived from naif's isrot routine
114  // rotation matrices must be square
115  if (matrix.size1() != matrix.size2()) return false;
116 
117  /* An exerpt from NAIF's isrot() routine...
118  *
119  * A property of rotation matrices is that their columns form a
120  * right-handed, orthonormal basis in 3-dimensional space. The
121  * converse is true: all 3x3 matrices with this property are
122  * rotation matrices.
123  *
124  * An ordered set of three vectors V1, V2, V3 forms a right-handed,
125  * orthonormal basis if and only if
126  *
127  * 1) || V1 || = || V2 || = || V3 || = 1
128  *
129  * 2) V3 = V1 x V2. Since V1, V2, and V3 are unit vectors,
130  * we also have
131  *
132  * < V3, V1 x V2 > = 1.
133  *
134  * This quantity is the determinant of the matrix whose
135  * colums are V1, V2 and V3.
136  *
137  * When finite precision numbers are used, rotation matrices will
138  * usually fail to satisfy these criteria exactly. We must use
139  * criteria that indicate approximate conformance to the criteria
140  * listed above. We choose
141  *
142  * 1) | || Vi || - 1 | < NTOL, i = 1, 2, 3.
143  * -
144  *
145  * 2) Let
146  *
147  * Vi
148  * Ui = ------ , i = 1, 2, 3.
149  * ||Vi||
150  *
151  * Then we require
152  *
153  * | < U3, U1 x U2 > - 1 | < DTOL;
154  * -
155  *
156  * equivalently, letting U be the matrix whose columns
157  * are U1, U2, and U3, we insist on
158  *
159  * | det(U) - 1 | < DTOL.
160  * _
161  * The columns of M must resemble unit vectors. If the norms are
162  * outside of the allowed range, M is not a rotation matrix.
163  *
164  * Also, the columns of M are required to be pretty nearly orthogonal. The
165  * discrepancy is gauged by taking the determinant of the matrix UNIT,
166  * computed below, whose columns are the unitized columns of M.
167  */
168 
169  // create a matrix whose columns are unit vectors of the columns of the
170  // given matrix
171  Matrix unitMatrix(matrix.size1(), matrix.size2());
172 
173  for (unsigned int i = 0; i < unitMatrix.size1(); i++) {
174  // get the ith column vector from the given matrix
175  Vector columnVector = column(matrix, i);
176  // get the magnitude and if it is not near 1, this is not a rotation matrix
177  double columnMagnitude = magnitude(columnVector);
178  if ( columnMagnitude < 0.9 || columnMagnitude > 1.1 ) {
179  return false;
180  }
181 
182  // put the unitized row into the unitized matrix
183  setColumn(unitMatrix, columnVector / columnMagnitude, i);
184 
185  }
186 
187  try {
188  // get the determinant of the unitized matrix and if it is not near 1,
189  // this is not a rotation matrix
190  double det = determinant(unitMatrix);
191  if ( det >= 0.9 && det <= 1.1 ) {
192  return true;
193  }
194  }
195  catch (IException &e) {
196  // since we can only calculate the determinant for 2x2 or 3x3
197  QString msg = "Unable to determine whether the given matrix is a rotation matrix.";
198  throw IException(e, IException::Programmer, msg, _FILEINFO_);
199  }
200  return false;
201  }
202 
203 
211  bool LinearAlgebra::isZero(const Matrix &matrix) {
212  for (unsigned int i = 0; i < matrix.size1(); i++) {
213  for (unsigned int j = 0; j < matrix.size2(); j++) {
214  // When using qFuzzy compare against a number that is zero
215  // you must offset the number per Qt documentation
216  if (!qFuzzyCompare(matrix(i, j) + 1.0, 1.0)) return false;
217  }
218  }
219 
220  return true;
221  }
222 
223 
231  bool LinearAlgebra::isZero(const Vector &vector) {
232  for (unsigned int i = 0; i < vector.size(); i++) {
233  // When using qFuzzy compare against a number that is zero
234  // you must offset the number per Qt documentation
235  if (!qFuzzyCompare(vector(i) + 1.0, 1.0)) return false;
236  }
237 
238  return true;
239  }
240 
241 
251  return vector.empty();
252  }
253 
254 
262  bool LinearAlgebra::isUnit(const Vector &vector) {
263  if (qFuzzyCompare(dotProduct(vector, vector), 1.0)) {
264  return true;
265  }
266  return false;
267  }
268 
269 
283  try {
284  if (isOrthogonal(matrix)) {
285  return transpose(matrix);
286  }
287 
288  // the determinant method will verify the size of the matrix is 2x2 or 3x3
289  double det = determinant(matrix);
290 
291  if (qFuzzyCompare(det + 1.0, 1.0)) {
292  // the inverse exists <==> the determinant is not 0.0
293  QString msg = "The given matrix is not invertible. The determinant is 0.0.";
294  throw IException(IException::Programmer, msg, _FILEINFO_);
295  }
296 
297  // since the determinant is not zero, we can calculate the reciprocal
298  double scale = 1 / det;
299 
300  LinearAlgebra::Matrix inverse = identity(matrix.size1());
301  // find the inverse for 2x2
302  if (matrix.size1() == 2) {
303  inverse(0, 0) = scale * matrix(1, 1);
304  inverse(0, 1) = -scale * matrix(0, 1);
305 
306  inverse(1, 0) = -scale * matrix(1, 0);
307  inverse(1, 1) = scale * matrix(0, 0);
308  return inverse;
309  }
310  // else we have a 3x3
311  inverse(0, 0) = scale * ( matrix(1, 1) * matrix(2, 2) - matrix(2, 1) * matrix(1, 2) );
312  inverse(0, 1) = scale * ( matrix(0, 2) * matrix(2, 1) - matrix(2, 2) * matrix(0, 1) );
313  inverse(0, 2) = scale * ( matrix(0, 1) * matrix(1, 2) - matrix(1, 1) * matrix(0, 2) );
314 
315  inverse(1, 0) = scale * ( matrix(1, 2) * matrix(2, 0) - matrix(2, 2) * matrix(1, 0) );
316  inverse(1, 1) = scale * ( matrix(0, 0) * matrix(2, 2) - matrix(2, 0) * matrix(0, 2) );
317  inverse(1, 2) = scale * ( matrix(0, 2) * matrix(0, 1) - matrix(1, 2) * matrix(0, 0) );
318 
319  inverse(2, 0) = scale * ( matrix(1, 0) * matrix(2, 1) - matrix(2, 0) * matrix(1, 1) );
320  inverse(2, 1) = scale * ( matrix(0, 1) * matrix(2, 0) - matrix(2, 1) * matrix(0, 0) );
321  inverse(2, 2) = scale * ( matrix(0, 0) * matrix(1, 1) - matrix(1, 0) * matrix(0, 1) );
322 
323  return inverse;
324  }
325  catch (IException &e) {
326  QString msg = "Unable to invert the given matrix.";
327  throw IException(e, IException::Programmer, msg, _FILEINFO_);
328  }
329  }
330 
331 
340  // Copy values into Armadillo matrix
341  arma::mat arMat(matrix.size1(), matrix.size2());
342  for (size_t i = 0; i < matrix.size1(); i++) {
343  for (size_t j = 0; j < matrix.size2(); j++) {
344  arMat(i, j) = matrix(i, j);
345  }
346  }
347 
348  arma::mat invArMat = arma::pinv(arMat);
349 
350  // Copy values back to Boost matrix
351  LinearAlgebra::Matrix inverse(invArMat.n_rows, invArMat.n_cols);
352  for (size_t i = 0; i < invArMat.n_rows; i++) {
353  for (size_t j = 0; j < invArMat.n_cols; j++) {
354  inverse(i, j) = invArMat(i, j);
355  }
356  }
357 
358  return inverse;
359  }
360 
361 
370  // no error testing required so call the boost transpose function
371  return boost::numeric::ublas::trans(matrix);
372  }
373 
374 
385  if (size < 1) {
386  QString msg = "Can not create identity matrix of negative size ["
387  + toString((int) size) + "].";
388  throw IException(IException::Programmer, msg, _FILEINFO_);
389  }
390 
391  LinearAlgebra::Matrix m(size, size, 0.0);
392  for (int i = 0; i < size; i++) {
393  m(i, i) = 1.0;
394  }
395 
396  return m;
397  }
398 
399 
409  boost::numeric::ublas::zero_matrix<double> m(rows, columns);
410  return m;
411  }
412 
413 
422  boost::numeric::ublas::zero_vector<double> v(size);
423  return v;
424  }
425 
426 
440  double LinearAlgebra::determinant(const Matrix &matrix) {
441  if ( (matrix.size1() != matrix.size2()) || (matrix.size1() != 2 && matrix.size1() != 3) ) {
442  QString msg = "Unable to calculate the determinant for the given matrix. "
443  "This method only calculates the determinant for 2x2 or 3x3 matrices."
444  "The given matrix is [" + toString((int) matrix.size1()) + "x"
445  + toString((int) matrix.size2()) + "].";
446  throw IException(IException::Programmer, msg, _FILEINFO_);
447  }
448 
449  if (matrix.size1() == 2) {
450  return matrix(0, 0) * matrix(1, 1) - matrix(1, 0) * matrix(0, 1);
451  }
452  else {
453 
454  return matrix(0, 0) * (matrix(1, 1)*matrix(2, 2) - matrix(1, 2)*matrix(2, 1))
455  - matrix(0, 1) * (matrix(1, 0)*matrix(2, 2) - matrix(1, 2)*matrix(2, 0))
456  + matrix(0, 2) * (matrix(1, 0)*matrix(2, 1) - matrix(1, 1)*matrix(2, 0));
457  }
458 
459  }
460 
461 
478  // impossible to unitize the zero vector
480  QString msg = "Unable to normalize the zero vector.";
481  throw IException(IException::Unknown, msg, _FILEINFO_);
482  }
484  }
485 
486 
504  double LinearAlgebra::magnitude(const Vector &vector) {
505  double magnitude;
506  // avoid dividing by maxNorm = 0
507  // no stabilization is needed for the zero vector, magnitude is always 0.0
509  magnitude = 0.0;
510  }
511  else {
512  double maxNorm = LinearAlgebra::absoluteMaximum(vector);
513  magnitude = maxNorm * boost::numeric::ublas::norm_2(vector / maxNorm);
514  }
515  return magnitude;
516  }
517 
518 
531  double LinearAlgebra::absoluteMaximum(const Vector &vector) {
532  return boost::numeric::ublas::norm_inf(vector);
533  }
534 
535 
549  LinearAlgebra::Matrix LinearAlgebra::multiply(const Matrix &matrix1, const Matrix &matrix2) {
550  // Check to make sure we can multiply
551  if (matrix1.size2() != matrix2.size1()) {
552  QString msg = "Unable to multiply matrices with mismatched dimensions. "
553  "The left matrix has [" + toString((int) matrix1.size2())
554  + "] columns and the right matrix has [" + toString((int) matrix2.size1())
555  + "] rows.";
556 
557  throw IException(IException::Programmer, msg, _FILEINFO_);
558  }
559 
560  // Use boost product routine
561  return boost::numeric::ublas::prod(matrix1, matrix2);
562  }
563 
564 
581  // Check to make sure we can multiply
582  if (matrix.size2() != vector.size()) {
583  QString msg = "Unable to multiply matrix and vector with mismatched dimensions."
584  "The given vector has [" + toString((int) vector.size())
585  + "] components and the given matrix has ["
586  + toString((int) matrix.size2()) + "] columns.";
587  throw IException(IException::Programmer, msg, _FILEINFO_);
588  }
589 
590  // Use boost product routine
591  return boost::numeric::ublas::prod(matrix, vector);
592  }
593 
594 
603  LinearAlgebra::Vector LinearAlgebra::multiply(double scalar, const Vector &vector) {
604  // no error checks necessary (use the boost operator* method)
605  return scalar * vector;
606  }
607 
608 
617  LinearAlgebra::Matrix LinearAlgebra::multiply(double scalar, const Matrix &matrix) {
618  // no error checks necessary
619  return scalar * matrix;
620  }
621 
622 
634  LinearAlgebra::Vector LinearAlgebra::add(const Vector &vector1, const Vector &vector2) {
635  // Vectors best be the same size
636  if (vector1.size() != vector2.size()) {
637  QString msg = "Unable to add vectors with mismatched sizes."
638  "Vector1 has [" + toString((int) vector1.size())
639  + "] components and vector2 has ["
640  + toString((int) vector2.size()) + "] components.";
641  throw IException(IException::Programmer, msg, _FILEINFO_);
642  }
643 
644  return vector1 + vector2;
645  }
646 
647 
660  LinearAlgebra::Vector LinearAlgebra::subtract(const Vector &vector1, const Vector &vector2) {
661  // Vectors best be the same size
662  if (vector1.size() != vector2.size()) {
663  QString msg = "Unable to subtract vectors with mismatched sizes."
664  "Vector1 has [" + toString((int) vector1.size())
665  + "] components and vector2 has ["
666  + toString((int) vector2.size()) + "] components.";
667  throw IException(IException::Programmer, msg, _FILEINFO_);
668  }
669 
670  return vector1 - vector2;
671  }
672 
673 
689  if ((vector1.size() != 3) || (vector2.size() != 3)) {
690  QString msg = "Unable to calculate the cross product on vectors that are not size 3. "
691  "Vector1 has [" + toString((int) vector1.size())
692  + "] components and vector2 has ["
693  + toString((int) vector2.size()) + "] components.";
694  throw IException(IException::Programmer, msg, _FILEINFO_);
695  }
696 
697  Vector crossProd(3);
698  crossProd(0) = vector1(1)*vector2(2) - vector1(2)*vector2(1);
699  crossProd(1) = vector1(2)*vector2(0) - vector1(0)*vector2(2);
700  crossProd(2) = vector1(0)*vector2(1) - vector1(1)*vector2(0);
701 
702  return crossProd;
703  }
704 
705 
720  // is this derived from naif's ucrss routine???
722  const Vector &vector2) {
723 
724  double maxVector1 = LinearAlgebra::absoluteMaximum(vector1);
725  double maxVector2 = LinearAlgebra::absoluteMaximum(vector2);
726 
727  LinearAlgebra::Vector normalizedVector1 = vector1;
728  LinearAlgebra::Vector normalizedVector2 = vector2;
729 
730  if (maxVector1 != 0.0) {
731  normalizedVector1 /= maxVector1;
732  }
733 
734  if (maxVector2 != 0.0) {
735  normalizedVector2 /= maxVector2;
736  }
737 
738  LinearAlgebra::Vector vcross = crossProduct(normalizedVector1, normalizedVector2);
739 
740  return normalize(vcross);
741  }
742 
743 
758  if (vector1.size() != vector2.size()) {
759  QString msg = "Unable to compute the outer product for vectors with mismatched sizes."
760  "Vector1 has [" + toString((int) vector1.size())
761  + "] components and vector2 has ["
762  + toString((int) vector2.size()) + "] components.";
763  throw IException(IException::Programmer, msg, _FILEINFO_);
764  }
765  return boost::numeric::ublas::outer_prod(vector1, vector2);
766  }
767 
768 
781  double LinearAlgebra::dotProduct(const Vector &vector1, const Vector &vector2) {
782  // no error check needed - this is done by innerProduct
783  return LinearAlgebra::innerProduct(vector1, vector2);
784  }
785 
786 
801  double LinearAlgebra::innerProduct(const Vector &vector1, const Vector &vector2) {
802  if (vector1.size() != vector2.size()) {
803  QString msg = "Unable to compute the dot product for vectors with mismatched sizes."
804  "Vector1 has [" + toString((int) vector1.size())
805  + "] components and vector2 has ["
806  + toString((int) vector2.size()) + "] components.";
807  throw IException(IException::Programmer, msg, _FILEINFO_);
808  }
809  return boost::numeric::ublas::inner_prod(vector1, vector2);
810  }
811 
812 
832  // derived from naif's vproj routine
833  LinearAlgebra::Vector LinearAlgebra::project(const Vector &vector1, const Vector &vector2) {
834  if (vector1.size() != vector2.size()) {
835  QString msg = "Unable to project vector1 onto vector2 with mismatched sizes."
836  "Vector1 has [" + toString((int) vector1.size())
837  + "] components and vector2 has ["
838  + toString((int) vector2.size()) + "] components.";
839  throw IException(IException::Programmer, msg, _FILEINFO_);
840  }
841 
842  // if vector2 is the zero vector, then the projection of vector1 onto vector2
843  // is also the zero vector
844  if (LinearAlgebra::isZero(vector2)) return vector2;
845 
846  // find the dot product of the two vectors
847  double v1Dotv2 = LinearAlgebra::dotProduct(vector1, vector2);
848 
849  // find the square of the length of vector2 (this is the dot product of the vector2 with itself)
850  double v2Dotv2 = LinearAlgebra::dotProduct(vector2, vector2);
851 
852  return v1Dotv2/v2Dotv2 * vector2;
853  }
854 
855 
871  // derived from naif's vrotv routine
873  Angle angle) {
874  if ((vector.size() != 3) || (axis.size() != 3)) {
875  QString msg = "Unable to rotate vector about the given axis and angle. "
876  "Vectors must be of size 3 to perform rotation. "
877  "The given vector has [" + toString((int) vector.size())
878  + "] components and the given axis has ["
879  + toString((int) axis.size()) + "] components.";
880  throw IException(IException::Programmer, msg, _FILEINFO_);
881  }
882 
883  // if the given vector is the zero vector, then the rotation about the vector
884  // is also the zero vector
885  if (isZero(axis)) return vector;
886 
887  // Compute the unit vector that is codirectional with the given axis
888  Vector axisUnitVector = normalize(axis);
889 
890  // Compute the projection of the given vector onto the axis unit vector.
891  Vector projVectorOnAxis = project(vector, axisUnitVector);
892 
893  // Compute the component of the input orthogonal to the AXIS. Call it V1.
894  Vector v1 = vector - projVectorOnAxis;
895 
896  // Rotate V1 by 90 degrees about the AXIS and call the result V2.
897  Vector v2 = LinearAlgebra::crossProduct(axisUnitVector, v1);
898 
899  // Compute cos(angle)*v1 + sin(angle)*v2. This is v1 rotated about
900  // the axis in the plane normal to the axis, call the result rplane
901  double c = cos(angle.radians());
902  double s = sin(angle.radians());
903  Vector rplane = (c*v1) + (s*v2);
904 
905  // Add the rotated component in the normal plane to axis to the
906  // projection of v onto axis to obtain rotation.
907  return (rplane + projVectorOnAxis);
908  }
909 
910 
929  // Derived from NAIF's vperp routine
930  // possible that we may need to restrict size to dimesion 3, but doesn't seem
931  // necessary in the code.
933 
934  // if vector1 is the zero vector, just set p to zero and return.
935  if ( isZero(vector1) ) {
936  return vector1;
937  }
938 
939  // if vector2 is the zero vector, just set p to vector1 and return.
940  if ( isZero(vector2) ) {
941  return vector1;
942  }
943 
944  // normalize (using the max norm) the given vectors and project the first onto the second
945  double max1 = absoluteMaximum(vector1);
946  double max2 = absoluteMaximum(vector2);
947  Vector parallelVector = project(vector1 / max1, vector2 / max2);
948 
949  Vector perpendicularVector = vector1 - parallelVector * max1;
950 
951  return perpendicularVector;
952 
953  }
954 
955 
972  // Derived from NAIF's raxisa routine
974 
975  if ((rotationMatrix.size1() != 3) || (rotationMatrix.size2() != 3)) {
976  QString msg = "Unable to convert the given matrix to an axis of rotation "
977  "and a rotation angle. A 3x3 matrix is required. The given matrix is ["
978  + toString((int) rotationMatrix.size1()) + "x"
979  + toString((int) rotationMatrix.size2()) + "].";
980  throw IException(IException::Programmer, msg, _FILEINFO_);
981  }
982 
983  // if given matrix is not a rotation matrix, we can't proceed.
984  if ( !isRotationMatrix(rotationMatrix) ) {
985  QString msg = "Unable to convert the given matrix to an axis of rotation "
986  "and a rotation angle. The given matrix is not a rotation matrix.";
987  throw IException(IException::Programmer, msg, _FILEINFO_);
988  }
989 
990  Angle angle;
991  Vector axis(3);
992 
993  // Construct the quaternion corresponding to the input rotation matrix
994  Vector quaternion = LinearAlgebra::toQuaternion(rotationMatrix);
995 
996  LinearAlgebra::Vector subQuaternion(3);
997  subQuaternion[0] = quaternion[1];
998  subQuaternion[1] = quaternion[2];
999  subQuaternion[2] = quaternion[3];
1000 
1001 
1002  // The quaternion we've just constructed is of the form:
1003  //
1004  // cos(ANGLE/2) + sin(ANGLE/2) * AXIS
1005  //
1006  // We take a few precautions to handle the case of an identity
1007  // rotation.
1008  if (isZero(subQuaternion)) {
1009  axis(0) = 0.0;
1010  axis(1) = 0.0;
1011  axis(2) = 1.0;
1012 
1013  angle.setRadians(0.0);
1014  }
1015  else if (qFuzzyCompare(quaternion(0) + 1.0, 1.0)) {
1016  axis = subQuaternion;
1017  angle.setRadians(Isis::PI);
1018  }
1019  else {
1020  axis = LinearAlgebra::normalize(subQuaternion);
1021  angle.setRadians(2.0 * atan2(magnitude(subQuaternion), quaternion(0)));
1022  }
1023 
1024  return qMakePair(axis, angle);
1025  }
1026 
1027 
1050  // Derived from NAIF's m2eul routine
1052  const QList<int> axes) {
1053 
1054  // check there are 3 axes in the set {1,2,3} with center axis not equal to first or last
1055  if (axes.size() != 3) {
1056  QString msg = "Unable to convert the given matrix to Euler angles. "
1057  "Exactly 3 axis codes are required. The given list has ["
1058  + toString((int) axes.size()) + "] axes.";
1059  throw IException(IException::Programmer, msg, _FILEINFO_);
1060  }
1061 
1062  QSet<int> validAxes;
1063  validAxes << 1 << 2 << 3;
1064  if (!validAxes.contains(axes[0])
1065  || !validAxes.contains(axes[1])
1066  || !validAxes.contains(axes[2])) {
1067  QString msg = "Unable to convert the given matrix to Euler angles using the given axis codes "
1068  "[" + toString(axes[0]) + ", " + toString(axes[1]) + ", " + toString(axes[2])
1069  + "]. Axis codes must be 1, 2, or 3.";
1070  throw IException(IException::Programmer, msg, _FILEINFO_);
1071  }
1072 
1073  if (axes[0] == axes[1] || axes[1] == axes[2]) {
1074  QString msg = "Unable to convert the given matrix to Euler angles using the given axis codes "
1075  "[" + toString(axes[0]) + ", " + toString(axes[1]) + ", " + toString(axes[2])
1076  + "]. The middle axis code must differ from its neighbors.";
1077  throw IException(IException::Programmer, msg, _FILEINFO_);
1078  }
1079 
1080  // check the matrix is 3x3 rotation
1081  if ((rotationMatrix.size1() != 3) || (rotationMatrix.size2() != 3)) {
1082  QString msg = "Unable to convert the given matrix to Euler angles. A 3x3 matrix is required. "
1083  "The given matrix is ["
1084  + toString((int) rotationMatrix.size1()) + "x"
1085  + toString((int) rotationMatrix.size2()) + "].";
1086  throw IException(IException::Programmer, msg, _FILEINFO_);
1087  }
1088 
1089  if ( !isRotationMatrix(rotationMatrix) ) {
1090  QString msg = "Unable to convert the given matrix to Euler angles. "
1091  "The given matrix is not a rotation matrix.";
1092  throw IException(IException::Programmer, msg, _FILEINFO_);
1093  }
1094 
1095  // AXIS3, AXIS2, AXIS1 and R have passed their tests at this
1096  // point. We take the liberty of working with TEMPROT, a
1097  // version of R that has unitized columns.
1098  // DO I = 1, 3
1099  // CALL VHAT ( R(1,I), TEMPROT(1,I) )
1100  // END DO
1101 
1102  LinearAlgebra::Matrix tempRotation(3, 3);
1103  for (int i = 0; i < 3; i++) {
1104  Vector columnVector = column(rotationMatrix, i);
1105  // replace the ith column with a unitized column vector
1106  setColumn(tempRotation, normalize(columnVector), i);
1107  }
1108 
1109  QList<int> nextAxis;
1110  nextAxis << 2 << 3 << 1;
1111  double sign;
1112  // create a matrix of zeros and we will fill in the non zero components below
1113  LinearAlgebra::Matrix change = zeroMatrix(3, 3);
1114 
1115  Angle angle1, angle2, angle3;
1116  if ( axes[0] == axes[2] ) {
1117  if ( axes[1] == nextAxis[axes[0] - 1] ) {
1118  sign = 1.0;
1119  }
1120  else {
1121  sign = -1.0;
1122  }
1123  int c = 6 - axes[0] - axes[1];
1124 
1125  change( axes[0] - 1, 2 ) = 1.0;
1126  change( axes[1] - 1, 0 ) = 1.0;
1127  change( c - 1, 1 ) = sign * 1.0;
1128  LinearAlgebra::Matrix tempMatrix = multiply( tempRotation, change );
1129  tempRotation = multiply( transpose(change), tempMatrix );
1130 
1131  bool degen = ( qFuzzyCompare(tempRotation(0, 2) + 1.0, 1.0)
1132  && qFuzzyCompare(tempRotation(1, 2) + 1.0, 1.0) )
1133  || ( qFuzzyCompare(tempRotation(2, 0) + 1.0, 1.0)
1134  && qFuzzyCompare(tempRotation(2, 1) + 1.0, 1.0) )
1135  || qFuzzyCompare( qAbs(tempRotation(2, 2)), 1.0 );
1136 
1137  if ( degen ) {
1138 
1139  angle3.setRadians( 0.0 );
1140  angle2.setRadians( acos( tempRotation(2, 2) ) );
1141  angle1.setRadians( atan2( tempRotation(0, 1), tempRotation(0, 0) ) );
1142 
1143  }
1144  else {
1145  // the normal case.
1146  angle3.setRadians( atan2( tempRotation(0, 2), tempRotation(1, 2) ) );
1147  angle2.setRadians( acos( tempRotation(2, 2) ) );
1148  angle1.setRadians( atan2( tempRotation(2, 0), -tempRotation(2, 1) ) );
1149  }
1150  }
1151  else {
1152  // The axis order is c-b-a. We're going to find a matrix CHANGE
1153  // such that
1154  //
1155  // T
1156  // CHANGE R CHANGE
1157  if ( axes[1] == nextAxis[axes[0] - 1] ) {
1158  sign = 1.0;
1159  }
1160  else {
1161  sign = -1.0;
1162  }
1163  change( axes[0] - 1, 0 ) = 1.0;
1164  change( axes[1] - 1, 1 ) = 1.0;
1165  change( axes[2] - 1, 2 ) = sign * 1.0;
1166  LinearAlgebra::Matrix tempMatrix = multiply( tempRotation, change );
1167  tempRotation = multiply( transpose(change), tempMatrix );
1168  bool degen = ( qFuzzyCompare(tempRotation(0, 0) + 1.0, 1.0)
1169  && qFuzzyCompare(tempRotation(0, 1) + 1.0, 1.0) )
1170  || ( qFuzzyCompare(tempRotation(1, 2) + 1.0, 1.0)
1171  && qFuzzyCompare(tempRotation(2, 2) + 1.0, 1.0) )
1172  || qFuzzyCompare( qAbs(tempRotation(0, 2)), 1.0 );
1173 
1174  if ( degen ) {
1175 
1176  angle3.setRadians( 0.0 );
1177  angle2.setRadians( asin( -tempRotation(0, 2) ) );
1178  angle1.setRadians( sign * atan2( -tempRotation(1, 0), tempRotation(1, 1) ) );
1179 
1180  }
1181  else {
1182  // the normal case.
1183  angle3.setRadians( atan2( tempRotation(1, 2), tempRotation(2, 2) ) );
1184  angle2.setRadians( asin( -tempRotation(0, 2) ) );
1185  angle1.setRadians( sign * atan2( tempRotation(0, 1), tempRotation(0, 0) ) );
1186  }
1187  }
1188 
1190  eulerAngles << qMakePair(angle3, axes[0])
1191  << qMakePair(angle2, axes[1])
1192  << qMakePair(angle1, axes[2]);
1193  return eulerAngles;
1194  }
1195 
1196 
1210  // Derived from NAIF's m2q routine
1212 
1213  if ((rotationMatrix.size1() != 3) || (rotationMatrix.size2() != 3)) {
1214  QString msg = "Unable to convert the given matrix to a quaternion. "
1215  "A 3x3 matrix is required. The given matrix is ["
1216  + toString((int) rotationMatrix.size1()) + "x"
1217  + toString((int) rotationMatrix.size2()) + "].";
1218  throw IException(IException::Programmer, msg, _FILEINFO_);
1219  }
1220 
1221  // if given matrix is not a rotation matrix, we can't proceed.
1222  if ( !isRotationMatrix(rotationMatrix) ) {
1223  QString msg = "Unable to convert the given matrix to an axis of rotation "
1224  "and a rotation angle. The given matrix is not a rotation matrix.";
1225  throw IException(IException::Programmer, msg, _FILEINFO_);
1226  }
1227 
1228  // Let q = c + s1*i + s2*j + s3*k
1229  // where c is the constant and s1, s2, s3 are the coefficients of the imaginary parts
1230  // and |q| = 1, .
1231 
1232  // Denote the following for n,m in {1,2,3}
1233  // cc = c * c
1234  // csn = c * sn
1235  // snm = sn * sm
1236 
1237  // The rotation matrix corresponding to our quaternion is:
1238  //
1239  // | cc+s11-s22-s33 2*s12-2*cs3 2*s13+2*cs2 |
1240  // | 2*s12+2*cs3 cc-s11+s22-s33 2*s23-2*cs1 |
1241  // | 2*s13-2*cs2 2*s23+2*cs1 cc-s11-s22+s33 |
1242  //
1243  //
1244  // since |q| = cc + s11 + s22 + s33 = 1, we can use substitution on the diagonal entries to get
1245  //
1246  // | 1-2*s22-2*s33 2*s12-2*cs3 2*s13+2*cs2 |
1247  // | 2*s12+2*cs3 1-2*s11-2*s33 2*s23-2*cs1 |
1248  // | 2*s13-2*cs2 2*s23+2*cs1 1-2*s11-2*s22 |
1249  //
1250  //
1251  //
1252  // r(1,1) = 1.0 - 2*s22 - 2*s33
1253  // r(2,1) = 2*s12 + 2*cs3
1254  // r(3,1) = 2*s13 - 2*cs2
1255  //
1256  // r(1,2) = 2*s12 - 2*cs3
1257  // r(2,2) = 1.0 - 2*s11 - 2*s33
1258  // r(3,2) = 2*s23 + 2*cs1
1259  //
1260  // r(1,3) = 2*s13 + 2*cs2
1261  // r(2,3) = 2*s23 - 2*cs1
1262  // r(3,3) = 1.0 - 2*s11 - 2*s22
1263 
1264  // Using this matrix, we get the trace by summing the diagonal entries
1265  // trace = (1-2*s22-2*s33) + (1-2*s11-2*s33) + (1-2*s11-2*s22)
1266  // = 3 - 4*(s11 + s22 + s33)
1267 
1268  // Therefore
1269  // 1.0 + trace = 4 - 4*(s11 + s22 + s33)
1270  // = 4*(1 - s11 - s22 - s33) by factoring 4
1271  // = 4*(|q| - s11 - s22 - s33) since |q| = 1
1272  // = 4*cc since |q| = cc + s11 + s22 + s33
1273  //
1274  // Solving for c, we get that
1275  // 4*cc = 1 + trace
1276  // 2*c = +/- sqrt(1 + trace)
1277  // c = +/- 0.5 * sqrt( 1.0 + trace )
1278 
1279  // We also have the following where {n,m,p} = {1,2,3}
1280  // 1.0 + trace - 2.0*r(n,n) = 4.0 - 4.0(snn + smm + spp) - 2(1.0 - 2.0(smm + spp ))
1281  // = 4.0 - 4.0(snn + smm + spp) - 2.0 + 4.0(smm + spp )
1282  // = 2.0 - 4.0*snn
1283  //
1284  // Solving for snn, we get
1285  // 2.0 - 4.0*snn = 1.0 + trace - 2.0*r(n,n)
1286  // -2.0 + 4.0*snn = -1.0 - trace + 2.0*r(n,n)
1287  // 4.0*snn = 1.0 - trace + 2.0*r(n,n) ******** we will use this value *************
1288  // ******** in our code to minimize *************
1289  // ******** computations *************
1290  // 2.0*sn = +/- sqrt(1.0 - trace + 2.0*r(n,n))
1291  // sn = +/- 0.5 * sqrt(1.0 - trace + 2.0*r(n,n)) for any n in {1,2,3}
1292 
1293 
1294  // In addition to these observations, note that all of the product
1295  // pairs can easily be computed by simplifying the expressions
1296  // (r(n,m) - r(m,n)) / 4.0 and (r(n,m) + r(m,n)) / 4.0
1297  //
1298  // For example,
1299  // (r(3,2) - r(2,3)) / 4.0 = ( (2*s23 + 2*cs1) - (2*s23 - 2*cs1) ) / 4.0
1300  // = ( 4*cs1 ) / 4.0
1301  // = cs1
1302  //
1303  // So we have the following
1304  // cs1 = (r(3,2) - r(2,3))/4.0
1305  // cs2 = (r(1,3) - r(3,1))/4.0
1306  // cs3 = (r(2,1) - r(1,2))/4.0
1307  // s12 = (r(2,1) + r(1,2))/4.0
1308  // s13 = (r(3,1) + r(1,3))/4.0
1309  // s23 = (r(2,3) + r(3,2))/4.0
1310 
1311  //but taking sums or differences of numbers that are nearly equal
1312  //or nearly opposite results in a loss of precision. as a result
1313  //we should take some care in which terms to select when computing
1314  //c, s1, s2, s3. however, by simply starting with one of the
1315  //large quantities cc, s11, s22, or s33 we can make sure that we
1316  //use the best of the 6 quantities above when computing the
1317  //remaining components of the quaternion.
1318 
1319  double trace = rotationMatrix(0, 0) + rotationMatrix(1, 1) + rotationMatrix(2, 2);
1320  double mtrace = 1.0 - trace;
1321 
1322  // cc4 = 4 * c * c where c is the constant term (first) of the quaternion
1323  double cc4 = 1.0 + trace;
1324  // snn4 = 4 * sn * sn where sn is the coefficient for the n+1 term of the quaternion vector
1325  double s114 = mtrace + 2.0*rotationMatrix(0, 0);
1326  double s224 = mtrace + 2.0*rotationMatrix(1, 1);
1327  double s334 = mtrace + 2.0*rotationMatrix(2, 2);
1328 
1329  // Note that cc4 + s114 + s224 + s334 = 4|q| = 4
1330  // Thus, at least one of the 4 terms is greater than 1.
1331  double normalizingFactor;
1332  LinearAlgebra::Vector quaternion(4);
1333  if ( cc4 >= 1.0 ) { // true if the trace is non-negative
1334 
1335  quaternion[0] = sqrt( cc4 * 0.25 ); // note that q0 = c = sqrt(4*c*c*0.25)
1336  normalizingFactor = 1.0 / ( quaternion[0] * 4.0 );
1337 
1338  // multiply the difference of the entries symmetric about the diagonal by the factor 1/4c
1339  // to get s1, s2, and s3
1340  // (see calculations for cs1, cs2, cs3 in comments above)
1341  quaternion[1] = ( rotationMatrix(2, 1) - rotationMatrix(1, 2) ) * normalizingFactor;
1342  quaternion[2] = ( rotationMatrix(0, 2) - rotationMatrix(2, 0) ) * normalizingFactor;
1343  quaternion[3] = ( rotationMatrix(1, 0) - rotationMatrix(0, 1) ) * normalizingFactor;
1344 
1345  }
1346  else if ( s114 >= 1.0 ) {
1347 
1348  quaternion[1] = sqrt( s114 * 0.25 ); // note that q1 = s1 = sqrt(4*s1*s1*0.25)
1349  normalizingFactor = 1.0 /( quaternion[1] * 4.0 );
1350 
1351  quaternion[0] = ( rotationMatrix(2, 1) - rotationMatrix(1, 2) ) * normalizingFactor;
1352  quaternion[2] = ( rotationMatrix(0, 1) + rotationMatrix(1, 0) ) * normalizingFactor;
1353  quaternion[3] = ( rotationMatrix(0, 2) + rotationMatrix(2, 0) ) * normalizingFactor;
1354 
1355  }
1356  else if ( s224 >= 1.0 ) {
1357 
1358  quaternion[2] = sqrt( s224 * 0.25 );
1359  normalizingFactor = 1.0 /( quaternion[2] * 4.0 );
1360 
1361  quaternion[0] = ( rotationMatrix(0, 2) - rotationMatrix(2, 0) ) * normalizingFactor;
1362  quaternion[1] = ( rotationMatrix(0, 1) + rotationMatrix(1, 0) ) * normalizingFactor;
1363  quaternion[3] = ( rotationMatrix(1, 2) + rotationMatrix(2, 1) ) * normalizingFactor;
1364  }
1365  else { // s334 >= 1.0
1366 
1367  quaternion[3] = sqrt( s334 * 0.25 );
1368  normalizingFactor = 1.0 /( quaternion[3] * 4.0 );
1369 
1370  quaternion[0] = ( rotationMatrix(1, 0) - rotationMatrix(0, 1) ) * normalizingFactor;
1371  quaternion[1] = ( rotationMatrix(0, 2) + rotationMatrix(2, 0) ) * normalizingFactor;
1372  quaternion[2] = ( rotationMatrix(1, 2) + rotationMatrix(2, 1) ) * normalizingFactor;
1373 
1374  }
1375 
1376  // if the magnitude of this quaternion is not one, we polish it up a bit.
1377  if ( !isUnit(quaternion) ) {
1378  quaternion = normalize(quaternion);
1379  }
1380 
1381  // M2Q always returns a quaternion with scalar part greater than or equal to zero.
1382  if ( quaternion[0] < 0.0 ) {
1383  quaternion *= -1.0;
1384  }
1385 
1386  return quaternion;
1387  }
1388 
1389 
1404  // Derived from NAIF's axisar routine
1406  if (axis.size() != 3) {
1407  QString msg = "Unable to convert the given vector and angle to a rotation matrix. "
1408  "The given vector with size [" + toString((int) axis.size())
1409  + "] is not a 3D axis vector.";
1410  throw IException(IException::Programmer, msg, _FILEINFO_);
1411  }
1412 
1413  // intialize the matrix with the 3x3 identity.
1414  LinearAlgebra::Matrix rotationMatrix = identity(3);
1415 
1416  // The matrix we want rotates every vector by angle about axis.
1417  // In particular, it does so to our basis vectors. The columns
1418  // of the output matrix are the images of the basis vectors
1419  // under this rotation.
1420  for (unsigned int i = 0; i < axis.size(); i++) {
1421  // rotate the ith column of the matrix (the ith standard basis vector)
1422  // about the given axis using the given angle
1423  Vector stdBasisVector = column(rotationMatrix, i);
1424 
1425  // replace the ith column with the rotated vector
1426  setColumn(rotationMatrix, rotate(stdBasisVector, axis, angle), i);
1427  }
1428 
1429  return rotationMatrix;
1430  }
1431 
1432 
1443  return LinearAlgebra::toMatrix(axisAngle.first, axisAngle.second);
1444  }
1445 
1446 
1461  // Derived from NAIF's eul2m routine
1463  const EulerAngle &angle2,
1464  const EulerAngle &angle1) {
1465  QSet<int> validAxes;
1466  validAxes << 1 << 2 << 3;
1467  if (!validAxes.contains(angle3.second)
1468  || !validAxes.contains(angle2.second)
1469  || !validAxes.contains(angle1.second)) {
1470  QString msg = "Unable to convert the given Euler angles to a matrix using the given axis "
1471  "codes [" + toString(angle3.second) + ", " + toString(angle2.second) + ", "
1472  + toString(angle1.second) + "]. Axis codes must be 1, 2, or 3.";
1473  throw IException(IException::Programmer, msg, _FILEINFO_);
1474  }
1475 
1476  LinearAlgebra::Matrix m(3, 3);
1477  // implement eul2m
1478  // Calculate the 3x3 rotation matrix generated by a rotation
1479  // of a specified angle about a specified axis. This rotation
1480  // is thought of as rotating the coordinate system.
1481  //
1482  //ROTATE(angle1, axis1);
1483  double sinAngle = sin(angle1.first.radians());
1484  double cosAngle = cos(angle1.first.radians());
1485  // get the index offset based on the axis number corresponding to this angle
1486  double indexOffset = ((angle1.second % 3) + 3) % 3;
1487  QList<int> indexSet;
1488  indexSet << 2 << 0 << 1 << 2 << 0;
1489  int index1 = indexSet[indexOffset + 0];
1490  int index2 = indexSet[indexOffset + 1];
1491  int index3 = indexSet[indexOffset + 2];
1492  m(index1, index1) = 1.0; m(index1, index2) = 0.0; m(index1, index3) = 0.0;
1493  m(index2, index1) = 0.0; m(index2, index2) = cosAngle; m(index2, index3) = sinAngle;
1494  m(index3, index1) = 0.0; m(index3, index2) = -sinAngle; m(index3, index3) = cosAngle;
1495 
1496  //
1497  // C ROTMAT applies a rotation of ANGLE radians about axis IAXIS to a
1498  // C matrix. This rotation is thought of as rotating the coordinate
1499  // C system.
1500  // C
1501  //CALL ROTMAT ( R, ANGLE2, AXIS2, R1 )
1502  sinAngle = sin(angle2.first.radians());
1503  cosAngle = cos(angle2.first.radians());
1504  indexOffset = ((angle2.second % 3) + 3) % 3;
1505  index1 = indexSet[indexOffset + 0];
1506  index2 = indexSet[indexOffset + 1];
1507  index3 = indexSet[indexOffset + 2];
1508 
1509  LinearAlgebra::Matrix tempMatrix(3, 3);
1510  for (int i = 0; i < 3; i++) {
1511  tempMatrix(index1, i) = m(index1, i);
1512  tempMatrix(index2, i) = cosAngle*m(index2, i) + sinAngle*m(index3, i);
1513  tempMatrix(index3, i) = -sinAngle*m(index2, i) + cosAngle*m(index3, i);
1514  }
1515 
1516  //CALL ROTMAT ( tempMatrix, ANGLE3, AXIS3, m )
1517  sinAngle = sin(angle3.first.radians());
1518  cosAngle = cos(angle3.first.radians());
1519  indexOffset = ((angle3.second % 3) + 3) % 3;
1520  index1 = indexSet[indexOffset + 0];
1521  index2 = indexSet[indexOffset + 1];
1522  index3 = indexSet[indexOffset + 2];
1523  for (int i = 0; i < 3; i++) {
1524  m(index1, i) = tempMatrix(index1, i);
1525  m(index2, i) = cosAngle*tempMatrix(index2, i) + sinAngle*tempMatrix(index3, i);
1526  m(index3, i) = -sinAngle*tempMatrix(index2, i) + cosAngle*tempMatrix(index3, i);
1527  }
1528 
1529  return m;
1530  }
1531 
1532 
1546 
1547  if (eulerAngles.size() != 3) {
1548  QString msg = "Unable to convert the given Euler angles to a matrix. "
1549  "Exactly 3 Euler angles are required. The given list has ["
1550  + toString((int) eulerAngles.size()) + "] angles.";
1551  throw IException(IException::Programmer, msg, _FILEINFO_);
1552  }
1553  return LinearAlgebra::toMatrix(eulerAngles[0], eulerAngles[1], eulerAngles[2]);
1554  }
1555 
1556 
1557 
1571  // Derived from NAIF's q2m routine
1573  if (quaternion.size() != 4) {
1574  QString msg = "Unable to convert the given vector to a rotation matrix. "
1575  "The given vector with [" + toString((int) quaternion.size())
1576  + "] components is not a quaternion.";
1577  throw IException(IException::Programmer, msg, _FILEINFO_);
1578  }
1579 
1580  Vector q = quaternion;
1581  if ( !isUnit(quaternion) && !isZero(quaternion) ) {
1582  q = normalize(quaternion);
1583  }
1584 
1585  LinearAlgebra::Matrix matrix(3, 3);
1586  // For efficiency, we avoid duplicating calculations where possible.
1587  double q0q1 = q[0] * q[1];
1588  double q0q2 = q[0] * q[2];
1589  double q0q3 = q[0] * q[3];
1590 
1591  double q1q1 = q[1] * q[1];
1592  double q1q2 = q[1] * q[2];
1593  double q1q3 = q[1] * q[3];
1594 
1595  double q2q2 = q[2] * q[2];
1596  double q2q3 = q[2] * q[3];
1597 
1598  double q3q3 = q[3] * q[3];
1599 
1600  matrix(0, 0) = 1.0 - 2.0 * ( q2q2 + q3q3 );
1601  matrix(0, 1) = 2.0 * ( q1q2 - q0q3 );
1602  matrix(0, 2) = 2.0 * ( q1q3 + q0q2 );
1603 
1604  matrix(1, 0) = 2.0 * ( q1q2 + q0q3 );
1605  matrix(1, 1) = 1.0 - 2.0 * ( q1q1 + q3q3 );
1606  matrix(1, 2) = 2.0 * ( q2q3 - q0q1 );
1607 
1608  matrix(2, 0) = 2.0 * ( q1q3 - q0q2 );
1609  matrix(2, 1) = 2.0 * ( q2q3 + q0q1 );
1610  matrix(2, 2) = 1.0 - 2.0 * ( q1q1 + q2q2 );
1611 
1612  return matrix;
1613  }
1614 
1615 
1626  void LinearAlgebra::setRow(Matrix &matrix, const Vector &vector, int rowIndex) {
1627  if ( (rowIndex+1 > (int) matrix.size1()) ) {
1628  QString msg = "Unable to set the matrix row to the given vector. Row index "
1629  + toString(rowIndex) + " is out of bounds. The given matrix only has "
1630  + toString((int) matrix.size1()) + " rows." ;
1631  throw IException(IException::Programmer, msg, _FILEINFO_);
1632  }
1633  boost::numeric::ublas::row(matrix, rowIndex) = vector;
1634  }
1635 
1636 
1647  void LinearAlgebra::setColumn(Matrix &matrix, const Vector &vector, int columnIndex) {
1648  if ( (columnIndex+1 > (int) matrix.size2()) ) {
1649  QString msg = "Unable to set the matrix column to the given vector. Column index "
1650  + toString(columnIndex) + " is out of bounds. The given matrix only has "
1651  + toString((int) matrix.size1()) + " columns." ;
1652  throw IException(IException::Programmer, msg, _FILEINFO_);
1653  }
1654  boost::numeric::ublas::column(matrix, columnIndex) = vector;
1655  }
1656 
1657 
1670  LinearAlgebra::Vector LinearAlgebra::row(const Matrix &matrix, int rowIndex) {
1671  if ( (rowIndex+1 > (int) matrix.size1()) ) {
1672  QString msg = "Unable to get the matrix row to the given vector. Row index "
1673  + toString(rowIndex) + " is out of bounds. The given matrix only has "
1674  + toString((int) matrix.size1()) + " rows." ;
1675  throw IException(IException::Programmer, msg, _FILEINFO_);
1676  }
1677  return boost::numeric::ublas::row(matrix, rowIndex);
1678  }
1679 
1680 
1693  LinearAlgebra::Vector LinearAlgebra::column(const Matrix &matrix, int columnIndex) {
1694  if ( (columnIndex+1 > (int) matrix.size2()) ) {
1695  QString msg = "Unable to get the matrix column to the given vector. Column index "
1696  + toString(columnIndex) + " is out of bounds. The given matrix only has "
1697  + toString((int) matrix.size1()) + " columns." ;
1698  throw IException(IException::Programmer, msg, _FILEINFO_);
1699  }
1700  return boost::numeric::ublas::column(matrix, columnIndex);
1701  }
1702 
1703 
1714  LinearAlgebra::Vector LinearAlgebra::vector(double v0, double v1, double v2) {
1715  Vector v(3);
1716  v[0] = v0;
1717  v[1] = v1;
1718  v[2] = v2;
1719  return v;
1720  }
1721 
1722 
1734  LinearAlgebra::Vector LinearAlgebra::vector(double v0, double v1, double v2, double v3) {
1735  Vector v(4);
1736  v[0] = v0;
1737  v[1] = v1;
1738  v[2] = v2;
1739  v[3] = v3;
1740  return v;
1741  }
1742 
1743 
1752  void LinearAlgebra::setVec3(Vector *v, double v0, double v1, double v2) {
1753  (*v)[0] = v0;
1754  (*v)[1] = v1;
1755  (*v)[2] = v2;
1756  }
1757 
1758 
1768  void LinearAlgebra::setVec4(Vector *v, double v0, double v1, double v2, double v3) {
1769  (*v)[0] = v0;
1770  (*v)[1] = v1;
1771  (*v)[2] = v2;
1772  (*v)[3] = v3;
1773  }
1774 
1775 
1789  LinearAlgebra::Vector LinearAlgebra::subVector(const Vector &v, int startIndex, int size) {
1790  LinearAlgebra::Vector sub(size);
1791  for (int i = 0; i < size; i++) {
1792  sub[i] = v[i + startIndex];
1793  }
1794  return sub;
1795  }
1796 
1797 
1810  QDebug operator<<(QDebug dbg, const LinearAlgebra::Vector &vector) {
1811  QDebugStateSaver saver(dbg);
1812  dbg.noquote() << toString(vector);
1813  return dbg;
1814  }
1815 
1816 
1828  QDebug operator<<(QDebug dbg, const LinearAlgebra::Matrix &matrix) {
1829  QDebugStateSaver saver(dbg);
1830  for (unsigned int i = 0; i < matrix.size1(); i++) {
1831  dbg.noquote() << " ";
1832  for (unsigned int j = 0; j < matrix.size2(); j++) {
1833  dbg.noquote() << toString(matrix(i, j), 15) << " ";
1834  }
1835  dbg.noquote() << endl;
1836  }
1837  return dbg;
1838  }
1839 
1840 
1852  QString toString(const LinearAlgebra::Vector &vector, int precision) {
1853  QString result = "( ";
1854  for (unsigned int i = 0; i < vector.size(); i++) {
1855  result += toString(vector(i), precision);
1856  if (i != vector.size() - 1) result += ", ";
1857  }
1858  result += " )";
1859  return result;
1860  }
1861 }
Isis::operator<<
QDebug operator<<(QDebug debug, const Hillshade &hillshade)
Print this class out to a QDebug object.
Definition: Hillshade.cpp:314
Isis::LinearAlgebra::multiply
static Matrix multiply(const Matrix &matrix1, const Matrix &matrix2)
Returns the product of two matrices.
Definition: LinearAlgebra.cpp:549
Isis::PI
const double PI
The mathematical constant PI.
Definition: Constants.h:40
Isis::LinearAlgebra::add
static Vector add(const Vector &vector1, const Vector &vector2)
Adds the two given vectors.
Definition: LinearAlgebra.cpp:634
Isis::LinearAlgebra::project
static Vector project(const Vector &vector1, const Vector &vector2)
Compute the vector projection of vector1 onto vector2.
Definition: LinearAlgebra.cpp:833
QList
This is free and unencumbered software released into the public domain.
Definition: BoxcarCachingAlgorithm.h:13
Isis::LinearAlgebra::isIdentity
static bool isIdentity(const Matrix &matrix)
Determines whether the given matrix is the identity.
Definition: LinearAlgebra.cpp:61
Isis::LinearAlgebra::isOrthogonal
static bool isOrthogonal(const Matrix &matrix)
Determines whether the given matrix is orthogonal by verifying that the matrix and its tranpose are i...
Definition: LinearAlgebra.cpp:89
Isis::LinearAlgebra::subtract
static Vector subtract(const Vector &vector1, const Vector &vector2)
Subtracts the right vector from the left vector.
Definition: LinearAlgebra.cpp:660
Isis::LinearAlgebra::~LinearAlgebra
~LinearAlgebra()
Destructor for a LinearAlgebra object.
Definition: LinearAlgebra.cpp:46
QSet
This is free and unencumbered software released into the public domain.
Definition: Process.h:16
Isis::IException::Unknown
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition: IException.h:118
Isis::LinearAlgebra::determinant
static double determinant(const Matrix &matrix)
Returns the determinant of the given 3x3 matrix.
Definition: LinearAlgebra.cpp:440
Isis::LinearAlgebra::perpendicular
static Vector perpendicular(const Vector &vector1, const Vector &vector2)
Finds the unique vector P such that A = V + P, V is parallel to B and P is perpendicular to B,...
Definition: LinearAlgebra.cpp:932
Isis::LinearAlgebra::isZero
static bool isZero(const Matrix &matrix)
Determines whether the given matrix is filled with zereos.
Definition: LinearAlgebra.cpp:211
Isis::LinearAlgebra::absoluteMaximum
static double absoluteMaximum(const Vector &vector)
Returns the maximum norm (L-infinity norm) for the given vector.
Definition: LinearAlgebra.cpp:531
Isis::LinearAlgebra::zeroMatrix
static Matrix zeroMatrix(int rows, int columns)
Returns a matrix with given dimensions that is filled with zeroes.
Definition: LinearAlgebra.cpp:408
Isis::LinearAlgebra::innerProduct
static double innerProduct(const Vector &vector1, const Vector &vector2)
Computes the inner product of the given vectors.
Definition: LinearAlgebra.cpp:801
Isis::LinearAlgebra::rotate
static Vector rotate(const Vector &vector, const Vector &axis, Angle angle)
Rotates a vector about an axis vector given a specified angle.
Definition: LinearAlgebra.cpp:872
Isis::LinearAlgebra::magnitude
static double magnitude(const Vector &vector)
Computes the magnitude (i.e., the length) of the given vector using the Euclidean norm (L2 norm).
Definition: LinearAlgebra.cpp:504
Isis::LinearAlgebra::transpose
static Matrix transpose(const Matrix &matrix)
Returns the transpose of the given matrix.
Definition: LinearAlgebra.cpp:369
Isis::LinearAlgebra::vector
static Vector vector(double v0, double v1, double v2)
Constructs a 3 dimensional vector with the given component values.
Definition: LinearAlgebra.cpp:1714
Isis::LinearAlgebra::isEmpty
static bool isEmpty(const Vector &vector)
Determines whether the given vector is empty (i.e.
Definition: LinearAlgebra.cpp:250
Isis::LinearAlgebra::setRow
static void setRow(Matrix &matrix, const Vector &vector, int rowIndex)
Sets the row of the given matrix to the values of the given vector.
Definition: LinearAlgebra.cpp:1626
Isis::LinearAlgebra::Matrix
boost::numeric::ublas::matrix< double > Matrix
Definition for an Isis::LinearAlgebra::Matrix of doubles.
Definition: LinearAlgebra.h:100
Isis::LinearAlgebra::row
static Vector row(const Matrix &matrix, int rowIndex)
Returns a vector whose components match those of the given matrix row.
Definition: LinearAlgebra.cpp:1670
Isis::toString
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:211
Isis::LinearAlgebra::LinearAlgebra
LinearAlgebra()
Default constructor for a LinearAlgebra object.
Definition: LinearAlgebra.cpp:39
Isis::LinearAlgebra::inverse
static Matrix inverse(const Matrix &matrix)
Returns the inverse of a 2x2 or 3x3 matrix.
Definition: LinearAlgebra.cpp:282
Isis::LinearAlgebra::outerProduct
static Matrix outerProduct(const Vector &vector1, const Vector &vector2)
Computes the outer product of the given vectors.
Definition: LinearAlgebra.cpp:757
Isis::LinearAlgebra::isRotationMatrix
static bool isRotationMatrix(const Matrix &matrix)
Determines whether the given matrix is a rotation matrix.
Definition: LinearAlgebra.cpp:113
Isis::LinearAlgebra::dotProduct
static double dotProduct(const Vector &vector1, const Vector &vector2)
Computes the dot product of the given vectors.
Definition: LinearAlgebra.cpp:781
Isis::LinearAlgebra::Vector
boost::numeric::ublas::vector< double > Vector
Definition for an Isis::LinearAlgebra::Vector of doubles.
Definition: LinearAlgebra.h:120
Isis::LinearAlgebra::column
static Vector column(const Matrix &matrix, int columnIndex)
Returns a vector whose components match those of the given matrix column.
Definition: LinearAlgebra.cpp:1693
Isis::LinearAlgebra::toAxisAngle
static AxisAngle toAxisAngle(const Matrix &rotationMatrix)
Converts a rotation's representation from a matrix to a axis of rotation and its corresponding rotati...
Definition: LinearAlgebra.cpp:973
Isis::LinearAlgebra::pseudoinverse
static Matrix pseudoinverse(const Matrix &matrix)
Returns the pseudoinverse of a matrix.
Definition: LinearAlgebra.cpp:339
Isis::LinearAlgebra::zeroVector
static Vector zeroVector(int size)
Returns a vector of given length that is filled with zeroes.
Definition: LinearAlgebra.cpp:421
Isis::LinearAlgebra::normalize
static Vector normalize(const Vector &vector)
Returns a unit vector that is codirectional with the given vector by dividing each component of the v...
Definition: LinearAlgebra.cpp:477
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::LinearAlgebra::toMatrix
static Matrix toMatrix(const AxisAngle &axisAngle)
Converts a rotation's representation from an axis of rotation and its corresponding rotation angle to...
Definition: LinearAlgebra.cpp:1442
Isis::Angle
Defines an angle and provides unit conversions.
Definition: Angle.h:45
Isis::Angle::setRadians
void setRadians(double radians)
Set the angle in units of Radians.
Definition: Angle.h:239
Isis::IException::Programmer
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:146
Isis::LinearAlgebra::toEulerAngles
static QList< EulerAngle > toEulerAngles(const Matrix &rotationMatrix, const QList< int > axes)
Converts a rotation's representation from a matrix to a set of Euler angles with corresponding axes.
Definition: LinearAlgebra.cpp:1051
Isis::LinearAlgebra::setVec4
static void setVec4(Vector *v, double v0, double v1, double v2, double v3)
Fills the first four elements of the given vector with the given values.
Definition: LinearAlgebra.cpp:1768
QPair
This is free and unencumbered software released into the public domain.
Definition: CubeIoHandler.h:23
Isis::LinearAlgebra::setVec3
static void setVec3(Vector *v, double v0, double v1, double v2)
Fills the first three elements of the given vector with the given values.
Definition: LinearAlgebra.cpp:1752
Isis::LinearAlgebra::identity
static Matrix identity(int size)
Returns the identity matrix of size NxN.
Definition: LinearAlgebra.cpp:384
Isis::LinearAlgebra::crossProduct
static Vector crossProduct(const Vector &vector1, const Vector &vector2)
Returns the cross product of two vectors.
Definition: LinearAlgebra.cpp:688
Isis::LinearAlgebra::normalizedCrossProduct
static Vector normalizedCrossProduct(const Vector &vector1, const Vector &vector2)
Divides each vector by its corresponding absolute maximum, computes the cross product of the new vect...
Definition: LinearAlgebra.cpp:721
Isis::LinearAlgebra::isUnit
static bool isUnit(const Vector &vector)
Determines whether the given vector is a unit vector.
Definition: LinearAlgebra.cpp:262
Isis::LinearAlgebra::subVector
static Vector subVector(const Vector &v, int start, int size)
Constructs a vector of given size using the given vector and starting index.
Definition: LinearAlgebra.cpp:1789
Isis::LinearAlgebra::setColumn
static void setColumn(Matrix &matrix, const Vector &vector, int columnIndex)
Sets the column of the given matrix to the values of the given vector.
Definition: LinearAlgebra.cpp:1647
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::LinearAlgebra::toQuaternion
static Vector toQuaternion(const Matrix &rotationMatrix)
Converts a rotation's representation from a matrix to a unit quaternion.
Definition: LinearAlgebra.cpp:1211
Isis::Angle::radians
double radians() const
Convert an angle to a double.
Definition: Angle.h:226

U.S. Department of the Interior | U.S. Geological Survey
ISIS | Privacy & Disclaimers | Astrogeology Research Program
To contact us, please post comments and questions on the USGS Astrogeology Discussion Board
To report a bug, or suggest a feature go to: ISIS Github
File Modified: 07/13/2023 15:16:48