xmsgrid  1.0
matrix.cpp
Go to the documentation of this file.
1 //------------------------------------------------------------------------------
13 //------------------------------------------------------------------------------
14 
15 //----- Included files ---------------------------------------------------------
16 
17 // 1. Precompiled header
18 
19 // 2. My own header
21 
22 // 3. Standard library headers
23 #include <cmath>
24 
25 // 4. External library headers
26 #include <xmscore/points/pt.h> // Pt3d
27 
28 // 5. Shared code headers
29 #include <xmscore/misc/XmLog.h> // XM_LOG
30 #include <xmscore/misc/xmstype.h> // XM_PI, XM_SUCCESS, XM_FAILURE
31 
32 // 6. Non-shared code headers
33 
34 //----- Namespace declaration --------------------------------------------------
35 
36 namespace xms
37 {
38 //-------------------------------------------------------------------------------
46 //-------------------------------------------------------------------------------
47 int mxLUDecomp(double** mat, int n, int* indx, double* d)
48 {
49  int i, j, k, imax = 0;
50  double big, tmp, sum;
51  // allocate implicit scales for each row
52  std::vector<double> vv(n, 0);
53  *d = 1.0; // no row interchanges yet
54  // loop over rows to get implicit scale info
55  for (i = 0; i < n; ++i)
56  {
57  big = 0.0;
58  for (j = 0; j < n; ++j)
59  if ((tmp = fabs(mat[i][j])) > big)
60  big = tmp;
61  if (big == 0.0)
62  {
63  return (XM_FAILURE);
64  }
65  vv[i] = 1.0 / big;
66  }
67  // loop over columns-Crout's method
68  for (j = 0; j < n; ++j)
69  {
70  for (i = 0; i < j; ++i)
71  {
72  sum = mat[i][j];
73  for (k = 0; k < i; ++k)
74  sum -= mat[i][k] * mat[k][j];
75  mat[i][j] = sum;
76  }
77  big = 0.0; // initialize pivot search
78  for (i = j; i < n; ++i)
79  {
80  sum = mat[i][j];
81  for (k = 0; k < j; ++k)
82  sum -= mat[i][k] * mat[k][j];
83  mat[i][j] = sum;
84  if ((tmp = vv[i] * fabs(sum)) > big)
85  {
86  big = tmp;
87  imax = i;
88  }
89  }
90  if (j != imax)
91  { // do we need to change rows
92  for (k = 0; k < n; ++k)
93  {
94  tmp = mat[imax][k];
95  mat[imax][k] = mat[j][k];
96  mat[j][k] = tmp;
97  }
98  *d = -(*d);
99  vv[imax] = vv[j];
100  }
101  indx[j] = imax;
102  if (mat[j][j] == 0.0)
103  mat[0][0] = 1.0e-20;
104  if (j != n)
105  { // divide by the pivot element
106  tmp = 1.0 / mat[j][j];
107  for (i = j + 1; i < n; ++i)
108  mat[i][j] *= tmp;
109  }
110  } // go back for next column
111  return XM_SUCCESS;
112 } // mxLUDecomp
113 //-------------------------------------------------------------------------------
121 //-------------------------------------------------------------------------------
122 int mxLUBcksub(double** mat, int n, const int* indx, double* b)
123 {
124  int i, j, ii, ip;
125  double sum;
126  // do the forward substitution
127  ii = -1;
128  for (i = 0; i < n; ++i)
129  {
130  ip = indx[i];
131  sum = b[ip];
132  b[ip] = b[i];
133  if (ii >= 0)
134  for (j = ii; j <= i - 1; ++j)
135  sum -= mat[i][j] * b[j];
136  else if (sum)
137  ii = i;
138  b[i] = sum;
139  }
140  // do the back substitution
141  for (i = n - 1; i >= 0; --i)
142  {
143  sum = b[i];
144  for (j = i + 1; j < n; ++j)
145  sum -= mat[i][j] * b[j];
146  b[i] = sum / mat[i][i]; // store a component of solution
147  }
148  return XM_SUCCESS;
149 } // mxLUBcksub
150 //-------------------------------------------------------------------------------
156 //-------------------------------------------------------------------------------
157 bool mxiLudcmp3(double mat[3][3], int indx[3], double* d)
158 {
159  int i, j, k, imax;
160  double vv[3], big, tmp, sum;
161 
162  imax = 0; // there is a slight chance that leaving this uninitialized can
163  // lead to a UMR below.
164  *d = 1.0; // no row interchanges yet
165  // loop over rows to get implicit scale info
166  for (i = 0; i < 3; ++i)
167  {
168  big = 0.0;
169  for (j = 0; j < 3; ++j)
170  if ((tmp = fabs(mat[i][j])) > big)
171  big = tmp;
172  if (big == 0.0)
173  {
174  XM_LOG(xmlog::debug, "Singular Matrix");
175  return false;
176  }
177  vv[i] = 1.0 / big;
178  }
179  // loop over columns-Crout's method
180  for (j = 0; j < 3; ++j)
181  {
182  for (i = 0; i < j; ++i)
183  {
184  sum = mat[i][j];
185  for (k = 0; k < i; ++k)
186  sum -= mat[i][k] * mat[k][j];
187  mat[i][j] = sum;
188  }
189  big = 0.0; // initialize pivot search
190  for (i = j; i < 3; ++i)
191  {
192  sum = mat[i][j];
193  for (k = 0; k < j; ++k)
194  sum -= mat[i][k] * mat[k][j];
195  mat[i][j] = sum;
196  if ((tmp = vv[i] * fabs(sum)) > big)
197  {
198  big = tmp;
199  imax = i;
200  }
201  }
202  if (j != imax)
203  { // do we need to change rows
204  for (k = 0; k < 3; ++k)
205  {
206  tmp = mat[imax][k];
207  mat[imax][k] = mat[j][k];
208  mat[j][k] = tmp;
209  }
210  *d = -(*d);
211  vv[imax] = vv[j];
212  }
213  indx[j] = imax;
214  if (mat[j][j] == 0.0)
215  mat[j][j] = 1.0e-20;
216  if (j != 3)
217  { // divide by the pivot element
218  tmp = 1.0 / mat[j][j];
219  for (i = j + 1; i < 3; ++i)
220  mat[i][j] *= tmp;
221  }
222  } // go back for next column
223  return true;
224 } // mxiLudcmp3
225 //-------------------------------------------------------------------------------
230 //-------------------------------------------------------------------------------
231 void mxiLubksb3(const double mat[3][3], const int indx[3], double b[3])
232 {
233  int i, j, ii, ip;
234  double sum;
235  // do the forward substitution
236  ii = -1;
237  for (i = 0; i < 3; ++i)
238  {
239  ip = indx[i];
240  sum = b[ip];
241  b[ip] = b[i];
242  if (ii >= 0)
243  for (j = ii; j <= i - 1; ++j)
244  sum -= mat[i][j] * b[j];
245  else if (sum)
246  ii = i;
247  b[i] = sum;
248  }
249  // do the back substitution
250  for (i = 2; i >= 0; --i)
251  {
252  sum = b[i];
253  for (j = i + 1; j < 3; ++j)
254  sum -= mat[i][j] * b[j];
255  b[i] = sum / mat[i][i]; // store a component of solution
256  }
257 } // mxiLubksb3
258 //-------------------------------------------------------------------------------
267 //-------------------------------------------------------------------------------
268 bool mxSolveNxN(double** A, double* x, double* b, int n)
269 {
270  int *indx, i;
271  double d;
272 
273  switch (n)
274  {
275  case 1:
276  if (fabs(A[0][0]) < 0.000000001)
277  return false;
278  x[0] = b[0] / A[0][0];
279  return true;
280  case 2:
281  if (fabs(A[0][1]) >= fabs(A[0][0]))
282  {
283  if (fabs(A[0][1]) < 0.000000001)
284  return false;
285  d = A[1][1] / A[0][1];
286  x[0] = (b[1] - d * b[0]) / (A[1][0] - d * A[0][0]);
287  x[1] = (b[0] - A[0][0] * x[0]) / A[0][1];
288  }
289  else
290  {
291  d = A[1][0] / A[0][0];
292  x[1] = (b[1] - d * b[0]) / (A[1][1] - d * A[0][1]);
293  x[0] = (b[0] - A[0][1] * x[1]) / A[0][0];
294  }
295  return true;
296  default:
297  indx = (int*)malloc(n * sizeof(int));
298  if (mxLUDecomp(A, n, indx, &d) == XM_FAILURE)
299  {
300  free(indx);
301  return false;
302  }
303  for (i = 0; i < n; ++i)
304  x[i] = b[i];
305  mxLUBcksub(A, n, indx, x);
306  free(indx);
307  return true;
308  }
309 } // mxSolveNxN
310 //-------------------------------------------------------------------------------
324 //-------------------------------------------------------------------------------
325 bool mxSolveBandedEquations(double** a, double* x, double* b, int numeqs, int halfbandwidth)
326 
327 {
328  int i, ib, m1, j, k, k1, j1, j2, mM, np1;
329  double sum;
330 
331  for (i = 0; i < numeqs; i++)
332  x[i] = 0.0;
333 
334  ib = halfbandwidth;
335  for (i = 1; i < numeqs; i++)
336  {
337  m1 = std::min(ib - 1, numeqs - i);
338  for (j = 0; j < m1; j++)
339  {
340  sum = 0.0;
341  k1 = std::min(i, ib - j - 1);
342  for (k = 0; k < k1; k++)
343  {
344  if (fabs(a[i - k - 1][0]) < 1e-20)
345  return false;
346  else
347  {
348  if (fabs(a[i - k - 1][0]) < 1e-20)
349  return false;
350  sum += a[i - k - 1][k + 1] * a[i - k - 1][j + k + 1] / a[i - k - 1][0];
351  }
352  }
353  a[i][j] -= sum;
354  }
355  }
356 
357  for (i = 1; i < numeqs; i++)
358  {
359  sum = 0.0;
360  k1 = std::min(ib - 1, i);
361  for (k = 0; k < k1; k++)
362  {
363  if (fabs(a[i - k - 1][0] * b[i - k - 1]) < 1e-20)
364  return false;
365  sum += a[i - k - 1][k + 1] / a[i - k - 1][0] * b[i - k - 1];
366  }
367  b[i] -= sum;
368  }
369 
370  if (fabs(a[numeqs - 1][0]) < 1e-20)
371  return false;
372  x[numeqs - 1] = b[numeqs - 1] / a[numeqs - 1][0];
373  np1 = numeqs;
374  for (k = 1; k < numeqs; k++)
375  {
376  i = np1 - k;
377  j1 = i + 1;
378  j2 = std::min(numeqs, i + ib - 1);
379  sum = 0.0;
380  for (j = j1; j <= j2; j++)
381  {
382  mM = j - j1 + 2;
383  sum += x[j - 1] * a[i - 1][mM - 1];
384  }
385  if (fabs(a[i - 1][0]) < 1e-20)
386  return false;
387  x[i - 1] = (b[i - 1] - sum) / a[i - 1][0];
388  }
389  return true;
390 } // mxSolveBandedEquations
391 //-------------------------------------------------------------------------------
398 //-------------------------------------------------------------------------------
399 bool mxSolve3x3(double A[3][3], double x[3], double b[3])
400 {
401  int indx[3];
402  double d;
403 
404  if (!mxiLudcmp3(A, indx, &d))
405  return false;
406  mxiLubksb3(A, indx, b);
407 
408  x[0] = b[0];
409  x[1] = b[1];
410  x[2] = b[2];
411  return true;
412 } /* mxSolve3x3 */
413 //-------------------------------------------------------------------------------
421 //-------------------------------------------------------------------------------
422 int mxInvert4x4(const double matrix[4][4], double inv[4][4])
423 {
424  double tmp[4][4], scale[4];
425  // Make local copy of matrix
426  mxCopy4x4(tmp, matrix);
427  // generate scaling factors
428  double dummy;
429  int i, j, k, l;
430  for (i = 0; i < 4; i++)
431  {
432  double biggest = 0.0;
433  for (j = 0; j < 4; j++)
434  if ((dummy = fabs(tmp[i][j])) > biggest)
435  biggest = dummy;
436  if (biggest == 0.0)
437  {
438  XM_LOG(xmlog::error, "(mxInvert4x4) Singular Matrix");
439  return XM_FAILURE;
440  }
441  scale[i] = 1.0 / biggest;
442  }
443 
444  int index_col[4], index_row[4], index_pivot[4];
445  index_pivot[0] = 0;
446  index_pivot[1] = 0;
447  index_pivot[2] = 0;
448  index_pivot[3] = 0;
449  // main loop, columns to be reduced
450  int irow = 0, icol = 0;
451  for (i = 0; i < 4; i++)
452  {
453  // get pivot element
454  double biggest = 0.0;
455  for (j = 0; j < 4; j++)
456  if (index_pivot[j] != 1)
457  for (k = 0; k < 4; k++)
458  {
459  if (index_pivot[k] == 0)
460  {
461  if ((dummy = scale[j] * fabs(tmp[j][k])) >= biggest)
462  {
463  biggest = dummy;
464  irow = j;
465  icol = k;
466  }
467  }
468  else if (index_pivot[k] > 1)
469  {
470  XM_LOG(xmlog::error, "(mxInvert4x4) Singular Matrix");
471  return XM_FAILURE;
472  }
473  }
474  ++(index_pivot[icol]);
475  // interchange rows
476  if (irow != icol)
477  {
478  double temp = tmp[irow][0];
479  tmp[irow][0] = tmp[icol][0];
480  tmp[icol][0] = temp;
481  temp = tmp[irow][1];
482  tmp[irow][1] = tmp[icol][1];
483  tmp[icol][1] = temp;
484  temp = tmp[irow][2];
485  tmp[irow][2] = tmp[icol][2];
486  tmp[icol][2] = temp;
487  temp = tmp[irow][3];
488  tmp[irow][3] = tmp[icol][3];
489  tmp[icol][3] = temp;
490  temp = scale[irow];
491  scale[irow] = scale[icol];
492  scale[icol] = temp;
493  }
494  index_row[i] = irow;
495  index_col[i] = icol;
496  if (tmp[icol][icol] == 0.0)
497  {
498  XM_LOG(xmlog::error, "(mxInvert4x4) Singular Matrix");
499  return XM_FAILURE;
500  }
501  // divide pivot row by pivot
502  double pivot_inverse = 1.0 / tmp[icol][icol];
503  tmp[icol][icol] = 1.0;
504  tmp[icol][0] *= pivot_inverse;
505  tmp[icol][1] *= pivot_inverse;
506  tmp[icol][2] *= pivot_inverse;
507  tmp[icol][3] *= pivot_inverse;
508  // reduce all rows except pivot row
509  for (l = 0; l < 4; l++)
510  if (l != icol)
511  {
512  dummy = tmp[l][icol];
513  tmp[l][icol] = 0.0;
514  tmp[l][0] -= tmp[icol][0] * dummy;
515  tmp[l][1] -= tmp[icol][1] * dummy;
516  tmp[l][2] -= tmp[icol][2] * dummy;
517  tmp[l][3] -= tmp[icol][3] * dummy;
518  }
519  }
520  // end of reduction algorithm
521  // unscramble solution
522  for (l = 3; l >= 0; l--)
523  {
524  if (index_row[l] != index_col[l])
525  {
526  double temp = tmp[0][index_row[l]];
527  tmp[0][index_row[l]] = tmp[0][index_col[l]];
528  tmp[0][index_col[l]] = temp;
529  temp = tmp[1][index_row[l]];
530  tmp[1][index_row[l]] = tmp[1][index_col[l]];
531  tmp[1][index_col[l]] = temp;
532  temp = tmp[2][index_row[l]];
533  tmp[2][index_row[l]] = tmp[2][index_col[l]];
534  tmp[2][index_col[l]] = temp;
535  temp = tmp[3][index_row[l]];
536  tmp[3][index_row[l]] = tmp[3][index_col[l]];
537  tmp[3][index_col[l]] = temp;
538  }
539  }
540  // copy solution to output
541  mxCopy4x4(inv, tmp);
542  return XM_SUCCESS;
543 } // mxInvert4x4
544 //-------------------------------------------------------------------------------
548 //-------------------------------------------------------------------------------
549 void mxPointMult(Pt3d* pt, const double ctm[4][4])
550 {
551  double tx = pt->x;
552  double ty = pt->y;
553  double tz = pt->z;
554  pt->x = tx * ctm[0][0] + ty * ctm[0][1] + tz * ctm[0][2] + ctm[0][3];
555  pt->y = tx * ctm[1][0] + ty * ctm[1][1] + tz * ctm[1][2] + ctm[1][3];
556  pt->z = tx * ctm[2][0] + ty * ctm[2][1] + tz * ctm[2][2] + ctm[2][3];
557 } // mxPointMult
558 //-------------------------------------------------------------------------------
562 //-------------------------------------------------------------------------------
563 void mxCopy4x4(double copy[4][4], const double matrix[4][4])
564 {
565  memcpy((char*)&(copy[0][0]), &(matrix[0][0]), 16 * sizeof(double));
566 } // mxCopy4x4
567 //-------------------------------------------------------------------------------
570 //-------------------------------------------------------------------------------
571 void mxIdent4x4(double matrix[4][4])
572 {
573  matrix[0][1] = matrix[0][2] = matrix[0][3] = 0.0;
574  matrix[1][0] = matrix[1][2] = matrix[1][3] = 0.0;
575  matrix[2][0] = matrix[2][1] = matrix[2][3] = 0.0;
576  matrix[3][0] = matrix[3][1] = matrix[3][2] = 0.0;
577  matrix[0][0] = matrix[1][1] = matrix[2][2] = matrix[3][3] = 1.0;
578 } // mxIdent4x4
579 //-------------------------------------------------------------------------------
584 //-------------------------------------------------------------------------------
585 void mxMult4x4(double product[4][4], const double matrix1[4][4], const double matrix2[4][4])
586 {
587  int i, j, k;
588  // We make internal copies of the matrices to allow you to pass the same
589  // matrix as both the product and either matrix1 or matrix2.
590  double temp1[4][4], temp2[4][4];
591  mxCopy4x4(temp1, matrix1);
592  mxCopy4x4(temp2, matrix2);
593  for (i = 3; i >= 0; i--)
594  {
595  for (j = 3; j >= 0; j--)
596  {
597  product[i][j] = 0.;
598  for (k = 3; k >= 0; k--)
599  product[i][j] += (temp1[i][k] * temp2[k][j]);
600  }
601  }
602 } // mxMult4x4
603 //-------------------------------------------------------------------------------
610 //-------------------------------------------------------------------------------
611 void mxRotate4x4(double xrot, double yrot, double zrot, double rMatt[4][4])
612 {
613  // rotation cosines
614  double cosX = cos(xrot * XM_PI / 180);
615  double cosY = cos(yrot * XM_PI / 180);
616  double cosZ = cos(zrot * XM_PI / 180);
617  // rotation sines
618  double sinX = sin(xrot * XM_PI / 180);
619  double sinY = sin(yrot * XM_PI / 180);
620  double sinZ = sin(zrot * XM_PI / 180);
621  mxIdent4x4(rMatt);
622  rMatt[0][0] = cosY * cosZ;
623  rMatt[1][0] = cosX * sinZ + sinX * sinY * cosZ;
624  rMatt[2][0] = sinX * sinZ - cosX * sinY * cosZ;
625  rMatt[0][1] = -cosY * sinZ;
626  rMatt[1][1] = cosX * cosZ - sinX * sinY * sinZ;
627  rMatt[2][1] = sinX * cosZ + cosX * sinY * sinZ;
628  rMatt[0][2] = sinY;
629  rMatt[1][2] = -sinX * cosY;
630  rMatt[2][2] = cosX * cosY;
631 } // mxRotate4x4
632 //-------------------------------------------------------------------------------
637 //-------------------------------------------------------------------------------
638 void mxTranslate4x4(const Pt3d& a_translation, double a_mx[4][4])
639 {
640  mxIdent4x4(a_mx);
641  // build scale matrix
642  a_mx[0][3] = a_translation.x;
643  a_mx[1][3] = a_translation.y;
644  a_mx[2][3] = a_translation.z;
645 } // mxTranslate4x4
646 } // namespace xms
#define XM_FAILURE
void mxRotate4x4(double xrot, double yrot, double zrot, double rMatt[4][4])
return a rotation matrix with specified x, y, z rotations z - y - x order
Definition: matrix.cpp:611
#define XM_LOG(A, B)
int mxLUBcksub(double **mat, int n, const int *indx, double *b)
solve [mat]{x} = {b} by back substitution (mat = LU of mat), from "Numerical Recipes in C" p 44...
Definition: matrix.cpp:122
void mxMult4x4(double product[4][4], const double matrix1[4][4], const double matrix2[4][4])
Multiplies two transformation matrices.
Definition: matrix.cpp:585
void mxIdent4x4(double matrix[4][4])
Sets a transformation matrix to identity.
Definition: matrix.cpp:571
int mxInvert4x4(const double matrix[4][4], double inv[4][4])
Compute the inverse of a transformation matrix. Checks for special case of Orthogonal 4x4 and does ea...
Definition: matrix.cpp:422
int mxLUDecomp(double **mat, int n, int *indx, double *d)
Decompose an n x n matrix into Upper & Lower trianglar (in place), from "Numerical Recipes in C" p 43...
Definition: matrix.cpp:47
routines for manipulating matrices
void mxCopy4x4(double copy[4][4], const double matrix[4][4])
Copy a transformation matrix. Simply uses memcpy.
Definition: matrix.cpp:563
bool mxSolveBandedEquations(double **a, double *x, double *b, int numeqs, int halfbandwidth)
Solves the matrix equation [a][x]=[b] using gauss elimination.
Definition: matrix.cpp:325
bool mxSolve3x3(double A[3][3], double x[3], double b[3])
Solves the matrix equation [A]*{x}={b} for {x} where [A] is 3x3 and {x} and {b} are 3x1 vectors...
Definition: matrix.cpp:399
Pt3< double > Pt3d
void mxiLubksb3(const double mat[3][3], const int indx[3], double b[3])
solve [mat]{x} = {b} by back substitution (mat = LU of mat)
Definition: matrix.cpp:231
XMS Namespace.
Definition: geoms.cpp:34
#define XM_SUCCESS
void mxPointMult(Pt3d *pt, const double ctm[4][4])
Multiplies a point by a transformation matrix.
Definition: matrix.cpp:549
#define XM_PI
void mxTranslate4x4(const Pt3d &a_translation, double a_mx[4][4])
return a translation matrix with specified translation z - y - x order
Definition: matrix.cpp:638
bool mxiLudcmp3(double mat[3][3], int indx[3], double *d)
Decomposes a 3 x 3 matrix into Upper & Lower trianglar(in place)
Definition: matrix.cpp:157
bool mxSolveNxN(double **A, double *x, double *b, int n)
Solves the matrix equation [A]*{x}={b} for {x} where [A] is NxN and {x} and {b} are Nx1 vectors...
Definition: matrix.cpp:268