Berkeley SfM
rotation.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015, The Regents of the University of California (Regents).
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following
14  * disclaimer in the documentation and/or other materials provided
15  * with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Please contact the author(s) of this library if you have any questions.
34  * Authors: Erik Nelson ( eanelson@eecs.berkeley.edu )
35  * David Fridovich-Keil ( dfk@eecs.berkeley.edu )
36  */
37 
38 #include "rotation.h"
39 
40 #include <cmath>
41 #include <Eigen/LU>
42 #include <glog/logging.h>
43 
44 namespace bsfm {
45 
46 // Convert from Euler angles to a rotation matrix. Phi, theta, and psi define the
47 // angles of the intermediate rotations about x (R_x), y (R_y), and z (R_z)
48 // respectively. See https://en.wikipedia.org/wiki/Rotation_matrix.
49 Matrix3d EulerAnglesToMatrix(double phi, double theta, double psi) {
50  double c1 = std::cos(phi);
51  double c2 = std::cos(theta);
52  double c3 = std::cos(psi);
53  double s1 = std::sin(phi);
54  double s2 = std::sin(theta);
55  double s3 = std::sin(psi);
56 
57  Matrix3d R;
58  R(0, 0) = c2*c3;
59  R(0, 1) = c3*s1*s2 - c1*s3;
60  R(0, 2) = s1*s3 + c1*c3*s2;
61  R(1, 0) = c2*s3;
62  R(1, 1) = c1*c3 + s1*s2*s3;
63  R(1, 2) = c1*s2*s3 - c3*s1;
64  R(2, 0) = -s2;
65  R(2, 1) = c2*s1;
66  R(2, 2) = c1*c2;
67 
68  return R;
69 }
70 
71 // Same thing as above, but where phi, theta, and psi are specified as a vector.
72 Matrix3d EulerAnglesToMatrix(const Vector3d& euler_angles) {
73  return EulerAnglesToMatrix(euler_angles(0), euler_angles(1), euler_angles(2));
74 }
75 
76 // Convert from a rotation matrix to Euler angles.
77 // From: http://staff.city.ac.uk/~sbbh653/publications/euler.pdf
78 // Note that the solution that is returned is only unique when phi, theta, and
79 // psi are all <= 0.5 * PI. If this is not the case, they will still be correct,
80 // but may not be unique!
81 Vector3d MatrixToEulerAngles(const Matrix3d& R) {
82  // Make sure R is actually a rotation matrix.
83  if (std::abs(R.determinant() - 1) > 1e-4) {
84  LOG(WARNING) << "R does not have a determinant of 1.";
85  return Vector3d::Zero();
86  }
87 
88  double theta = -std::asin(R(2, 0));
89 
90  if (std::abs(cos(theta)) < 1e-8) {
91  LOG(WARNING) << "Theta is approximately +/- PI/2, which yields a "
92  "singularity. Cannot decompose matrix into Euler angles.";
93  return Vector3d(theta, 0.0, 0.0);
94  }
95 
96  double phi = std::atan2(R(2, 1), R(2, 2));
97  double psi = std::atan2(R(1, 0) / std::cos(theta), R(0, 0) / std::cos(theta));
98 
99  return Vector3d(phi, theta, psi);
100 }
101 
102 // Get roll angle from a rotation matrix.
103 // Just like above, the solution will only be unique if roll < 0.5 * PI.
104 double Roll(const Matrix3d& R) {
105  double theta = -std::asin(R(2, 0));
106  if (std::abs(std::cos(theta)) < 1e-8)
107  return 0.0;
108  return std::atan2(R(2, 1), R(2, 2));
109 }
110 
111 // Get pitch angle from a rotation matrix.
112 // This solution is unique.
113 double Pitch(const Matrix3d& R) {
114  return -std::asin(R(2, 0));
115 }
116 
117 // Get yaw angle from a rotation matrix.
118 // Just like above, the solution will only be unique if yaw < 0.5 * PI.
119 double Yaw(const Matrix3d& R) {
120  double theta = -std::asin(R(2, 0));
121  if (std::abs(std::cos(theta)) < 1e-8)
122  return 0.0;
123  return std::atan2(R(1, 0) / std::cos(theta), R(0, 0) / std::cos(theta));
124 }
125 
126 // Unroll an angle to be \in [0, 2*PI)
127 double Unroll(double angle) {
128  angle = fmod(angle, 2.0 * M_PI);
129  if (angle < 0)
130  angle += 2.0 * M_PI;
131  return angle;
132 }
133 
134 // Normalize an angle to be \in [-PI, PI)
135 double Normalize(double angle) {
136  angle = fmod(angle + M_PI, 2.0 * M_PI);
137  if (angle < 0)
138  angle += 2.0 * M_PI;
139  return angle - M_PI;
140 }
141 
142 // Computes the shortest distance between two angles on S^1.
143 // Found by manipulating the first answer on:
144 // stackoverflow.com/questions/1878907/the-smallest-difference-between-2-angles
145 double S1Distance(double from, double to) {
146  double d = Unroll(Unroll(to) - Unroll(from));
147  if (d > M_PI)
148  d -= 2.0*M_PI;
149  return Normalize(d);
150 }
151 
152 // Convert from degrees to radians.
153 double D2R(double angle) {
154  return angle * M_PI / 180.0;
155 }
156 
157 // Convert from radians to degrees.
158 double R2D(double angle) {
159  return angle * 180.0 / M_PI;
160 }
161 
162 // An error metric between two rotation matrices on SO3.
163 double SO3Error(const Matrix3d& R1, const Matrix3d& R2) {
164  const Matrix3d R_error = R1.transpose()*R2 - R2.transpose()*R1;
165 
166  // 'vee' is the inverse of the hat operator, and extracts a vector from a
167  // cross-product matrix.
168  const Vector3d R_vee(R_error(2,1), R_error(0,2), R_error(1,0));
169  return (0.5 * R_vee).norm();
170 }
171 
172 } //\namespace bsfm
double Normalize(double angle)
Definition: rotation.cpp:135
double Roll(const Matrix3d &R)
Definition: rotation.cpp:104
double D2R(double angle)
Definition: rotation.cpp:153
double S1Distance(double from, double to)
Definition: rotation.cpp:145
Vector3d MatrixToEulerAngles(const Matrix3d &R)
Definition: rotation.cpp:81
double Unroll(double angle)
Definition: rotation.cpp:127
double Pitch(const Matrix3d &R)
Definition: rotation.cpp:113
double Yaw(const Matrix3d &R)
Definition: rotation.cpp:119
double R2D(double angle)
Definition: rotation.cpp:158
double SO3Error(const Matrix3d &R1, const Matrix3d &R2)
Definition: rotation.cpp:163
Definition: camera.cpp:50
Matrix3d EulerAnglesToMatrix(double phi, double theta, double psi)
Definition: rotation.cpp:49