licornea_tools
rotation.cc
Go to the documentation of this file.
1 #include "rotation.h"
2 
3 namespace tlz {
4 
5 constexpr real epsilon = 1.0e-6;
6 
7 bool is_orthogonal_matrix(const mat33& R) {
8  mat33 I(
9  1.0, 0.0, 0.0,
10  0.0, 1.0, 0.0,
11  0.0, 0.0, 1.0
12  );
13  return cv::norm(I, R * R.t()) < epsilon;
14 }
15 
16 
17 mat33 to_rotation_matrix(const vec3& euler) {
18  real x = euler[0], y = euler[1], z = euler[2];
19  mat33 Rx(
20  1.0, 0.0, 0.0,
21  0.0, std::cos(x), -std::sin(x),
22  0.0, std::sin(x), std::cos(x)
23  );
24  mat33 Ry(
25  std::cos(y), 0.0, std::sin(y),
26  0.0, 1.0, 0.0,
27  -std::sin(y), 0.0, std::cos(y)
28  );
29  mat33 Rz(
30  std::cos(z), -std::sin(z), 0.0,
31  std::sin(z), std::cos(z), 0.0,
32  0.0, 0.0, 1.0
33  );
34  mat33 R = Rz * Ry * Rx;
35  return R.t();
36 }
37 
38 
39 vec3 to_euler(const mat33& R_) {
40  if(! is_orthogonal_matrix(R_)) throw std::runtime_error("R is not an orthogonal matrix");
41 
42  mat33 R = R_.t();
43 
44  // https://www.learnopencv.com/rotation-matrix-to-euler-angles/
45 
46  real sy = std::sqrt(R(0,0)*R(0,0) + R(1,0)*R(1,0));
47  bool singular = (sy < epsilon);
48  real x, y, z;
49 
50  if(! singular) {
51  x = std::atan2(R(2,1), R(2,2));
52  y = std::atan2(-R(2,0), sy);
53  z = std::atan2(R(1,0), R(0,0));
54  } else {
55  x = std::atan2(-R(1,2), R(1,1));
56  y = std::atan2(-R(2,0), sy);
57  z = 0.0;
58  }
59 
60  return vec3(x, y, z);
61 }
62 
63 
64 }
cv::Matx< real, 3, 3 > mat33
Definition: common.h:26
double real
Definition: common.h:16
cv::Vec< real, 3 > vec3
Definition: common.h:23
mat33 to_rotation_matrix(const vec3 &euler)
Definition: rotation.cc:17
vec3 to_euler(const mat33 &R_)
Definition: rotation.cc:39
bool is_orthogonal_matrix(const mat33 &R)
Definition: rotation.cc:7
constexpr real epsilon
Definition: rotation.cc:5