NDEVR
API Documentation
se3quat.h
1// g2o - General Graph Optimization
2// Copyright (C) 2011 H. Strasdat
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// * Redistributions of source code must retain the above copyright notice,
10// this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the distribution.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
18// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27#ifndef G2O_SE3QUAT_H_
28#define G2O_SE3QUAT_H_
29
30#include "se3_ops.h"
31
32#include <Eigen/Core>
33#include <Eigen/Geometry>
34
35namespace NDEVR {
36 using namespace Eigen;
37
38 typedef Eigen::Matrix<g_type, 6, 1> Vector6d;
39 typedef Eigen::Matrix<g_type, 7, 1> Vector7d;
40
42 class SE3Quat {
43 public:
44 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
45
46
47 protected:
48
50 Vector3<g_type> m_t;
51
52
53 public:
56 _r.setIdentity();
57 m_t.setZero();
58 }
59
63 SE3Quat(const Matrix3<g_type>& R, const Vector3<g_type>& t)
64 : _r(Quaternion<g_type>(R))
65 , m_t(t)
66 {
68 }
69
73 SE3Quat(const Quaternion<g_type>& q, const Vector3<g_type>& t)
74 : _r(q)
75 , m_t(t)
76 {
78 }
79
83 template <typename Derived>
84 explicit SE3Quat(const MatrixBase<Derived>& v)
85 {
86 assert((v.size() == 6 || v.size() == 7) && "Vector dimension does not match");
87 if (v.size() == 6) {
88 for (int i=0; i<3; i++){
89 m_t[i]=v[i];
90 _r.coeffs()(i)=v[i+3];
91 }
92 _r.w() = 0.; // recover the positive w
93 if (_r.norm()>1.){
94 _r.normalize();
95 } else {
96 g_type w2=1.-_r.squaredNorm();
97 _r.w()= (w2<0.) ? 0. : sqrt(w2);
98 }
99 }
100 else if (v.size() == 7) {
101 int idx = 0;
102 for (int i=0; i<3; ++i, ++idx)
103 m_t(i) = v(idx);
104 for (int i=0; i<4; ++i, ++idx)
105 _r.coeffs()(i) = v(idx);
107 }
108 }
109
111 inline const Vector3<g_type>& translation() const {return m_t;}
114 inline void setTranslation(const Vector3<g_type>& t_) {m_t = t_;}
116 inline const Quaternion<g_type>& rotation() const {return _r;}
119 void setRotation(const Quaternion<g_type>& r_) { _r = r_; }
120
122 inline SE3Quat operator* (const SE3Quat& tr2) const{
123 SE3Quat result(*this);
124 result.m_t += _r*tr2.m_t;
125 result._r*=tr2._r;
126 result.normalizeRotation();
127 return result;
128 }
129
131 inline SE3Quat& operator*= (const SE3Quat& tr2){
132 m_t+=_r*tr2.m_t;
133 _r*=tr2._r;
135 return *this;
136 }
137
140 inline Vector3<g_type> operator* (const Vector3<g_type>& v) const {
141 return m_t+_r*v;
142 }
143
145 inline SE3Quat inverse() const{
146 SE3Quat ret;
147 ret._r=_r.conjugate();
148 ret.m_t=ret._r*(m_t*-1.);
149 return ret;
150 }
151
153 inline g_type operator [](int i) const {
154 assert(i<7);
155 if (i<3)
156 return m_t[i];
157 return _r.coeffs()[i-3];
158 }
159
160
162 inline Vector7d toVector() const{
163 Vector7d v;
164 v[0]=m_t(0);
165 v[1]=m_t(1);
166 v[2]=m_t(2);
167 v[3]=_r.x();
168 v[4]=_r.y();
169 v[5]=_r.z();
170 v[6]=_r.w();
171 return v;
172 }
173
176 inline void fromVector(const Vector7d& v){
177 _r=Quaternion<g_type>(v[6], v[3], v[4], v[5]);
178 m_t=Vector3<g_type>(v[0], v[1], v[2]);
179 }
180
182 inline Vector6d toMinimalVector() const{
183 Vector6d v;
184 v[0]=m_t(0);
185 v[1]=m_t(1);
186 v[2]=m_t(2);
187 v[3]=_r.x();
188 v[4]=_r.y();
189 v[5]=_r.z();
190 return v;
191 }
192
195 inline void fromMinimalVector(const Vector6d& v){
196 g_type w = g_type(1.)-v[3]*v[3]-v[4]*v[4]-v[5]*v[5];
197 if (w>0){
198 _r=Quaternion<g_type>(sqrt(w), v[3], v[4], v[5]);
199 } else {
200 _r=Quaternion<g_type>(0, -v[3], -v[4], -v[5]);
201 }
202 m_t=Vector3<g_type>(v[0], v[1], v[2]);
203 }
204
205
206
209 Vector6d log() const {
210 Vector6d res;
211 Matrix3<g_type> _R = _r.toRotationMatrix();
212 g_type d = g_type(0.5)*(_R(0,0)+_R(1,1)+_R(2,2)-1);
213 Vector3<g_type> omega;
214 Vector3<g_type> upsilon;
215
216
217 Vector3<g_type> dR = deltaR(_R);
218 Matrix3<g_type> V_inv;
219
220 if (d>0.99999)
221 {
222
223 omega=0.5*dR;
224 Matrix3<g_type> Omega = skew(omega);
225 V_inv = Matrix3<g_type>::Identity()- 0.5*Omega + (1./12.)*(Omega*Omega);
226 }
227 else
228 {
229 g_type d_clamped = (d < g_type(-1.0)) ? g_type(-1.0) : ((d > g_type(1.0)) ? g_type(1.0) : d);
230 g_type theta = acos(d_clamped);
231 g_type sin_theta = sqrt(g_type(1.0) - d_clamped * d_clamped);
232 if (sin_theta < g_type(1e-10))
233 {
234 // Near 180-degree rotation: use limit approximation
235 omega = g_type(PI<fltp08>() / 2.0) * dR.normalized();
236 Matrix3<g_type> Omega = skew(omega);
237 V_inv = Matrix3<g_type>::Identity() - g_type(0.5) * Omega + (g_type(1.0) / g_type(12.0)) * (Omega * Omega);
238 }
239 else
240 {
241 omega = theta / (g_type(2.0) * sin_theta) * dR;
242 Matrix3<g_type> Omega = skew(omega);
243 g_type half_theta = theta / g_type(2.0);
244 V_inv = ( Matrix3<g_type>::Identity() - g_type(0.5) * Omega
245 + ( g_type(1.0) - theta / (g_type(2.0) * tan(half_theta))) / (theta * theta) * (Omega * Omega) );
246 }
247 }
248
249 upsilon = V_inv*m_t;
250 for (int i=0; i<3;i++){
251 res[i]=omega[i];
252 }
253 for (int i=0; i<3;i++){
254 res[i+3]=upsilon[i];
255 }
256
257 return res;
258
259 }
260
263 Vector3<g_type> map(const Vector3<g_type>& xyz) const
264 {
265 return _r*xyz + m_t;
266 }
267
268
272 static SE3Quat exp(const Vector6d & update)
273 {
274 Vector3<g_type> omega;
275 for (int i=0; i<3; i++)
276 omega[i]=update[i];
277 Vector3<g_type> upsilon;
278 for (int i=0; i<3; i++)
279 upsilon[i]=update[i+3];
280
281 g_type theta = omega.norm();
282 Matrix3<g_type> Omega = skew(omega);
283
284 Matrix3<g_type> R;
285 Matrix3<g_type> V;
286 if (theta<0.00001f)
287 {
288 Matrix3<g_type> Omega2 = Omega*Omega;
289 R = (Matrix3<g_type>::Identity() + Omega + g_type(0.5)*Omega2);
290 V = (Matrix3<g_type>::Identity() + g_type(0.5)*Omega + g_type(1./6.)*Omega2);
291 }
292 else
293 {
294 Matrix3<g_type> Omega2 = Omega*Omega;
295
296 R = (Matrix3<g_type>::Identity()
297 + sin(theta)/theta *Omega
298 + (1-cos(theta))/(theta*theta)*Omega2);
299
300 V = (Matrix3<g_type>::Identity()
301 + (1-cos(theta))/(theta*theta)*Omega
302 + (theta-sin(theta))/(pow(theta,3))*Omega2);
303 }
304 return SE3Quat(Quaternion<g_type>(R),V*upsilon);
305 }
306
309 Eigen::Matrix<g_type, 6, 6> adj() const
310 {
311 Matrix3<g_type> R = _r.toRotationMatrix();
312 Eigen::Matrix<g_type, 6, 6> res;
313 res.block(0,0,3,3) = R;
314 res.block(3,3,3,3) = R;
315 res.block(3,0,3,3) = skew(m_t)*R;
316 res.block(0,3,3,3) = Matrix3<g_type>::Zero(3,3);
317 return res;
318 }
319
322 Eigen::Matrix<g_type,4,4> to_homogeneous_matrix() const
323 {
324 Eigen::Matrix<g_type,4,4> homogeneous_matrix;
325 homogeneous_matrix.setIdentity();
326 homogeneous_matrix.block(0,0,3,3) = _r.toRotationMatrix();
327 homogeneous_matrix.col(3).head(3) = translation();
328
329 return homogeneous_matrix;
330 }
331
334 if (_r.w()<0){
335 _r.coeffs() *= -1;
336 }
337 _r.normalize();
338 }
339
343 operator Eigen::Transform<g_type, 3, 1>() const
344 {
345 Eigen::Transform<g_type, 3, 1> result = (Eigen::Transform<g_type, 3, 1>)rotation();
346 result.translation() = translation();
347 return result;
348 }
349 public:
350 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
351 };
352
353 inline std::ostream& operator <<(std::ostream& out_str, const SE3Quat& se3)
354 {
355 out_str << se3.to_homogeneous_matrix() << std::endl;
356 return out_str;
357 }
358
359} // end namespace
360
361#endif
https://www.3dgep.com/understanding-quaternions/
SE(3) rigid body transformation represented by a unit quaternion and translation vector.
Definition se3quat.h:42
SE3Quat inverse() const
Computes the inverse of this SE3 transform.
Definition se3quat.h:145
const Quaternion< g_type > & rotation() const
Returns a const reference to the rotation quaternion.
Definition se3quat.h:116
SE3Quat(const Quaternion< g_type > &q, const Vector3< g_type > &t)
Constructs from a quaternion and translation vector.
Definition se3quat.h:73
Eigen::Matrix< g_type, 4, 4 > to_homogeneous_matrix() const
Converts to a 4x4 homogeneous transformation matrix.
Definition se3quat.h:322
Vector3< g_type > m_t
Translation component.
Definition se3quat.h:50
void normalizeRotation()
Normalizes the rotation quaternion, ensuring positive w.
Definition se3quat.h:333
g_type operator[](int i) const
Const element access: 0-2 = translation, 3-6 = quaternion coeffs.
Definition se3quat.h:153
Quaternion< g_type > _r
Rotation component as a unit quaternion.
Definition se3quat.h:49
Vector7d toVector() const
Converts to a 7D vector [t, qx, qy, qz, qw].
Definition se3quat.h:162
Vector6d log() const
Computes the logarithmic map (SE3 -> 6D tangent vector).
Definition se3quat.h:209
const Vector3< g_type > & translation() const
Returns a const reference to the translation vector.
Definition se3quat.h:111
SE3Quat(const Matrix3< g_type > &R, const Vector3< g_type > &t)
Constructs from a rotation matrix and translation vector.
Definition se3quat.h:63
Vector6d toMinimalVector() const
Converts to a minimal 6D vector [t, qx, qy, qz].
Definition se3quat.h:182
void setTranslation(const Vector3< g_type > &t_)
Sets the translation vector.
Definition se3quat.h:114
SE3Quat operator*(const SE3Quat &tr2) const
Composes two SE3 transforms: result = (*this) * tr2.
Definition se3quat.h:122
SE3Quat()
Default constructor.
Definition se3quat.h:55
SE3Quat(const MatrixBase< Derived > &v)
templaized constructor which allows v to be an arbitrary Eigen Vector type, e.g., Vector6d or Map<Vec...
Definition se3quat.h:84
static SE3Quat exp(const Vector6d &update)
Computes the exponential map from a 6D tangent vector to SE3.
Definition se3quat.h:272
Vector3< g_type > map(const Vector3< g_type > &xyz) const
Transforms a 3D point: R*xyz + t.
Definition se3quat.h:263
void fromMinimalVector(const Vector6d &v)
Initializes from a minimal 6D vector [t, qx, qy, qz], recovering qw.
Definition se3quat.h:195
SE3Quat & operator*=(const SE3Quat &tr2)
In-place composition with another SE3Quat.
Definition se3quat.h:131
void setRotation(const Quaternion< g_type > &r_)
Sets the rotation quaternion.
Definition se3quat.h:119
Eigen::Matrix< g_type, 6, 6 > adj() const
Computes the 6x6 adjoint matrix of this SE3 transform.
Definition se3quat.h:309
void fromVector(const Vector7d &v)
Initializes from a 7D vector [t, qw, qx, qy, qz].
Definition se3quat.h:176
The primary namespace for the NDEVR SDK.
Eigen::Matrix< g_type, 7, 1 > Vector7d
7D vector for quaternion + translation representation.
Definition se3quat.h:39
Vector3< g_type > deltaR(const Matrix3< g_type > &R)
Extracts the rotation vector from a rotation matrix using the Rodrigues formula.
Definition se3_ops.hpp:41
static constexpr t_float_type PI()
Returns the value of PI to a given precision.
Definition Angle.h:68
Matrix3< g_type > skew(const Vector3< g_type > &v)
Computes the 3x3 skew-symmetric matrix from a 3D vector.
Definition se3_ops.hpp:28
t_type sqrt(const t_type &value)
std::enable_if<!ObjectInfo< t_type >::Float, fltp08 >::type sin(const Angle< t_type > &angle)
Performs optimized sine operation on the given angle using pre-computed lookup table for optimal spee...
std::enable_if<!ObjectInfo< t_type >::Float, fltp08 >::type tan(const Angle< t_type > &angle)
Performs optimized tangent operation on the given angle using pre-computed lookup table for optimal s...
Eigen::Matrix< g_type, 6, 1 > Vector6d
6D vector for the se(3) tangent space.
Definition se3quat.h:38
std::enable_if<!ObjectInfo< t_type >::Float, fltp08 >::type cos(const Angle< t_type > &angle)
Performs optimized cosine operation on the given angle using pre-computed lookup table for optimal sp...