gtsam
Loading...
Searching...
No Matches
ExtendedPose3-inl.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
17
18#pragma once
19
20namespace gtsam {
21
22template <int K, class Derived>
23size_t ExtendedPose3<K, Derived>::RuntimeK(const TangentVector& xi) {
24 if constexpr (K == Eigen::Dynamic) {
25 assert(xi.size() >= 3 && (xi.size() - 3) % 3 == 0);
26 return static_cast<size_t>((xi.size() - 3) / 3);
27 } else {
28 return static_cast<size_t>(K);
29 }
30}
31
32template <int K, class Derived>
33void ExtendedPose3<K, Derived>::ZeroJacobian(ChartJacobian H, Eigen::Index d) {
34 if (!H) return;
35 if constexpr (dimension == Eigen::Dynamic) {
36 H->setZero(d, d);
37 } else {
38 (void)d;
39 H->setZero();
40 }
41}
42
43template <int K, class Derived>
45 : R_(R), t_(x) {}
46
47template <int K, class Derived>
48template <int FixedK, typename, typename... Vecs, typename>
50 : R_(R), t_(Matrix3K::Zero()) {
51 const Point3 columns[] = {Point3(xs)...};
52 for (Eigen::Index i = 0; i < static_cast<Eigen::Index>(FixedK); ++i) {
53 t_.col(i) = columns[i];
54 }
55}
56
57template <int K, class Derived>
59 const Eigen::Index n = T.rows();
60 if constexpr (K == Eigen::Dynamic) {
61 if (T.cols() != n || n < 3) {
62 throw std::invalid_argument("ExtendedPose3: invalid matrix shape.");
63 }
64 t_.resize(3, n - 3);
65 } else {
66 if (n != matrixDim || T.cols() != matrixDim) {
67 throw std::invalid_argument("ExtendedPose3: invalid matrix shape.");
68 }
69 }
70
71 R_ = Rot3(T.template block<3, 3>(0, 0));
72 t_ = T.block(0, 3, 3, n - 3);
73}
74
75template <int K, class Derived>
76const Rot3& ExtendedPose3<K, Derived>::rotation(ComponentJacobian H) const {
77 if (H) {
78 if constexpr (dimension == Eigen::Dynamic) {
79 H->setZero(3, static_cast<Eigen::Index>(dim()));
80 } else {
81 H->setZero();
82 }
83 H->template block<3, 3>(0, 0) = I_3x3;
84 }
85 return R_;
86}
87
88template <int K, class Derived>
89Point3 ExtendedPose3<K, Derived>::x(size_t i, ComponentJacobian H) const {
90 if (i >= k()) throw std::out_of_range("ExtendedPose3: x(i) out of range.");
91 if (H) {
92 if constexpr (dimension == Eigen::Dynamic) {
93 H->setZero(3, static_cast<Eigen::Index>(dim()));
94 } else {
95 H->setZero();
96 }
97 const Eigen::Index idx = 3 + 3 * static_cast<Eigen::Index>(i);
98 H->template block<3, 3>(0, idx) = R_.matrix();
99 }
100 return t_.col(static_cast<Eigen::Index>(i));
101}
102
103template <int K, class Derived>
104const typename ExtendedPose3<K, Derived>::Matrix3K&
106 return t_;
107}
108
109template <int K, class Derived>
110typename ExtendedPose3<K, Derived>::Matrix3K&
114
115template <int K, class Derived>
116void ExtendedPose3<K, Derived>::print(const std::string& s) const {
117 std::cout << (s.empty() ? s : s + " ") << *this << std::endl;
118}
119
120template <int K, class Derived>
122 double tol) const {
123 return R_.equals(other.R_, tol) && equal_with_abs_tol(t_, other.t_, tol);
124}
125
126template <int K, class Derived>
127typename ExtendedPose3<K, Derived>::This ExtendedPose3<K, Derived>::inverse()
128 const {
129 const Rot3 Rt = R_.inverse();
130 const Matrix3K x = -(Rt.matrix() * t_);
131 return MakeReturn(ExtendedPose3(Rt, x));
132}
133
134template <int K, class Derived>
135typename ExtendedPose3<K, Derived>::This ExtendedPose3<K, Derived>::operator*(
136 const This& other) const {
137 const ExtendedPose3& otherBase = AsBase(other);
138 if constexpr (K == Eigen::Dynamic) {
139 if (k() != otherBase.k()) {
140 throw std::invalid_argument(
141 "ExtendedPose3: compose requires matching k.");
142 }
143 }
144 Matrix3K x = t_ + R_.matrix() * otherBase.t_;
145 return MakeReturn(ExtendedPose3(R_ * otherBase.R_, x));
146}
147
148// Expmap is implemented in so3::ExpmapFunctor::expmap, based on Ethan Eade's
149// elegant Lie group document, at https://www.ethaneade.org/lie.pdf.
150// See also [this document](doc/Jacobians.md)
151template <int K, class Derived>
152typename ExtendedPose3<K, Derived>::This ExtendedPose3<K, Derived>::Expmap(
153 const TangentVector& xi, ChartJacobian Hxi) {
154 // Get angular velocity omega
155 const Vector3 w = xi.template head<3>();
156
157 // Instantiate functor for Dexp-related operations:
158 const so3::DexpFunctor local(w);
159
160// Compute rotation using Expmap
161#ifdef GTSAM_USE_QUATERNIONS
162 // Reuse any quaternion-specific validation inside Rot3::Expmap.
163 const Rot3 R = Rot3::Expmap(w);
164#else
165 const Rot3 R(local.expmap());
166#endif
167
168 const Eigen::Index k = static_cast<Eigen::Index>(RuntimeK(xi));
169
170 // The translation block is x = Jl(w) * rho.
171 // NOTE(Frank): this does the same as the intuitive formulas:
172 // t_parallel = w * w.dot(v); // translation parallel to axis
173 // w_cross_v = w.cross(v); // translation orthogonal to axis
174 // t = (w_cross_v - Rot3::Expmap(w) * w_cross_v + t_parallel) / theta2;
175 // but Local does not need R, deals automatically with the case where theta2
176 // is near zero, and also gives us the machinery for the Jacobians.
177
178 Matrix3K x;
179 if constexpr (K == Eigen::Dynamic) x.resize(3, k);
180
181 if (Hxi) {
182 ZeroJacobian(Hxi, 3 + 3 * k);
183 const so3::Kernel jacobian = local.Jacobian();
184 const Matrix3 Jr = jacobian.right();
185 // Jr here is the Jacobian of the rotation exponential map.
186 Hxi->template block<3, 3>(0, 0) = Jr;
187 const Matrix3 Rt = R.transpose();
188 for (Eigen::Index i = 0; i < k; ++i) {
189 Matrix3 H_xi_w;
190 const Eigen::Index idx = 3 + 3 * i;
191 const Vector3 rho = xi.template segment<3>(idx);
192 x.col(i) = jacobian.applyLeft(rho, &H_xi_w);
193 Hxi->template block<3, 3>(idx, 0) = Rt * H_xi_w;
194 Hxi->template block<3, 3>(idx, idx) = Jr;
195 // In the last row, Jr = R^T * Jl, see Barfoot eq. (8.83).
196 // Jl is the left Jacobian of SO(3) at w.
197 }
198 } else if (k > 0) {
199 const Matrix3 Jl = local.leftJacobian();
200 for (Eigen::Index i = 0; i < k; ++i) {
201 x.col(i).noalias() = Jl * xi.template segment<3>(3 + 3 * i);
202 }
203 }
204
205 return MakeReturn(ExtendedPose3(R, x));
206}
207
208template <int K, class Derived>
209typename ExtendedPose3<K, Derived>::TangentVector
210ExtendedPose3<K, Derived>::Logmap(const This& pose, ChartJacobian H) {
211 const ExtendedPose3& poseBase = AsBase(pose);
212 const Vector3 w = Rot3::Logmap(poseBase.R_);
213 const so3::DexpFunctor local(w);
214
215 TangentVector xi;
216 if constexpr (K == Eigen::Dynamic)
217 xi.resize(static_cast<Eigen::Index>(poseBase.dim()));
218 xi.template head<3>() = w;
219 const Eigen::Index k = static_cast<Eigen::Index>(poseBase.k());
220 if (k > 0) {
221 const Matrix3 JlInv = local.InvJacobian().left();
222 for (Eigen::Index i = 0; i < k; ++i) {
223 const Eigen::Index idx = 3 + 3 * i;
224 xi.template segment<3>(idx).noalias() = JlInv * poseBase.t_.col(i);
225 }
226 }
227
228 if (H) *H = LogmapDerivative(xi);
229 return xi;
230}
231
232template <int K, class Derived>
233typename ExtendedPose3<K, Derived>::Jacobian
235 const Matrix3 R = R_.matrix();
236
237 Jacobian adj;
238 if constexpr (dimension == Eigen::Dynamic) {
239 adj.setZero(dim(), dim());
240 } else {
241 adj.setZero();
242 }
243
244 adj.template block<3, 3>(0, 0) = R;
245 const Eigen::Index k = static_cast<Eigen::Index>(this->k());
246 for (Eigen::Index i = 0; i < k; ++i) {
247 const Eigen::Index idx = 3 + 3 * i;
248 adj.template block<3, 3>(idx, 0) = skewSymmetric(t_.col(i)) * R;
249 adj.template block<3, 3>(idx, idx) = R;
250 }
251 return adj;
252}
253
254template <int K, class Derived>
255typename ExtendedPose3<K, Derived>::Jacobian
257 const Matrix3 w_hat = skewSymmetric(xi(0), xi(1), xi(2));
258
259 const Eigen::Index k = static_cast<Eigen::Index>(RuntimeK(xi));
260
261 Jacobian adj;
262 if constexpr (dimension == Eigen::Dynamic) {
263 adj.setZero(3 + 3 * k, 3 + 3 * k);
264 } else {
265 adj.setZero();
266 }
267
268 adj.template block<3, 3>(0, 0) = w_hat;
269 for (Eigen::Index i = 0; i < k; ++i) {
270 const Eigen::Index idx = 3 + 3 * i;
271 adj.template block<3, 3>(idx, 0) =
272 skewSymmetric(xi(idx + 0), xi(idx + 1), xi(idx + 2));
273 adj.template block<3, 3>(idx, idx) = w_hat;
274 }
275 return adj;
276}
277
278template <int K, class Derived>
279typename ExtendedPose3<K, Derived>::Jacobian
281 Jacobian J;
282 Expmap(xi, J);
283 return J;
284}
285
286template <int K, class Derived>
287typename ExtendedPose3<K, Derived>::Jacobian
289 const Vector3 w = xi.template head<3>();
290
291 // Instantiate functor for Dexp-related operations:
292 const so3::DexpFunctor local(w);
293
294 const Eigen::Index k = static_cast<Eigen::Index>(RuntimeK(xi));
295 const so3::InvJKernel inverseJacobian = local.InvJacobian();
296 const Matrix3 JrInv = inverseJacobian.right();
297 const Matrix3 JlInv = inverseJacobian.left();
298
299 Jacobian H;
300 if constexpr (dimension == Eigen::Dynamic) {
301 H.setZero(3 + 3 * k, 3 + 3 * k);
302 } else {
303 H.setZero();
304 }
305
306 H.template block<3, 3>(0, 0) = JrInv;
307 const so3::Kernel& jacobian = inverseJacobian.J;
308 for (Eigen::Index i = 0; i < k; ++i) {
309 Matrix3 H_xi_w;
310 const Eigen::Index idx = 3 + 3 * i;
311 jacobian.applyLeft(xi.template segment<3>(idx), H_xi_w);
312 H.template block<3, 3>(idx, 0) = -JlInv * H_xi_w * JrInv;
313 H.template block<3, 3>(idx, idx) = JrInv;
314 }
315 return H;
316}
317
318template <int K, class Derived>
319typename ExtendedPose3<K, Derived>::Jacobian
321 return LogmapDerivative(Logmap(pose));
322}
323
324template <int K, class Derived>
325typename ExtendedPose3<K, Derived>::This
327 ChartJacobian Hxi) {
328 return ExtendedPose3::Expmap(xi, Hxi);
330
331template <int K, class Derived>
332typename ExtendedPose3<K, Derived>::TangentVector
334 ChartJacobian H) {
335 return ExtendedPose3::Logmap(pose, H);
336}
337
338template <int K, class Derived>
341 MatrixRep M;
342 if constexpr (matrixDim == Eigen::Dynamic) {
343 const Eigen::Index k = static_cast<Eigen::Index>(this->k());
344 const Eigen::Index n = 3 + k;
345 M = MatrixRep::Identity(n, n);
346 } else {
347 M = MatrixRep::Identity();
348 }
349 M.template block<3, 3>(0, 0) = R_.matrix();
350 M.block(0, 3, 3, static_cast<Eigen::Index>(this->k())) = t_;
351 return M;
352}
353
354template <int K, class Derived>
356 const TangentVector& xi) {
357 const Eigen::Index k = static_cast<Eigen::Index>(RuntimeK(xi));
358 LieAlgebra X;
359 if constexpr (matrixDim == Eigen::Dynamic) {
360 X.setZero(3 + k, 3 + k);
361 } else {
362 X.setZero();
363 }
364 X.template block<3, 3>(0, 0) =
365 skewSymmetric(xi(0), xi(1), xi(2));
366 for (Eigen::Index i = 0; i < k; ++i) {
367 const Eigen::Index idx = 3 + 3 * i;
368 X.template block<3, 1>(0, 3 + i) = xi.template segment<3>(idx);
369 }
370 return X;
371}
372
373template <int K, class Derived>
374typename ExtendedPose3<K, Derived>::TangentVector
376 if (X.rows() != X.cols() || X.rows() < 3) {
377 throw std::invalid_argument("ExtendedPose3::Vee: invalid matrix shape.");
378 }
379
380 const Eigen::Index k = [&]() -> Eigen::Index {
381 if constexpr (K == Eigen::Dynamic) {
382 return X.cols() - 3;
383 } else {
384 if (X.rows() != matrixDim) {
385 throw std::invalid_argument(
386 "ExtendedPose3::Vee: invalid matrix shape.");
387 }
388 return static_cast<Eigen::Index>(K);
389 }
390 }();
391
392 TangentVector xi;
393 if constexpr (dimension == Eigen::Dynamic) {
394 xi.resize(3 + 3 * k);
395 xi.setZero();
396 } else {
397 xi.setZero();
398 }
399 xi(0) = X(2, 1);
400 xi(1) = X(0, 2);
401 xi(2) = X(1, 0);
402 for (Eigen::Index i = 0; i < k; ++i) {
403 const Eigen::Index idx = 3 + 3 * i;
404 xi.template segment<3>(idx) = X.template block<3, 1>(0, 3 + i);
405 }
406 return xi;
407}
408
409} // namespace gtsam
Global functions in a separate testing namespace.
Definition chartTesting.h:28
Vector3 Point3
As of GTSAM 4, in order to make GTSAM more lean, it is now possible to just typedef Point3 to Vector3...
Definition Point3.h:38
Matrix3 skewSymmetric(double wx, double wy, double wz)
skew symmetric matrix returns this: 0 -wz wy wz 0 -wx -wy wx 0
Definition Matrix.h:365
@ Logmap
Use the SE_2(3) NavState Logmap for every backend.
Definition PreintegrationParams.h:32
bool equal_with_abs_tol(const Eigen::DenseBase< MATRIX > &A, const Eigen::DenseBase< MATRIX > &B, double tol=1e-9)
equals with a tolerance
Definition Matrix.h:81
MatrixRep matrix() const
Homogeneous matrix representation.
Definition ExtendedPose3-inl.h:340
static Jacobian adjointMap(const TangentVector &xi)
Lie algebra adjoint map.
Definition ExtendedPose3-inl.h:256
size_t dim() const
Definition ExtendedPose3.h:166
static LieAlgebra Hat(const TangentVector &xi)
Hat operator from tangent to Lie algebra.
Definition ExtendedPose3-inl.h:355
static This Expmap(const TangentVector &xi, ChartJacobian Hxi={})
Exponential map from tangent to group.
Definition ExtendedPose3-inl.h:152
Point3 x(size_t i, ComponentJacobian H={}) const
i-th R^3 component, returned by value.
Definition ExtendedPose3-inl.h:89
void print(const std::string &s="") const
Print this state.
Definition ExtendedPose3-inl.h:116
static TangentVector Logmap(const This &pose, ChartJacobian Hpose={})
Logarithm map from group to tangent.
Definition ExtendedPose3-inl.h:210
static Jacobian ExpmapDerivative(const TangentVector &xi)
Jacobian of Expmap.
Definition ExtendedPose3-inl.h:280
This operator*(const This &other) const
Group composition.
Definition ExtendedPose3-inl.h:135
Eigen::Matrix< double, matrixDim, matrixDim > MatrixRep
Homogeneous matrix representation in the group.
Definition ExtendedPose3.h:71
Rot3 R_
Rotation component.
Definition ExtendedPose3.h:80
size_t k() const
Definition ExtendedPose3.h:163
static TangentVector Vee(const LieAlgebra &X)
Vee operator from Lie algebra to tangent.
Definition ExtendedPose3-inl.h:375
This inverse() const
Group inverse.
Definition ExtendedPose3-inl.h:127
bool equals(const ExtendedPose3 &other, double tol=1e-9) const
Equality check with tolerance.
Definition ExtendedPose3-inl.h:121
Matrix3K t_
K translation-like columns in world frame.
Definition ExtendedPose3.h:81
ExtendedPose3()
Construct a fixed-size identity element.
Definition ExtendedPose3.h:99
Eigen::Matrix< double, matrixDim, matrixDim > LieAlgebra
Lie algebra matrix type used by Hat/Vee.
Definition ExtendedPose3.h:73
static Jacobian LogmapDerivative(const TangentVector &xi)
Jacobian of Logmap evaluated from tangent coordinates.
Definition ExtendedPose3-inl.h:288
const Rot3 & rotation(ComponentJacobian H={}) const
Rotation component.
Definition ExtendedPose3-inl.h:76
const Matrix3K & xMatrix() const
Access all x_i blocks.
Definition ExtendedPose3-inl.h:105
Jacobian AdjointMap() const
Adjoint map.
Definition ExtendedPose3-inl.h:234
static This Retract(const TangentVector &xi, ChartJacobian Hxi={})
Retract at identity.
Definition ExtendedPose3-inl.h:326
static TangentVector Local(const This &pose, ChartJacobian Hpose={})
Local coordinates at identity.
Definition ExtendedPose3-inl.h:333
Kernel: M(ω) = a I + b Ω + c Ω² with radial derivatives db,dc for Fréchet.
Definition Kernel.h:38
Definition Kernel.h:58
Rot3 is a 3D rotation represented as a rotation matrix if the preprocessor symbol GTSAM_USE_QUATERNIO...
Definition Rot3.h:65
static Rot3 Expmap(const Vector3 &v, OptionalJacobian< 3, 3 > H={})
Exponential map - create a rotation from canonical coordinates using Rodrigues' formula.
Definition Rot3M.cpp:173
static Vector3 Logmap(const Rot3 &R, OptionalJacobian< 3, 3 > H={})
Log map - returns the canonical coordinates of this rotation.
Definition Rot3M.cpp:183
Matrix3 matrix() const
return 3*3 rotation matrix
Definition Rot3M.cpp:261
Matrix3 expmap() const
Rodrigues formula.
Definition SO3.h:175
Functor that implements Exponential map and its derivatives Math extends Ethan theme of elegant I + a...
Definition SO3.h:184