BubbleProfiler  0.3.0
by Peter Athron, Csaba Balazs, Michael Bardsley, Andrew Fowlie, Dylan Harries & Graham White
rotation.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of BubbleProfiler.
3  *
4  * BubbleProfiler is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * BubbleProfiler is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with BubbleProfiler. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19 Notes
20 - The method for obtaining the new coordinate system
21  seems a bit inelegant. There is probably a cleaner way.
22 */
23 
24 #include "rotation.hpp"
25 #include "error.hpp"
26 
27 #include <vector>
28 #include <string>
29 #include <cassert>
30 #include <stdexcept>
31 
32 #include <Eigen/Dense>
33 
34 namespace BubbleProfiler {
35 
36 Eigen::MatrixXd calculate_rotation_to_target(const Eigen::VectorXd& target)
37 {
38  // Target must not be origin
39  if (target.isZero()) {
40  throw Setup_error("Rotation:calculate_rotation_to_target: "
41  "Invalid target: cannot rotate to origin.");
42  }
43 
44  const int num_dims = target.rows();
45 
46  // Matrix with target as first *row*. We use LU decomp.
47  // and find the null basis, which spans the complement
48  // of the target vector.
49  Eigen::MatrixXd mat_fr_target(
50  Eigen::MatrixXd::Zero(num_dims, num_dims));
51  mat_fr_target.row(0) = target;
52 
53  Eigen::FullPivLU<Eigen::MatrixXd> mat_t_lu(mat_fr_target);
54 
55  // Sanity check
56  assert(mat_t_lu.dimensionOfKernel() == num_dims - 1);
57  Eigen::MatrixXd mat_fr_kernel = mat_t_lu.kernel();
58 
59  // Adjoin target vector (as first column) to kernel matrix
60  Eigen::MatrixXd mat_basis = Eigen::MatrixXd(num_dims, num_dims);
61  mat_basis.col(0) = target;
62  for (int i = 1; i != num_dims; ++i) {
63  mat_basis.col(i) = mat_fr_kernel.col(i - 1);
64  }
65 
66  // Now we use a QR decomp to obtain an orthonormal basis
67  // for the new coordinate system. This is in fact the
68  // change of basis matrix that maps new -> old
69  Eigen::MatrixXd m_cob_new_to_old(
70  mat_basis.fullPivHouseholderQr().matrixQ());
71 
72  // The QR decomp may flip the sign of the first column; to be
73  // sure, we replace it with the normalized target vector
74  m_cob_new_to_old.col(0) = target.normalized();
75 
76  return m_cob_new_to_old;
77 }
78 
79 } // namespace BubbleProfiler
Eigen::MatrixXd calculate_rotation_to_target(const Eigen::VectorXd &target)
Calculate the rotation matrix for a rotation to the target vector.
Definition: rotation.cpp:36
Exception indicating general setup error.
Definition: error.hpp:32