cheshirekow  v0.1.0
rotation_conversions.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Josh Bialkowski (jbialk@mit.edu)
3  *
4  * This file is part of fiber.
5  *
6  * fiber is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * fiber is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with fiber. If not, see <http://www.gnu.org/licenses/>.
18  */
24 #ifndef FIBER_ROTATION_CONVERSIONS_H_
25 #define FIBER_ROTATION_CONVERSIONS_H_
26 
27 
28 namespace fiber {
29 
30 // forward declare the types
31 template <typename Scalar>
32 class AxisAngle;
33 template <typename Scalar, int Axis>
34 class CoordinateAxisAngle;
35 template <typename Scalar>
36 class Quaternion;
37 namespace euler {
38 template <typename Scalar, int Axis1, int Axis2, int Axis3>
39 class Angles;
40 } // namespace euler
41 
42 
49 template <typename Scalar, class Exp>
51  const Scalar angle, Quaternion<Scalar>* q) {
52  Scalar theta_over_2 = angle / Scalar(2.0);
53  Scalar cos_theta_over_2 = std::cos(theta_over_2);
54  Scalar sin_theta_over_2 = std::sin(theta_over_2);
55  (*q)[0] = cos_theta_over_2;
56  (*q)[1] = sin_theta_over_2 * axis[0];
57  (*q)[2] = sin_theta_over_2 * axis[1];
58  (*q)[3] = sin_theta_over_2 * axis[2];
59 }
60 
67 template <typename Scalar>
69  Quaternion<Scalar>* q) {
70  AxisAngleToQuaternion(axis_angle.GetAxis(), axis_angle.GetAngle(), q);
71 }
72 
79 template <typename Scalar, class Exp>
82  Scalar sin_theta = std::sin(axis_angle.GetAngle());
83  Scalar cos_theta = std::cos(axis_angle.GetAngle());
84  (*R) = cos_theta * Eye<Scalar, 3>()
85  + sin_theta * CrossMatrix(axis_angle.GetAxis())
86  + (1 - cos_theta) * axis_angle.GetAxis()
87  * Transpose(axis_angle.GetAxis());
88 }
89 
96 template <typename Scalar, int Axis>
98  const CoordinateAxisAngle<Scalar, Axis>& axis_angle,
99  Quaternion<Scalar>* q) {
100  Scalar theta_over_2 = axis_angle.GetAngle() / Scalar(2.0);
101  Scalar cos_theta_over_2 = std::cos(theta_over_2);
102  Scalar sin_theta_over_2 = std::sin(theta_over_2);
103  (*q)[0] = cos_theta_over_2;
104  (*q)[1] = (Axis == 0 ? sin_theta_over_2 : 0);
105  (*q)[2] = (Axis == 1 ? sin_theta_over_2 : 0);
106  (*q)[3] = (Axis == 2 ? sin_theta_over_2 : 0);
107 }
108 
115 template <typename Scalar, int Axis, class Exp>
117  const CoordinateAxisAngle<Scalar, Axis>& axis_angle,
119  Scalar sin_theta = std::sin(axis_angle.GetAngle());
120  Scalar cos_theta = std::cos(axis_angle.GetAngle());
121  if(Axis == 0) {
122  (*R) << 1, 0, 0,
123  0, cos_theta, -sin_theta,
124  0, sin_theta, cos_theta;
125  } else if (Axis == 1) {
126  (*R) << cos_theta, 0, sin_theta,
127  0, 1, 0,
128  -sin_theta, 0, cos_theta;
129  } else if (Axis == 2) {
130  (*R) << cos_theta, -sin_theta, 0,
131  sin_theta, cos_theta, 0,
132  0, 0, 1;
133  }
134 }
135 
136 template <typename Scalar, class Exp>
138  fiber::_LValue<Scalar, Exp>* axis, Scalar* angle) {
139  assert(axis->size() >= 3);
140  Scalar sin_theta_over_2 = fiber::Norm(fiber::Rows(q, 1, 3));
141  Scalar cos_theta_over_2 = q[0];
142  *angle = Scalar(2.0) * std::atan2(sin_theta_over_2, cos_theta_over_2);
144  if (*angle < 1e-9) {
145  *axis = Scalar(1.0) / sin_theta_over_2 * fiber::Rows(q, 1, 3);
146  } else {
147  *axis = fiber::Rows(q, 1, 3);
148  }
149 }
150 
151 template <typename Scalar, class Exp>
154  assert(R->size() >= 9);
155  assert(R->rows() >= 3);
156  assert(R->cols() >= 3);
157 
158  // Note: this is the transpose of what is given in Diebel to match
159  // the convention in eigen
160  (*R)(0, 0) = q[0] * q[0] + q[1] * q[1] - q[2] * q[2] - q[3] * q[3];
161  (*R)(1, 0) = 2 * q[1] * q[2] + 2 * q[0] * q[3];
162  (*R)(2, 0) = 2 * q[1] * q[3] - 2 * q[0] * q[2];
163  (*R)(0, 1) = 2 * q[1] * q[2] - 2 * q[0] * q[3];
164  (*R)(1, 1) = q[0] * q[0] - q[1] * q[1] + q[2] * q[2] - q[3] * q[3];
165  (*R)(2, 1) = 2 * q[2] * q[3] + 2 * q[0] * q[1];
166  (*R)(0, 2) = 2 * q[1] * q[3] + 2 * q[0] * q[2];
167  (*R)(1, 2) = 2 * q[2] * q[3] - 2 * q[0] * q[1];
168  (*R)(2, 2) = q[0] * q[0] - q[1] * q[1] - q[2] * q[2] + q[3] * q[3];
169 }
170 
171 template <typename Scalar, class Exp>
173  Quaternion<Scalar>* q) {
174  assert(R.size() >= 9);
175  assert(R.rows() >= 3);
176  assert(R.cols() >= 3);
177  const Scalar r11 = R(0, 0);
178  const Scalar r12 = R(0, 1);
179  const Scalar r13 = R(0, 2);
180  const Scalar r21 = R(1, 0);
181  const Scalar r22 = R(1, 1);
182  const Scalar r23 = R(1, 2);
183  const Scalar r31 = R(2, 0);
184  const Scalar r32 = R(2, 1);
185  const Scalar r33 = R(2, 2);
186 
187  // Note: these are the conjugate of what is given in Diebel to match the
188  // convention in eigen
189  if (r22 > -r33 && r11 > -r22 && r11 > -r33) {
190  const Scalar k = std::sqrt(1 + r11 + r22 + r33);
191  (*q)[0] = Scalar(0.5) * k;
192  (*q)[1] = -Scalar(0.5) * (r23 - r32) / k;
193  (*q)[2] = -Scalar(0.5) * (r31 - r13) / k;
194  (*q)[3] = -Scalar(0.5) * (r12 - r21) / k;
195  } else if (r22 < -r33 && r11 > r22 && r11 > r33) {
196  const Scalar k = std::sqrt(1 + r11 - r22 - r33);
197  (*q)[0] = Scalar(0.5) * (r23 - r32) / k;
198  (*q)[1] = -Scalar(0.5) * k;
199  (*q)[2] = -Scalar(0.5) * (r12 + r21) / k;
200  (*q)[3] = -Scalar(0.5) * (r31 + r13) / k;
201  } else if (r22 > r33 && r11 < r22 && r11 < -r33) {
202  const Scalar k = std::sqrt(1 - r11 + r22 - r33);
203  (*q)[0] = Scalar(0.5) * (r31 - r13) / k;
204  (*q)[1] = -Scalar(0.5) * (r21 + r12) / k;
205  (*q)[2] = -Scalar(0.5) * k;
206  (*q)[3] = -Scalar(0.5) * (r23 + r32) / k;
207  } else if (r22 < r33 && r11 < -r22 && r11 < r33) {
208  const Scalar k = std::sqrt(1 - r11 - r22 + r33);
209  (*q)[0] = Scalar(0.5) * (r12 - r21) / k;
210  (*q)[1] = -Scalar(0.5) * (r31 + r13) / k;
211  (*q)[2] = -Scalar(0.5) * (r23 + r32) / k;
212  (*q)[3] = -Scalar(0.5) * k;
213  } else {
214  assert(false);
215  }
216 }
217 
218 namespace euler {
219 
220 enum {
221  X = 0,
222  Y = 1,
223  Z = 2
224 };
225 
226 enum {
227  _1 = 0,
228  _2 = 1,
229  _3 = 2
230 };
231 
234 template <typename Scalar, int Axis1, int Axis2, int Axis3>
236  enum { HAS_SPECIALIZATION = false };
237 };
238 
239 // Equations from Stanford tech report by James Diebel
240 template <typename Scalar>
241 struct _AnglesFromQuaternion<Scalar, _1, _2, _1> {
242  enum { HAS_SPECIALIZATION = true };
243 
244  static void Build(const Quaternion<Scalar>& q,
245  Angles<Scalar, _1, _2, _1>* angles) {
246  (*angles)[0] = std::atan2(2 * q[1] * q[2] - 2 * q[0] * q[3],
247  2 * q[1] * q[3] + 2 * q[0] * q[2]);
248  (*angles)[1] =
249  std::acos(q[1] * q[1] + q[0] * q[0] - q[3] * q[3] - q[2] * q[2]);
250  (*angles)[2] = std::atan2(2 * q[1] * q[2] + 2 * q[0] * q[3],
251  -2 * q[1] * q[3] + 2 * q[0] * q[2]);
252  }
253 };
254 
255 template <typename Scalar>
256 struct _AnglesFromQuaternion<Scalar, _1, _2, _3> {
257  enum { HAS_SPECIALIZATION = true };
258 
259  static void Build(const Quaternion<Scalar>& q,
260  Angles<Scalar, _1, _2, _3>* angles) {
261  (*angles)[0] =
262  std::atan2(-2 * q[1] * q[2] + 2 * q[0] * q[3],
263  q[1] * q[1] + q[0] * q[0] - q[3] * q[3] - q[2] * q[2]);
264  (*angles)[1] = std::asin(2 * q[1] * q[3] + 2 * q[0] * q[2]);
265  (*angles)[2] =
266  std::atan2(-2 * q[2] * q[3] + 2 * q[0] * q[1],
267  q[3] * q[3] - q[2] * q[2] - q[1] * q[1] + q[0] * q[0]);
268  }
269 };
270 
271 template <typename Scalar>
272 struct _AnglesFromQuaternion<Scalar, _3, _2, _1> {
273  enum { HAS_SPECIALIZATION = true };
274 
275  static void Build(const Quaternion<Scalar>& q,
276  Angles<Scalar, _3, _2, _1>* angles) {
277  (*angles)[0] =
278  std::atan2(2 * q[2] * q[3] + 2 * q[0] * q[1],
279  q[3] * q[3] - q[2] * q[2] - q[1] * q[1] + q[0] * q[0]);
280  (*angles)[1] = -std::asin(2 * q[1] * q[3] - 2 * q[0] * q[2]);
281  (*angles)[2] =
282  std::atan2(2 * q[1] * q[2] + 2 * q[0] * q[3],
283  q[1] * q[1] + q[0] * q[0] - q[3] * q[3] - q[2] * q[2]);
284  }
285 };
286 
287 template <typename Scalar>
288 struct _AnglesFromQuaternion<Scalar, _3, _1, _3> {
289  enum { HAS_SPECIALIZATION = true };
290 
291  static void Build(const Quaternion<Scalar>& q,
292  Angles<Scalar, _3, _1, _3>* angles) {
293  (*angles)[0] = std::atan2(2 * q[1] * q[3] - 2 * q[0] * q[2],
294  2 * q[2] * q[3] + 2 * q[0] * q[1]);
295  (*angles)[1] =
296  std::acos(q[3] * q[3] - q[2] * q[2] - q[1] * q[1] + q[0] * q[0]);
297  (*angles)[2] = std::atan2(2 * q[1] * q[3] + 2 * q[0] * q[2],
298  -2 * q[2] * q[3] + 2 * q[0] * q[1]);
299  }
300 };
301 
302 } // namespace euler
303 
304 template<typename Scalar, int Axis1, int Axis2, int Axis3>
307  Quaternion<Scalar>* q) {
308  *q = CoordinateAxisAngle<Scalar, Axis1>(euler[0]).ToQuaternion()
309  * CoordinateAxisAngle<Scalar, Axis2>(euler[1]).ToQuaternion()
310  * CoordinateAxisAngle<Scalar, Axis3>(euler[2]).ToQuaternion();
311 }
312 
313 } // namespace fiber
314 
315 
316 
317 #endif // FIBER_ROTATION_CONVERSIONS_H_
static void Build(const Quaternion< Scalar > &q, Angles< Scalar, _3, _2, _1 > *angles)
Size cols() const
Definition: lvalue.h:39
void EulerAnglesToQuaternion(const euler::Angles< Scalar, Axis1, Axis2, Axis3 > &euler, Quaternion< Scalar > *q)
void QuaternionToAxisAngle(const Quaternion< Scalar > &q, fiber::_LValue< Scalar, Exp > *axis, Scalar *angle)
_CrossMatrix< Scalar, Exp > CrossMatrix(_RValue< Scalar, Exp > const &A)
cross-product matrix of a vector
Definition: cross_matrix.h:101
construction euler angles from quaternion, only certain sequences can be constructed this way ...
expression template for rvalues
Definition: rvalue.h:33
const AxisType & GetAxis() const
Definition: axis_angle.h:47
void QuaternionToRotationMatrix(const Quaternion< Scalar > &q, fiber::_LValue< Scalar, Exp > *R)
void CoordinateAxisAngleToRotationMatrix(const CoordinateAxisAngle< Scalar, Axis > &axis_angle, _LValue< Scalar, Exp > *R)
Size cols() const
Definition: rvalue.h:37
static void Build(const Quaternion< Scalar > &q, Angles< Scalar, _1, _2, _3 > *angles)
static void Build(const Quaternion< Scalar > &q, Angles< Scalar, _3, _1, _3 > *angles)
void AxisAngleToQuaternion(const fiber::_RValue< Scalar, Exp > &axis, const Scalar angle, Quaternion< Scalar > *q)
static void Build(const Quaternion< Scalar > &q, Angles< Scalar, _1, _2, _1 > *angles)
Size rows() const
Definition: lvalue.h:38
Scalar GetAngle() const
Definition: axis_angle.h:58
Size rows() const
Definition: rvalue.h:36
Scalar Norm(_RValue< Scalar, Exp > const &A)
Return the 2-norm of a vector.
Definition: normalize.h:41
void CoordinateAxisAngleToQuaternion(const CoordinateAxisAngle< Scalar, Axis > &axis_angle, Quaternion< Scalar > *q)
void RotationMatrixToQuaternion(const fiber::_RValue< Scalar, Exp > &R, Quaternion< Scalar > *q)
A N x N matrix expression for the identity matrix.
Definition: identity.h:32
LView< Scalar, Exp, rows, Exp::COLS_ > Rows(_LValue< Scalar, Exp > &A, int i)
Definition: view.h:172
Size size() const
Definition: lvalue.h:37
_Transpose< Scalar, Exp > Transpose(_RValue< Scalar, Exp > const &A)
Definition: transpose.h:54
expression template for rvalues
Definition: lvalue.h:33
A vector of euler angles.
Definition: euler_angles.h:40
An axis angle rotation about a coordinate axis.
Definition: axis_angle.h:103
Encodes a rotation in 3-dimensions by an return RView<Scalar, Exp, rows, Exp::COLS>(static_cast<Exp c...
Definition: axis_angle.h:33
Scalar GetAngle() const
Definition: axis_angle.h:123
Size size() const
Definition: rvalue.h:35
void AxisAngleToRotationMatrix(const AxisAngle< Scalar > &axis_angle, _LValue< Scalar, Exp > *R)