gtsam  4.0.0
gtsam
Quaternion.h
Go to the documentation of this file.
1 /* ----------------------------------------------------------------------------
2 
3  * GTSAM Copyright 2010, Georgia Tech Research Corporation,
4  * Atlanta, Georgia 30332-0415
5  * All Rights Reserved
6  * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7 
8  * See LICENSE for the license information
9 
10  * -------------------------------------------------------------------------- */
11 
18 #pragma once
19 
20 #include <gtsam/base/Lie.h>
21 #include <gtsam/base/concepts.h>
22 #include <gtsam/geometry/SO3.h> // Logmap/Expmap derivatives
23 #include <limits>
24 
25 #define QUATERNION_TYPE Eigen::Quaternion<_Scalar,_Options>
26 
27 namespace gtsam {
28 
29 // Define traits
30 template<typename _Scalar, int _Options>
31 struct traits<QUATERNION_TYPE> {
32  typedef QUATERNION_TYPE ManifoldType;
33  typedef QUATERNION_TYPE Q;
34 
37 
40  static Q Identity() {
41  return Q::Identity();
42  }
43 
47  enum {
48  dimension = 3
49  };
51  typedef Eigen::Matrix<_Scalar, 3, 1, _Options, 3, 1> TangentVector;
52 
56  static Q Compose(const Q &g, const Q & h,
57  ChartJacobian Hg = boost::none, ChartJacobian Hh = boost::none) {
58  if (Hg) *Hg = h.toRotationMatrix().transpose();
59  if (Hh) *Hh = I_3x3;
60  return g * h;
61  }
62 
63  static Q Between(const Q &g, const Q & h,
64  ChartJacobian Hg = boost::none, ChartJacobian Hh = boost::none) {
65  Q d = g.inverse() * h;
66  if (Hg) *Hg = -d.toRotationMatrix().transpose();
67  if (Hh) *Hh = I_3x3;
68  return d;
69  }
70 
71  static Q Inverse(const Q &g,
72  ChartJacobian H = boost::none) {
73  if (H) *H = -g.toRotationMatrix();
74  return g.inverse();
75  }
76 
78  static Q Expmap(const Eigen::Ref<const TangentVector>& omega,
79  ChartJacobian H = boost::none) {
80  using std::cos;
81  using std::sin;
82  if (H) *H = SO3::ExpmapDerivative(omega.template cast<double>());
83  _Scalar theta2 = omega.dot(omega);
84  if (theta2 > std::numeric_limits<_Scalar>::epsilon()) {
85  _Scalar theta = std::sqrt(theta2);
86  _Scalar ha = _Scalar(0.5) * theta;
87  Vector3 vec = (sin(ha) / theta) * omega;
88  return Q(cos(ha), vec.x(), vec.y(), vec.z());
89  } else {
90  // first order approximation sin(theta/2)/theta = 0.5
91  Vector3 vec = _Scalar(0.5) * omega;
92  return Q(1.0, vec.x(), vec.y(), vec.z());
93  }
94  }
95 
97  static TangentVector Logmap(const Q& q, ChartJacobian H = boost::none) {
98  using std::acos;
99  using std::sqrt;
100 
101  // define these compile time constants to avoid std::abs:
102  static const double twoPi = 2.0 * M_PI, NearlyOne = 1.0 - 1e-10,
103  NearlyNegativeOne = -1.0 + 1e-10;
104 
105  TangentVector omega;
106 
107  const _Scalar qw = q.w();
108  // See Quaternion-Logmap.nb in doc for Taylor expansions
109  if (qw > NearlyOne) {
110  // Taylor expansion of (angle / s) at 1
111  // (2 + 2 * (1-qw) / 3) * q.vec();
112  omega = ( 8. / 3. - 2. / 3. * qw) * q.vec();
113  } else if (qw < NearlyNegativeOne) {
114  // Taylor expansion of (angle / s) at -1
115  // (-2 - 2 * (1 + qw) / 3) * q.vec();
116  omega = (-8. / 3. - 2. / 3. * qw) * q.vec();
117  } else {
118  // Normal, away from zero case
119  _Scalar angle = 2 * acos(qw), s = sqrt(1 - qw * qw);
120  // Important: convert to [-pi,pi] to keep error continuous
121  if (angle > M_PI)
122  angle -= twoPi;
123  else if (angle < -M_PI)
124  angle += twoPi;
125  omega = (angle / s) * q.vec();
126  }
127 
128  if(H) *H = SO3::LogmapDerivative(omega.template cast<double>());
129  return omega;
130  }
131 
135 
136  static TangentVector Local(const Q& g, const Q& h,
137  ChartJacobian H1 = boost::none, ChartJacobian H2 = boost::none) {
138  Q b = Between(g, h, H1, H2);
139  Matrix3 D_v_b;
140  TangentVector v = Logmap(b, (H1 || H2) ? &D_v_b : 0);
141  if (H1) *H1 = D_v_b * (*H1);
142  if (H2) *H2 = D_v_b * (*H2);
143  return v;
144  }
145 
146  static Q Retract(const Q& g, const TangentVector& v,
147  ChartJacobian H1 = boost::none, ChartJacobian H2 = boost::none) {
148  Matrix3 D_h_v;
149  Q b = Expmap(v,H2 ? &D_h_v : 0);
150  Q h = Compose(g, b, H1, H2);
151  if (H2) *H2 = (*H2) * D_h_v;
152  return h;
153  }
154 
158  static void Print(const Q& q, const std::string& str = "") {
159  if (str.size() == 0)
160  std::cout << "Eigen::Quaternion: ";
161  else
162  std::cout << str << " ";
163  std::cout << q.vec().transpose() << std::endl;
164  }
165  static bool Equals(const Q& q1, const Q& q2, double tol = 1e-8) {
166  return Between(q1, q2).vec().array().abs().maxCoeff() < tol;
167  }
169 };
170 
171 typedef Eigen::Quaternion<double, Eigen::DontAlign> Quaternion;
172 
173 } // \namespace gtsam
174 
Base class and basic functions for Lie types.
static Matrix3 LogmapDerivative(const Vector3 &omega)
Derivative of Logmap.
Definition: SO3.cpp:176
OptionalJacobian is an Eigen::Ref like class that can take be constructed using either a fixed size o...
Definition: OptionalJacobian.h:39
3*3 matrix representation of SO(3)
Group operator syntax flavors.
Definition: Group.h:37
static TangentVector Logmap(const Q &q, ChartJacobian H=boost::none)
We use our own Logmap, as there is a slight bug in Eigen.
Definition: Quaternion.h:97
static Q Expmap(const Eigen::Ref< const TangentVector > &omega, ChartJacobian H=boost::none)
Exponential map, using the inlined code from Eigen&#39;s conversion from axis/angle.
Definition: Quaternion.h:78
tag to assert a type is a Lie group
Definition: Lie.h:167
A manifold defines a space in which there is a notion of a linear tangent space that can be centered ...
Definition: concepts.h:30
static Matrix3 ExpmapDerivative(const Vector3 &omega)
Derivative of Expmap.
Definition: SO3.cpp:128
Global functions in a separate testing namespace.
Definition: chartTesting.h:28