00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <vamos/geometry/Three_Matrix.h>
00019
00020 #include <cmath>
00021
00022 namespace Vamos_Geometry
00023 {
00024 void rotate_elements (double mat [3][3], int i, int j, int k, int l,
00025 double h, double s, double tau);
00026
00027 void swap (double& a, double& b);
00028 }
00029
00030 Vamos_Geometry::
00031 Three_Matrix::Three_Matrix (double diag)
00032 {
00033 zero ();
00034 set_diagonal (diag);
00035 }
00036
00037 Vamos_Geometry::
00038 Three_Matrix::Three_Matrix (const double mat_in [3][3])
00039 {
00040 for (int i = 0; i < 3; i++)
00041 {
00042 for (int j = 0; j < 3; j++)
00043 {
00044 m_mat [i][j] = mat_in [i][j];
00045 }
00046 }
00047 }
00048
00049 Vamos_Geometry::
00050 Three_Matrix::Three_Matrix (const Three_Matrix& mat)
00051 {
00052 copy_in (mat);
00053 }
00054
00055 Vamos_Geometry::Three_Matrix& Vamos_Geometry::
00056 Three_Matrix::operator = (const Three_Matrix& mat)
00057 {
00058 if (&mat != this)
00059 {
00060 copy_in (mat);
00061 }
00062 return *this;
00063 }
00064
00065 void Vamos_Geometry::
00066 Three_Matrix::copy_in (const Three_Matrix& mat)
00067 {
00068 for (int i = 0; i < 3; i++)
00069 {
00070 for (int j = 0; j < 3; j++)
00071 {
00072 m_mat [i][j] = mat [i][j];
00073 }
00074 }
00075 }
00076
00077 Vamos_Geometry::Three_Vector Vamos_Geometry::
00078 Three_Matrix::unit (int index) const
00079 {
00080 return Three_Vector (m_mat [0][index], m_mat [1][index], m_mat [2][index]);
00081 }
00082
00083 void Vamos_Geometry::
00084 Three_Matrix::set_diagonal (double diag)
00085 {
00086 for (int i = 0; i < 3; i++)
00087 {
00088 m_mat [i][i] = diag;
00089 }
00090 }
00091
00092 void Vamos_Geometry::
00093 Three_Matrix::identity ()
00094 {
00095 zero ();
00096 set_diagonal (1.0);
00097 }
00098
00099 void Vamos_Geometry::
00100 Three_Matrix::zero ()
00101 {
00102 for (int i = 0; i < 3; i++)
00103 {
00104 for (int j = 0; j < 3; j++)
00105 {
00106 m_mat [i][j] = 0.0;
00107 }
00108 }
00109 }
00110
00111 void Vamos_Geometry::
00112 Three_Matrix::rotate (const Three_Vector& delta_theta)
00113 {
00114 double angle = delta_theta.abs ();
00115 if (angle == 0.0)
00116 return;
00117
00118 Three_Vector unit = delta_theta / angle * sin (angle / 2.0);
00119 double w = cos (angle / 2.0);
00120
00121
00122 Three_Matrix q_rot;
00123 double x = unit [0];
00124 double y = unit [1];
00125 double z = unit [2];
00126
00127 q_rot [0][0] = 1.0 - 2.0 * (y*y + z*z);
00128 q_rot [0][1] = 2.0 * (x*y - w*z);
00129 q_rot [0][2] = 2.0 * (x*z + w*y);
00130
00131 q_rot [1][0] = 2.0 * (x*y + w*z);
00132 q_rot [1][1] = 1.0 - 2.0 * (x*x + z*z);
00133 q_rot [1][2] = 2.0 * (y*z - w*x);
00134
00135 q_rot [2][0] = 2.0 * (x*z - w*y);
00136 q_rot [2][1] = 2.0 * (y*z + w*x);
00137 q_rot [2][2] = 1.0 - 2.0 * (x*x + y*y);
00138
00139
00140
00141
00142
00143 *this *= q_rot;
00144 }
00145
00146 void Vamos_Geometry::
00147 Three_Matrix::diagonalize ()
00148 {
00149 const int dim = 3;
00150
00151 int rotations = 0;
00152 double array_z [dim] = {0.0};
00153 double array_b [dim];
00154 double mat [dim][dim];
00155
00156 for (int i = 0; i < dim; i++)
00157 {
00158 for (int j = 0; j < dim; j++)
00159 {
00160 mat [i][j] = m_mat [i][j];
00161 m_e_vec [i][j] = 0.0;
00162 }
00163 array_b [i] = m_mat [i][i];
00164 m_e_val [i] = m_mat [i][i];
00165 m_e_vec [i][i] = 1.0;
00166 }
00167
00168 for (int iter = 0; iter < 50; iter++)
00169 {
00170 double off_diag = 0.0;
00171 for (int i = 0; i < (dim - 1); i++)
00172 {
00173 for (int j = i + 1; j < dim; j++)
00174 {
00175 off_diag += mat [i][j];
00176 }
00177 }
00178 if (off_diag == 0.0)
00179 break;
00180
00181 double thresh = (iter < 4) ? (0.2 * off_diag / (dim * dim)) : 0.0;
00182
00183 for (int row = 0; row < (dim - 1); row++)
00184 {
00185 for (int col = row + 1; col < dim; col++)
00186 {
00187 double smalln = 100.0 * std::abs (mat [row][col]);
00188 if ((iter > 4)
00189 && (std::abs (m_e_val [row] + smalln)
00190 == std::abs (m_e_val [row]))
00191 && (std::abs (m_e_val [col] + smalln)
00192 == std::abs (m_e_val [col])))
00193 {
00194 mat [row][col] = 0.0;
00195 }
00196 else if (std::abs (mat [row][col]) > thresh)
00197 {
00198 double param_h = m_e_val [col] - m_e_val [row];
00199 double param_t;
00200 if (std::abs (param_h) + smalln == std::abs (param_h))
00201 {
00202 param_t = mat [row][col] / param_h;
00203 }
00204 else
00205 {
00206 double theta = 0.5 * param_h / mat [row][col];
00207 param_t = 1.0 / (std::abs (theta) +
00208 sqrt (1.0 + theta * theta));
00209 if (theta < 0.0)
00210 param_t = -param_t;
00211 }
00212 double param_c = 1.0 / sqrt (1.0 + param_t * param_t);
00213 double param_s = param_t * param_c;
00214 double tau = param_s / (1.0 + param_c);
00215
00216 param_h = param_t * mat [row][col];
00217 array_z [row] -= param_h;
00218 array_z [col] += param_h;
00219 m_e_val [row] -= param_h;
00220 m_e_val [col] += param_h;
00221 mat [row][col] = 0.0;
00222
00223
00224 for (int j = 0; j < row; j++)
00225 rotate_elements (mat, j, row, j, col,
00226 param_h, param_s, tau);
00227 for (int j = row + 1; j < col; j++)
00228 rotate_elements (mat, row, j, j, col,
00229 param_h, param_s, tau);
00230 for (int j = col + 1; j < dim; j++)
00231 rotate_elements (mat, row, j, col, j,
00232 param_h, param_s, tau);
00233
00234 for (int j = 0; j < dim; j++)
00235 rotate_elements (m_e_vec, j, row, j, col,
00236 param_h, param_s, tau);
00237
00238 rotations++;
00239 }
00240 }
00241 }
00242 for (int i = 0; i < dim; i++)
00243 {
00244 array_b [i] += array_z [i];
00245 m_e_val [i] = array_b [i];
00246 array_z [i] = 0.0;
00247 }
00248 }
00249 }
00250
00251 void
00252 Vamos_Geometry::rotate_elements (double mat [3][3], int i, int j, int k, int l,
00253 double param_h, double param_s, double tau)
00254 {
00255 double param_g = mat [i][j];
00256 param_h = mat [k][l];
00257 mat [i][j] = param_g - param_s * (param_h + param_g * tau);
00258 mat [k][l] = param_h + param_s * (param_g - param_h * tau);
00259 }
00260
00261 Vamos_Geometry::Three_Matrix Vamos_Geometry::
00262 Three_Matrix::eigen (Three_Vector* out_vec)
00263 {
00264 diagonalize ();
00265 if (out_vec)
00266 *out_vec = Three_Vector (m_e_val);
00267 return Three_Matrix (m_e_vec).transpose ();
00268 }
00269
00270 Vamos_Geometry::Three_Matrix& Vamos_Geometry::
00271 Three_Matrix::operator *= (double factor)
00272 {
00273 for (int i = 0; i < 3; i++)
00274 {
00275 for (int j = 0; j < 3; j++)
00276 {
00277 m_mat [i][j] *= factor;
00278 }
00279 }
00280 return *this;
00281 }
00282
00283 Vamos_Geometry::Three_Matrix& Vamos_Geometry::
00284 Three_Matrix::operator *= (const Three_Matrix& mat2)
00285 {
00286 double temp_mat [3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};
00287 for (int i = 0; i < 3; i++)
00288 {
00289 for (int j = 0; j < 3; j++)
00290 {
00291 for (int k = 0; k < 3; k++)
00292 {
00293 temp_mat [i][j] += m_mat [i][k] * mat2 [k][j];
00294 }
00295 }
00296 }
00297 for (int i = 0; i < 3; i++)
00298 {
00299 for (int j = 0; j < 3; j++)
00300 {
00301 m_mat [i][j] = temp_mat [i][j];
00302 }
00303 }
00304 return *this;
00305 }
00306
00307 const Vamos_Geometry::Three_Vector
00308 Vamos_Geometry::operator * (const Three_Vector& vec, const Three_Matrix& mat)
00309 {
00310 double out_vec [3] = {0.0, 0.0, 0.0};
00311 for (int i = 0; i < 3; i++)
00312 {
00313 for (int j = 0; j < 3; j++)
00314 {
00315 out_vec [i] += vec [j] * mat [j][i];
00316 }
00317 }
00318 return Three_Vector (out_vec);
00319 }
00320
00321 const Vamos_Geometry::Three_Matrix
00322 Vamos_Geometry::operator * (const Three_Matrix& mat1, const Three_Matrix& mat2)
00323 {
00324 double out_mat [3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}};
00325 for (int i = 0; i < 3; i++)
00326 {
00327 for (int j = 0; j < 3; j++)
00328 {
00329 for (int k = 0; k < 3; k++)
00330 {
00331 out_mat [i][j] += mat1 [i][k] * mat2 [k][j];
00332 }
00333 }
00334 }
00335 return Three_Matrix (out_mat);
00336 }
00337
00338 const Vamos_Geometry::Three_Matrix
00339 Vamos_Geometry::operator * (double factor, const Three_Matrix& mat)
00340 {
00341 Three_Matrix out_mat = mat;
00342 return out_mat *= factor;
00343 }
00344
00345 const Vamos_Geometry::Three_Matrix
00346 Vamos_Geometry::operator * (const Three_Matrix& mat, double factor)
00347 {
00348 return factor * mat;
00349 }
00350
00351
00352 std::ostream&
00353 Vamos_Geometry::operator << (std::ostream& os, Three_Matrix mat)
00354 {
00355 os << "[[ " << mat [0][0]
00356 << ",\t" << mat [0][1]
00357 << ",\t" << mat [0][2] << "]\n"
00358 << " [ " << mat [1][0]
00359 << ",\t" << mat [1][1]
00360 << ",\t" << mat [1][2] << "]\n"
00361 << " [ " << mat [2][0]
00362 << ",\t" << mat [2][1]
00363 << ",\t" << mat [2][2] << "]]";
00364 return os;
00365 }
00366
00367 Vamos_Geometry::Three_Matrix Vamos_Geometry::
00368 Three_Matrix::transpose () const
00369 {
00370 Three_Matrix out_mat (m_mat);
00371 out_mat [0][1] = m_mat [1][0];
00372 out_mat [1][0] = m_mat [0][1];
00373 out_mat [0][2] = m_mat [2][0];
00374 out_mat [2][0] = m_mat [0][2];
00375 out_mat [1][2] = m_mat [2][1];
00376 out_mat [2][1] = m_mat [1][2];
00377 return out_mat;
00378 }
00379
00380 void
00381 Vamos_Geometry::swap (double& a, double& b)
00382 {
00383 double temp = a;
00384 a = b;
00385 b = temp;
00386 }
00387
00388 Vamos_Geometry::Three_Matrix Vamos_Geometry::
00389 Three_Matrix::invert () const
00390 {
00391 double det
00392 = m_mat [0][0] * m_mat [1][1] * m_mat [2][2]
00393 + m_mat [0][1] * m_mat [1][2] * m_mat [2][0]
00394 + m_mat [0][2] * m_mat [1][0] * m_mat [2][1]
00395 - m_mat [0][2] * m_mat [1][1] * m_mat [2][0]
00396 - m_mat [0][1] * m_mat [1][0] * m_mat [2][2]
00397 - m_mat [0][0] * m_mat [1][2] * m_mat [2][1];
00398
00399 if (det == 0.0)
00400 {
00401 throw Singular_Matrix ();
00402 }
00403
00404
00405
00406
00407
00408 Three_Matrix out_mat;
00409 out_mat [0][0] =
00410 (m_mat [1][1] * m_mat [2][2] - m_mat [1][2] * m_mat [2][1]) / det;
00411 out_mat [1][0] =
00412 (m_mat [1][2] * m_mat [2][0] - m_mat [1][0] * m_mat [2][2]) / det;
00413 out_mat [2][0] =
00414 (m_mat [1][0] * m_mat [2][1] - m_mat [1][1] * m_mat [2][0]) / det;
00415 out_mat [0][1] =
00416 (m_mat [2][1] * m_mat [0][2] - m_mat [2][2] * m_mat [0][1]) / det;
00417 out_mat [1][1] =
00418 (m_mat [2][2] * m_mat [0][0] - m_mat [2][0] * m_mat [0][2]) / det;
00419 out_mat [2][1] =
00420 (m_mat [2][0] * m_mat [0][1] - m_mat [2][1] * m_mat [0][0]) / det;
00421 out_mat [0][2] =
00422 (m_mat [0][1] * m_mat [1][2] - m_mat [0][2] * m_mat [1][1]) / det;
00423 out_mat [1][2] =
00424 (m_mat [0][2] * m_mat [1][0] - m_mat [0][0] * m_mat [1][2]) / det;
00425 out_mat [2][2] =
00426 (m_mat [0][0] * m_mat [1][1] - m_mat [0][1] * m_mat [1][0]) / det;
00427
00428 return out_mat;
00429 }
00430
00431
00432
00433 void
00434 Vamos_Geometry::euler_angles (const Three_Matrix& mat,
00435 double* phi, double* theta, double* psi)
00436 {
00437 *theta = asin (mat [2][0]);
00438
00439 if (std::abs (*theta) > 0.00001)
00440 {
00441 double cos_theta = cos (*theta);
00442 double tr_x = mat [2][2] / cos_theta;
00443 double tr_y = -mat [2][1] / cos_theta;
00444
00445 *phi = atan2 (tr_y, tr_x);
00446
00447 tr_x = mat [0][0] / cos_theta;
00448 tr_y = mat [1][0] / cos_theta;
00449
00450 *psi = atan2 (tr_y, tr_x);
00451 }
00452 else
00453 {
00454 *phi = 0.0;
00455
00456 double tr_x = mat [1][1];
00457 double tr_y = -mat [0][1];
00458
00459 *psi = atan2 (tr_y, tr_x);
00460 }
00461 }