manif-geom-cpp
Loading...
Searching...
No Matches
SO3.h
Go to the documentation of this file.
1#pragma once
2
3#include <Eigen/Core>
4#include <Eigen/Geometry>
5#include <iostream>
6#include <math.h>
7
8using namespace Eigen;
9
13template<typename T>
14class SO3
15{
16private:
17 typedef Matrix<T, 3, 1> Vec3T;
18 typedef Matrix<T, 4, 1> Vec4T;
19 typedef Matrix<T, 3, 3> Mat3T;
20 typedef Matrix<T, 4, 4> Mat4T;
21
22 T buf_[4];
23
24public:
30
37 static SO3 random()
38 {
39 SO3 q;
40 q.arr_.setRandom();
41 q.normalize();
42 return q;
43 }
44
48 static SO3 identity()
49 {
50 SO3 q;
51 q.arr_ << 1., 0., 0., 0.;
52 return q;
53 }
54
58 static SO3 nans()
59 {
60 SO3 x;
61 x.arr_.setConstant(std::numeric_limits<T>::quiet_NaN());
62 return x;
63 }
64
68 static SO3 fromAxisAngle(const Vec3T& axis, const T angle)
69 {
70 T th2 = angle / 2.0;
71 Vec3T xyz = sin(th2) * axis / axis.norm();
72 SO3 q;
73 q.arr_ << cos(th2), xyz(0), xyz(1), xyz(2);
74 q.normalize();
75 return q;
76 }
77
81 static SO3 fromEuler(const T roll, const T pitch, const T yaw)
82 {
83 SO3 q_roll = SO3::fromAxisAngle((Vec3T() << (T)1., (T)0., (T)0.).finished(), roll);
84 SO3 q_pitch = SO3::fromAxisAngle((Vec3T() << (T)0., (T)1., (T)0.).finished(), pitch);
85 SO3 q_yaw = SO3::fromAxisAngle((Vec3T() << (T)0., (T)0., (T)1.).finished(), yaw);
88 return q_euler;
89 }
90
94 static SO3 fromR(const Mat3T& m)
95 {
96 T s, qw, qx, qy, qz;
97
98 T R11 = m(0, 0);
99 T R12 = m(0, 1);
100 T R13 = m(0, 2);
101 T R21 = m(1, 0);
102 T R22 = m(1, 1);
103 T R23 = m(1, 2);
104 T R31 = m(2, 0);
105 T R32 = m(2, 1);
106 T R33 = m(2, 2);
107
108 if (R11 + R22 + R33 > (T)0.0)
109 {
110 s = 2. * sqrt(1. + R11 + R22 + R33);
111 qw = 0.25 * s;
112 qx = (R32 - R23) / s;
113 qy = (R13 - R31) / s;
114 qz = (R21 - R12) / s;
115 }
116 else if (R11 > R22 && R11 > R33)
117 {
118 s = 2. * sqrt(1. + R11 - R22 - R33);
119 qw = (R32 - R23) / s;
120 qx = 0.25 * s;
121 qy = (R21 + R12) / s;
122 qz = (R31 + R13) / s;
123 }
124 else if (R22 > R33)
125 {
126 s = 2. * sqrt(1. + R22 - R11 - R33);
127 qw = (R13 - R31) / s;
128 qx = (R21 + R12) / s;
129 qy = 0.25 * s;
130 qz = (R32 + R23) / s;
131 }
132 else
133 {
134 s = 2. * sqrt(1. + R33 - R11 - R22);
135 qw = (R21 - R12) / s;
136 qx = (R31 + R13) / s;
137 qy = (R32 + R23) / s;
138 qz = 0.25 * s;
139 }
140
141 SO3 q = SO3::fromQuat(qw, qx, qy, qz);
142 q.normalize();
143
144 return q;
145 }
146
153 static SO3 fromTwoUnitVectors(const Vec3T& u, const Vec3T& v)
154 {
155 SO3 q;
156 T d = u.dot(v);
157
158 if (d < (T)0.99999999 && d > (T)-0.99999999)
159 {
160 T invs = 1. / sqrt((2. * (1. + d)));
161 Vec3T xyz = u.cross(v * invs);
162 q = SO3::fromQuat(0.5 / invs, xyz(0), xyz(1), xyz(2));
163 q.normalize();
164 }
165 else if (d < (T)-0.99999999)
166 {
167 // There are an infinite number of solutions here, choose one.
168 // This choice works better for vector comparisons with only
169 // nonzero x components.
170 q = SO3::fromQuat((T)0., (T)0., (T)1., (T)0.);
171 }
172 else
173 {
174 q = SO3::identity();
175 }
176
177 return q;
178 }
179
187 static SO3 fromQuat(const T qw, const T qx, const T qy, const T qz)
188 {
189 SO3 q;
190 q.arr_ << qw, qx, qy, qz;
191 return q;
192 }
193
198 static SO3 fromQuat(const Vec4T& qvec)
199 {
200 SO3 q;
201 q.arr_ << qvec(0), qvec(1), qvec(2), qvec(3);
202 return q;
203 }
204
210 {
211 SO3 q;
212 q.arr_ << quat.w(), quat.x(), quat.y(), quat.z();
213 return q;
214 }
215
219 SO3() : arr_(buf_) {}
220
224 SO3(const Ref<const Vec4T>& arr) : arr_(buf_)
225 {
226 arr_ = arr;
227 }
228
232 SO3(const SO3& q) : arr_(buf_)
233 {
234 arr_ = q.arr_;
235 }
236
241 SO3(const T* data) : arr_(const_cast<T*>(data)) {}
242
246 inline T& operator[](int i)
247 {
248 return arr_[i];
249 }
250
254 inline const T& w() const
255 {
256 return arr_(0);
257 }
258
262 inline const T& x() const
263 {
264 return arr_(1);
265 }
266
270 inline const T& y() const
271 {
272 return arr_(2);
273 }
274
278 inline const T& z() const
279 {
280 return arr_(3);
281 }
282
286 inline T& w()
287 {
288 return arr_(0);
289 }
290
294 inline T& x()
295 {
296 return arr_(1);
297 }
298
302 inline T& y()
303 {
304 return arr_(2);
305 }
306
310 inline T& z()
311 {
312 return arr_(3);
313 }
314
318 inline const Vec4T elements() const
319 {
320 return arr_;
321 }
322
326 inline Vec4T array() const
327 {
328 return arr_;
329 }
330
334 inline T* data()
335 {
336 return arr_.data();
337 }
338
342 inline const T* data() const
343 {
344 return arr_.data();
345 }
346
350 SO3 copy() const
351 {
352 SO3 tmp;
353 tmp.arr_ = arr_;
354 return tmp;
355 }
356
361 {
362 arr_ /= arr_.norm();
363 if (arr_(0) < (T)0.0)
364 arr_ *= (T)-1.0;
365 }
366
371 {
372 SO3 tmp = copy();
373 tmp.normalize();
374 return tmp;
375 }
376
380 Mat3T R() const
381 {
382 T wx = w() * x();
383 T wy = w() * y();
384 T wz = w() * z();
385 T xx = x() * x();
386 T xy = x() * y();
387 T xz = x() * z();
388 T yy = y() * y();
389 T yz = y() * z();
390 T zz = z() * z();
391 Mat3T out;
392 out << 1. - 2. * yy - 2. * zz, 2. * xy - 2. * wz, 2. * xz + 2. * wy, 2. * xy + 2. * wz, 1. - 2. * xx - 2. * zz,
393 2. * yz - 2. * wx, 2. * xz - 2. * wy, 2. * yz + 2. * wx, 1. - 2. * xx - 2. * yy;
394 return out;
395 }
396
400 SO3 inverse() const
401 {
402 SO3 q;
403 q.arr_(0) = arr_(0);
404 q.arr_(1) = -arr_(1);
405 q.arr_(2) = -arr_(2);
406 q.arr_(3) = -arr_(3);
407 return q;
408 }
409
414 {
415 arr_.template block<3, 1>(1, 0) *= (T)-1.0;
416 return *this;
417 }
418
422 T roll() const
423 {
424 return atan2(T(2.0) * (w() * x() + y() * z()), T(1.0) - T(2.0) * (x() * x() + y() * y()));
425 }
426
430 T pitch() const
431 {
432 const T val = T(2.0) * (w() * y() - x() * z());
433
434 // hold at 90 degrees if invalid
435 if (fabs(val) > T(1.0))
436 return copysign(T(1.0), val) * T(M_PI) / T(2.0);
437 else
438 return asin(val);
439 }
440
444 T yaw() const
445 {
446 return atan2(T(2.0) * (w() * z() + x() * y()), T(1.0) - T(2.0) * (y() * y() + z() * z()));
447 }
448
452 Vec3T toEuler() const
453 {
454 Vec3T out;
455 out << roll(), pitch(), yaw();
456 return out;
457 }
458
464 Mat4T qMatLeft() const
465 {
466 Mat4T qL;
467 qL << w(), -x(), -y(), -z(), x(), w(), -z(), y(), y(), z(), w(), -x(), z(), -y(), x(), w();
468 return qL;
469 }
470
475 template<typename Tout = T, typename T2>
476 SO3<Tout> otimes(const SO3<T2>& q) const
477 {
479 qout.arr_ << w() * q.w() - x() * q.x() - y() * q.y() - z() * q.z(),
480 w() * q.x() + x() * q.w() + y() * q.z() - z() * q.y(),
481 w() * q.y() - x() * q.z() + y() * q.w() + z() * q.x(),
482 w() * q.z() + x() * q.y() - y() * q.x() + z() * q.w();
483 return qout;
484 }
485
490 template<typename Tout = T, typename T2>
492 {
494 }
495
500 template<typename Tout = T, typename T2>
502 {
503 SO3<Tout> dq = q.inverse().template otimes<Tout>(*this);
504 if (dq.w() < 0.0)
505 {
506 dq.arr_ *= (Tout)-1.0;
507 }
508 return SO3<Tout>::Log(dq);
509 }
510
514 SO3& operator=(const SO3& q)
515 {
516 arr_ = q.elements();
517 return *this;
518 }
519
523 template<typename T2>
524 SO3 operator*(const SO3<T2>& q) const
525 {
526 return otimes(q);
527 }
528
532 template<typename T2>
534 {
535 arr_ = otimes(q).elements();
536 return *this;
537 }
538
545 SO3& operator*=(const double& s)
546 {
547 arr_ = SO3::Exp(s * SO3::Log(*this)).elements();
548 return *this;
549 }
550
557 SO3& operator/=(const double& s)
558 {
559 arr_ = SO3::Exp(SO3::Log(*this) / s).elements();
560 return *this;
561 }
562
569 SO3 operator/(const double& s) const
570 {
571 SO3 qs;
572 qs.arr_ = SO3::Exp(SO3::Log(*this) / s).elements();
573 return qs;
574 }
575
580 template<typename Tout = T, typename T2>
582 {
583 Vec3T qv = arr_.template block<3, 1>(1, 0);
584 Matrix<Tout, 3, 1> t = (Tout)2.0 * v.cross(qv);
585 return v - w() * t + t.cross(qv);
586 }
587
592 Vec3T operator*(const Vec3T& v) const
593 {
594 Vec3T qv = arr_.template block<3, 1>(1, 0);
595 Vec3T t = (T)2.0 * v.cross(qv);
596 return v - w() * t + t.cross(qv);
597 }
598
602 SO3 operator+(const Vec3T& v) const
603 {
604 return oplus(v);
605 }
606
610 SO3& operator+=(const Vec3T& v)
611 {
612 arr_ = oplus(v).elements();
613 return *this;
614 }
615
619 template<typename T2>
620 Vec3T operator-(const SO3<T2>& q) const
621 {
622 return ominus(q);
623 }
624
629 static Mat3T hat(const Vec3T& omega)
630 {
631 Mat3T Omega;
632 Omega << (T)0., -omega.z(), omega.y(), omega.z(), (T)0., -omega.x(), -omega.y(), omega.x(), (T)0.;
633 return Omega;
634 }
635
640 static Vec3T vee(const Mat3T& Omega)
641 {
642 Vec3T omega;
643 omega << Omega(2, 1), Omega(0, 2), Omega(1, 0);
644 return omega;
645 }
646
650 static Mat3T log(const SO3& q)
651 {
652 return hat(SO3::Log(q));
653 }
654
658 static Vec3T Log(const SO3& q)
659 {
660 Vec3T qv = q.elements().template block<3, 1>(1, 0);
661 T qw = q.w();
662
663 T n = qv.norm();
664 if (n > (T)1e-4)
665 return 2.0 * qv * atan2(n, qw) / n;
666 else
667 return qv;
668 }
669
673 static SO3 exp(const Mat3T& Omega)
674 {
675 return SO3::Exp(vee(Omega));
676 }
677
681 static SO3 Exp(const Vec3T& omega)
682 {
683 T th = omega.norm();
684
685 SO3 q;
686 if (th > (T)1e-4)
687 {
688 Vec3T u = omega / th;
689 q.arr_(0) = cos(th / 2.0);
690 q.arr_.template block<3, 1>(1, 0) = sin(th / 2.0) * u;
691 }
692 else
693 {
694 q.arr_(0) = (T)1.0;
695 q.arr_.template block<3, 1>(1, 0) = omega / 2.0;
696 q.normalize();
697 }
698
699 return q;
700 }
701
705 template<typename T2>
706 SO3<T2> cast() const
707 {
708 SO3<T2> q;
709 q.arr_ = arr_.template cast<T2>();
710 return q;
711 }
712};
713
720template<typename T>
721SO3<T> operator*(const double& l, const SO3<T>& r)
722{
723 SO3<T> lr;
724 lr.arr_ = SO3<T>::Exp(l * SO3<T>::Log(r)).elements();
725 return lr;
726}
727
734template<typename T>
735SO3<T> operator*(const SO3<T>& l, const double& r)
736{
737 SO3<T> lr;
738 lr.arr_ = SO3<T>::Exp(r * SO3<T>::Log(l)).elements();
739 return lr;
740}
741
745template<typename T>
746inline std::ostream& operator<<(std::ostream& os, const SO3<T>& q)
747{
748 os << "SO(3): [ " << q.w() << ", " << q.x() << "i, " << q.y() << "j, " << q.z() << "k ]";
749 return os;
750}
751
SO3< T > operator*(const double &l, const SO3< T > &r)
Scale a rotation by a scalar.
Definition SO3.h:721
std::ostream & operator<<(std::ostream &os, const SO3< T > &q)
Render the rotation in a stream.
Definition SO3.h:746
SO3< double > SO3d
Definition SO3.h:752
Class representing a member of the manifold, or a 3D rotation.
Definition SO3.h:15
static SO3 Exp(const Vec3T &omega)
Exponential chart map implementation: .
Definition SO3.h:681
static Vec3T vee(const Mat3T &Omega)
Vee operator implementation, which coverts the Lie algebra representation to a tangent-space vector r...
Definition SO3.h:640
T pitch() const
Obtain the pitch component of the yaw-pitch-roll successive-axes Euler angle representation.
Definition SO3.h:430
EIGEN_MAKE_ALIGNED_OPERATOR_NEW Map< Vec4T > arr_
Memory-mapped array representing all rotation fields in .
Definition SO3.h:29
static SO3 nans()
Obtain a rotation full of NaNs.
Definition SO3.h:58
static Mat3T hat(const Vec3T &omega)
Hat operator implementation, which coverts the tangent-space vector representation to the correspondi...
Definition SO3.h:629
T & z()
Access the third imaginary element of the rotation.
Definition SO3.h:310
static SO3 fromQuat(const T qw, const T qx, const T qy, const T qz)
Construct a rotation from the individual fields.
Definition SO3.h:187
static SO3 fromR(const Mat3T &m)
Convert a rotation matrix to a rotation.
Definition SO3.h:94
SO3()
Create a rotation (with garbage data).
Definition SO3.h:219
Matrix< Tout, 3, 1 > operator*(const Matrix< T2, 3, 1 > &v) const
Transform a vector via multiplication: .
Definition SO3.h:581
const Vec4T elements() const
Access all elements of .
Definition SO3.h:318
SO3 & operator+=(const Vec3T &v)
Invocation of oplus via addition.
Definition SO3.h:610
T & operator[](int i)
Access a field from .
Definition SO3.h:246
SO3 & operator/=(const double &s)
Scale a rotation by a scalar.
Definition SO3.h:557
const T & w() const
Access the real element of the rotation.
Definition SO3.h:254
T yaw() const
Obtain the yaw component of the yaw-pitch-roll successive-axes Euler angle representation.
Definition SO3.h:444
SO3 operator/(const double &s) const
Scale a rotation by a scalar.
Definition SO3.h:569
Vec4T array() const
Access all elements of .
Definition SO3.h:326
T roll() const
Obtain the roll component of the yaw-pitch-roll successive-axes Euler angle representation.
Definition SO3.h:422
Vec3T toEuler() const
Obtain the Euler angle representation as a 3-vector.
Definition SO3.h:452
static SO3 random()
Obtain a random rotation.
Definition SO3.h:37
static SO3 exp(const Mat3T &Omega)
Exponential chart map implementation: .
Definition SO3.h:673
const T & y() const
Access the second imaginary element of the rotation.
Definition SO3.h:270
static SO3 identity()
Obtain an identity rotation.
Definition SO3.h:48
T & y()
Access the second imaginary element of the rotation.
Definition SO3.h:302
Mat3T R() const
Convert the rotation to matrix representation .
Definition SO3.h:380
void normalize()
Normalize the elements of to make it a valid rotation.
Definition SO3.h:360
SO3(const Ref< const Vec4T > &arr)
Create a transform from an array representing all rotation fields in .
Definition SO3.h:224
SO3 & operator*=(const SO3< T2 > &q)
Invocation of otimes via multiplication.
Definition SO3.h:533
SO3< T2 > cast() const
Cast the underlying numeric type.
Definition SO3.h:706
static Mat3T log(const SO3 &q)
Logarithmic chart map implementation: .
Definition SO3.h:650
SO3 & operator*=(const double &s)
Scale a rotation by a scalar.
Definition SO3.h:545
SO3 normalized()
Obtain a normalized copy of the current rotation.
Definition SO3.h:370
SO3 & operator=(const SO3 &q)
Copy constructor.
Definition SO3.h:514
SO3< Tout > otimes(const SO3< T2 > &q) const
Implementation of group composition: .
Definition SO3.h:476
SO3 operator*(const SO3< T2 > &q) const
Invocation of otimes via multiplication.
Definition SO3.h:524
const T & x() const
Access the first imaginary element of the rotation.
Definition SO3.h:262
SO3(const T *data)
Create a rotation from a pointer array representing all rotation fields in .
Definition SO3.h:241
static SO3 fromQuat(const Quaternion< T > quat)
Construct a rotation from an Eigen quaternion.
Definition SO3.h:209
T * data()
Access pointer to all elements of .
Definition SO3.h:334
Matrix< Tout, 3, 1 > ominus(const SO3< T2 > &q) const
Implementation of group subtraction: .
Definition SO3.h:501
static SO3 fromTwoUnitVectors(const Vec3T &u, const Vec3T &v)
Given two unit vectors , returns the rotation that rotates .
Definition SO3.h:153
T & x()
Access the first imaginary element of the rotation.
Definition SO3.h:294
SO3< Tout > oplus(const Matrix< T2, 3, 1 > &delta) const
Implementation of tangent space group perturbations: .
Definition SO3.h:491
static SO3 fromAxisAngle(const Vec3T &axis, const T angle)
Convert an angle (in radians) with accompanying axis (defined by a vector) into a rotation.
Definition SO3.h:68
SO3 inverse() const
Obtain the inverse rotation .
Definition SO3.h:400
T & w()
Access the real element of the rotation.
Definition SO3.h:286
static SO3 fromEuler(const T roll, const T pitch, const T yaw)
Construct a rotation from yaw-pitch-roll successive-axes Euler angles.
Definition SO3.h:81
Mat4T qMatLeft() const
Obtain an equivalent 4-by-4 matrix representation of such that .
Definition SO3.h:464
SO3 & invert()
Invert the current rotation .
Definition SO3.h:413
const T * data() const
Access pointer to all elements of .
Definition SO3.h:342
SO3 operator+(const Vec3T &v) const
Invocation of oplus via addition.
Definition SO3.h:602
Vec3T operator-(const SO3< T2 > &q) const
Invocation of ominus via subtraction.
Definition SO3.h:620
SO3(const SO3 &q)
Copy constructor from another rotation.
Definition SO3.h:232
SO3 copy() const
Get a deep copy of the current rotation.
Definition SO3.h:350
const T & z() const
Access the third imaginary element of the rotation.
Definition SO3.h:278
static SO3 fromQuat(const Vec4T &qvec)
Construct a rotation from a rotation fields vector.
Definition SO3.h:198
static Vec3T Log(const SO3 &q)
Logarithmic chart map implementation: .
Definition SO3.h:658
Vec3T operator*(const Vec3T &v) const
Transform a vector via multiplication: .
Definition SO3.h:592