// This file is part of Sophus. // // Copyright 2011-2013 Hauke Strasdat // 2012-2013 Steven Lovegrove // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. #ifndef SOPHUS_SE3_HPP #define SOPHUS_SE3_HPP #include "so3.hpp" //////////////////////////////////////////////////////////////////////////// // Forward Declarations / typedefs //////////////////////////////////////////////////////////////////////////// namespace Sophus { template class SE3Group; typedef SE3Group SE3 EIGEN_DEPRECATED; typedef SE3Group SE3d; /**< double precision SE3 */ typedef SE3Group SE3f; /**< single precision SE3 */ typedef Matrix Vector6d; typedef Matrix Matrix6d; typedef Matrix Vector6f; typedef Matrix Matrix6f; } //////////////////////////////////////////////////////////////////////////// // Eigen Traits (For querying derived types in CRTP hierarchy) //////////////////////////////////////////////////////////////////////////// namespace Eigen { namespace internal { template struct traits > { typedef _Scalar Scalar; typedef Matrix TranslationType; typedef Sophus::SO3Group SO3Type; }; template struct traits, _Options> > : traits > { typedef _Scalar Scalar; typedef Map,_Options> TranslationType; typedef Map,_Options> SO3Type; }; template struct traits, _Options> > : traits > { typedef _Scalar Scalar; typedef Map,_Options> TranslationType; typedef Map,_Options> SO3Type; }; } } namespace Sophus { using namespace Eigen; using namespace std; /** * \brief SE3 base type - implements SE3 class but is storage agnostic * * [add more detailed description/tutorial] */ template class SE3GroupBase { public: /** \brief scalar type */ typedef typename internal::traits::Scalar Scalar; /** \brief translation reference type */ typedef typename internal::traits::TranslationType & TranslationReference; /** \brief translation const reference type */ typedef const typename internal::traits::TranslationType & ConstTranslationReference; /** \brief SO3 reference type */ typedef typename internal::traits::SO3Type & SO3Reference; /** \brief SO3 const reference type */ typedef const typename internal::traits::SO3Type & ConstSO3Reference; /** \brief degree of freedom of group * (three for translation, three for rotation) */ static const int DoF = 6; /** \brief number of internal parameters used * (unit quaternion for rotation + translation 3-vector) */ static const int num_parameters = 7; /** \brief group transformations are NxN matrices */ static const int N = 4; /** \brief group transfomation type */ typedef Matrix Transformation; /** \brief point type */ typedef Matrix Point; /** \brief tangent vector type */ typedef Matrix Tangent; /** \brief adjoint transformation type */ typedef Matrix Adjoint; /** * \brief Adjoint transformation * * This function return the adjoint transformation \f$ Ad \f$ of the * group instance \f$ A \f$ such that for all \f$ x \f$ * it holds that \f$ \widehat{Ad_A\cdot x} = A\widehat{x}A^{-1} \f$ * with \f$\ \widehat{\cdot} \f$ being the hat()-operator. */ inline const Adjoint Adj() const { const Matrix & R = so3().matrix(); Adjoint res; res.block(0,0,3,3) = R; res.block(3,3,3,3) = R; res.block(0,3,3,3) = SO3Group::hat(translation())*R; res.block(3,0,3,3) = Matrix::Zero(3,3); return res; } /** * \returns copy of instance casted to NewScalarType */ template inline SE3Group cast() const { return SE3Group(so3().template cast(), translation().template cast() ); } /** * \brief Fast group multiplication * * This method is a fast version of operator*=(), since it does not perform * normalization. It is up to the user to call normalize() once in a while. * * \see operator*=() */ inline void fastMultiply(const SE3Group& other) { translation() += so3()*(other.translation()); so3().fastMultiply(other.so3()); } /** * \returns Group inverse of instance */ inline const SE3Group inverse() const { const SO3Group invR = so3().inverse(); return SE3Group(invR, invR*(translation() *static_cast(-1) ) ); } /** * \brief Logarithmic map * * \returns tangent space representation * (translational part and rotation vector) of instance * * \see log(). */ inline const Tangent log() const { return log(*this); } /** * \brief Normalize SO3 element * * It re-normalizes the SO3 element. This method only needs to * be called in conjunction with fastMultiply() or data() write access. */ inline void normalize() { so3().normalize(); } /** * \returns 4x4 matrix representation of instance */ inline const Transformation matrix() const { Transformation homogenious_matrix; homogenious_matrix.setIdentity(); homogenious_matrix.block(0,0,3,3) = rotationMatrix(); homogenious_matrix.col(3).head(3) = translation(); return homogenious_matrix; } /** * \returns 3x4 matrix representation of instance * * It returns the three first row of matrix(). */ inline const Matrix matrix3x4() const { Matrix matrix; matrix.block(0,0,3,3) = rotationMatrix(); matrix.col(3) = translation(); return matrix; } /** * \brief Assignment operator */ template inline SE3GroupBase& operator= (const SE3GroupBase & other) { so3() = other.so3(); translation() = other.translation(); return *this; } /** * \brief Group multiplication * \see operator*=() */ inline const SE3Group operator*(const SE3Group& other) const { SE3Group result(*this); result *= other; return result; } /** * \brief Group action on \f$ \mathbf{R}^3 \f$ * * \param p point \f$p \in \mathbf{R}^3 \f$ * \returns point \f$p' \in \mathbf{R}^3 \f$, * rotated and translated version of \f$p\f$ * * This function rotates and translates point \f$ p \f$ * in \f$ \mathbf{R}^3 \f$ by the SE3 transformation \f$R,t\f$ * (=rotation matrix, translation vector): \f$ p' = R\cdot p + t \f$. */ inline const Point operator*(const Point & p) const { return so3()*p + translation(); } /** * \brief In-place group multiplication * * \see fastMultiply() * \see operator*() */ inline void operator*=(const SE3Group& other) { fastMultiply(other); normalize(); } /** * \returns Rotation matrix * * deprecated: use rotationMatrix() instead. */ typedef Transformation M3_marcos_dont_like_commas; inline EIGEN_DEPRECATED const M3_marcos_dont_like_commas rotation_matrix() const { return so3().matrix(); } /** * \returns Rotation matrix */ inline const Matrix rotationMatrix() const { return so3().matrix(); } /** * \brief Mutator of SO3 group */ EIGEN_STRONG_INLINE SO3Reference so3() { return static_cast(this)->so3(); } /** * \brief Accessor of SO3 group */ EIGEN_STRONG_INLINE ConstSO3Reference so3() const { return static_cast(this)->so3(); } /** * \brief Setter of internal unit quaternion representation * * \param quaternion * \pre the quaternion must not be zero * * The quaternion is normalized to unit length. */ inline void setQuaternion(const Quaternion & quat) { return so3().setQuaternion(quat); } /** * \brief Setter of unit quaternion using rotation matrix * * \param rotation_matrix a 3x3 rotation matrix * \pre the 3x3 matrix should be orthogonal and have a determinant of 1 */ inline void setRotationMatrix (const Matrix & rotation_matrix) { so3().setQuaternion(Quaternion(rotation_matrix)); } /** * \brief Mutator of translation vector */ EIGEN_STRONG_INLINE TranslationReference translation() { return static_cast(this)->translation(); } /** * \brief Accessor of translation vector */ EIGEN_STRONG_INLINE ConstTranslationReference translation() const { return static_cast(this)->translation(); } /** * \brief Accessor of unit quaternion * * No direct write access is given to ensure the quaternion stays normalized. */ inline typename internal::traits::SO3Type::ConstQuaternionReference unit_quaternion() const { return so3().unit_quaternion(); } //////////////////////////////////////////////////////////////////////////// // public static functions //////////////////////////////////////////////////////////////////////////// /** * \param b 6-vector representation of Lie algebra element * \returns derivative of Lie bracket * * This function returns \f$ \frac{\partial}{\partial a} [a, b]_{se3} \f$ * with \f$ [a, b]_{se3} \f$ being the lieBracket() of the Lie algebra se3. * * \see lieBracket() */ inline static const Adjoint d_lieBracketab_by_d_a(const Tangent & b) { Adjoint res; res.setZero(); const Matrix & upsilon2 = b.template head<3>(); const Matrix & omega2 = b.template tail<3>(); res.template topLeftCorner<3,3>() = -SO3Group::hat(omega2); res.template topRightCorner<3,3>() = -SO3Group::hat(upsilon2); res.template bottomRightCorner<3,3>() = -SO3Group::hat(omega2); return res; } /** * \brief Group exponential * * \param a tangent space element (6-vector) * \returns corresponding element of the group SE3 * * The first three components of \f$ a \f$ represent the translational * part \f$ \upsilon \f$ in the tangent space of SE3, while the last three * components of \f$ a \f$ represents the rotation vector \f$ \omega \f$. * * To be more specific, this function computes \f$ \exp(\widehat{a}) \f$ * with \f$ \exp(\cdot) \f$ being the matrix exponential * and \f$ \widehat{\cdot} \f$ the hat()-operator of SE3. * * \see hat() * \see log() */ inline static const SE3Group exp(const Tangent & a) { const Matrix & omega = a.template tail<3>(); Scalar theta; const SO3Group & so3 = SO3Group::expAndTheta(omega, &theta); const Matrix & Omega = SO3Group::hat(omega); const Matrix & Omega_sq = Omega*Omega; Matrix V; if(theta::epsilon()) { V = so3.matrix(); //Note: That is an accurate expansion! } else { Scalar theta_sq = theta*theta; V = (Matrix::Identity() + (static_cast(1)-std::cos(theta))/(theta_sq)*Omega + (theta-std::sin(theta))/(theta_sq*theta)*Omega_sq); } return SE3Group(so3,V*a.template head<3>()); } /** * \brief Generators * * \pre \f$ i \in \{0,1,2,3,4,5\} \f$ * \returns \f$ i \f$th generator \f$ G_i \f$ of SE3 * * The infinitesimal generators of SE3 are: \f[ * G_0 = \left( \begin{array}{cccc} * 0& 0& 0& 1\\ * 0& 0& 0& 0\\ * 0& 0& 0& 0\\ * 0& 0& 0& 0\\ * \end{array} \right), * G_1 = \left( \begin{array}{cccc} * 0& 0& 0& 0\\ * 0& 0& 0& 1\\ * 0& 0& 0& 0\\ * 0& 0& 0& 0\\ * \end{array} \right), * G_2 = \left( \begin{array}{cccc} * 0& 0& 0& 0\\ * 0& 0& 0& 0\\ * 0& 0& 0& 1\\ * 0& 0& 0& 0\\ * \end{array} \right). * G_3 = \left( \begin{array}{cccc} * 0& 0& 0& 0\\ * 0& 0& -1& 0\\ * 0& 1& 0& 0\\ * 0& 0& 0& 0\\ * \end{array} \right), * G_4 = \left( \begin{array}{cccc} * 0& 0& 1& 0\\ * 0& 0& 0& 0\\ * -1& 0& 0& 0\\ * 0& 0& 0& 0\\ * \end{array} \right), * G_5 = \left( \begin{array}{cccc} * 0& -1& 0& 0\\ * 1& 0& 0& 0\\ * 0& 0& 0& 0\\ * 0& 0& 0& 0\\ * \end{array} \right). * \f] * \see hat() */ inline static const Transformation generator(int i) { if (i<0 || i>5) { throw SophusException("i is not in range [0,5]."); } Tangent e; e.setZero(); e[i] = static_cast(1); return hat(e); } /** * \brief hat-operator * * \param omega 6-vector representation of Lie algebra element * \returns 4x4-matrix representatin of Lie algebra element * * Formally, the hat-operator of SE3 is defined * as \f$ \widehat{\cdot}: \mathbf{R}^6 \rightarrow \mathbf{R}^{4\times 4}, * \quad \widehat{\omega} = \sum_{i=0}^5 G_i \omega_i \f$ * with \f$ G_i \f$ being the ith infinitesial generator(). * * \see generator() * \see vee() */ inline static const Transformation hat(const Tangent & v) { Transformation Omega; Omega.setZero(); Omega.template topLeftCorner<3,3>() = SO3Group::hat(v.template tail<3>()); Omega.col(3).template head<3>() = v.template head<3>(); return Omega; } /** * \brief Lie bracket * * \param a 6-vector representation of Lie algebra element * \param b 6-vector representation of Lie algebra element * \returns 6-vector representation of Lie algebra element * * It computes the bracket of SE3. To be more specific, it * computes \f$ [a, b]_{se3} * := [\widehat{a}, \widehat{b}]^\vee \f$ * with \f$ [A,B] = AB-BA \f$ being the matrix * commutator, \f$ \widehat{\cdot} \f$ the * hat()-operator and \f$ (\cdot)^\vee \f$ the vee()-operator of SE3. * * \see hat() * \see vee() */ inline static const Tangent lieBracket(const Tangent & a, const Tangent & b) { Matrix upsilon1 = a.template head<3>(); Matrix upsilon2 = b.template head<3>(); Matrix omega1 = a.template tail<3>(); Matrix omega2 = b.template tail<3>(); Tangent res; res.template head<3>() = omega1.cross(upsilon2) + upsilon1.cross(omega2); res.template tail<3>() = omega1.cross(omega2); return res; } /** * \brief Logarithmic map * * \param other element of the group SE3 * \returns corresponding tangent space element * (translational part \f$ \upsilon \f$ * and rotation vector \f$ \omega \f$) * * Computes the logarithmic, the inverse of the group exponential. * To be specific, this function computes \f$ \log({\cdot})^\vee \f$ * with \f$ \vee(\cdot) \f$ being the matrix logarithm * and \f$ \vee{\cdot} \f$ the vee()-operator of SE3. * * \see exp() * \see vee() */ inline static const Tangent log(const SE3Group & se3) { Tangent upsilon_omega; Scalar theta; upsilon_omega.template tail<3>() = SO3Group::logAndTheta(se3.so3(), &theta); if (std::abs(theta)::epsilon()) { const Matrix & Omega = SO3Group::hat(upsilon_omega.template tail<3>()); const Matrix & V_inv = Matrix::Identity() - static_cast(0.5)*Omega + static_cast(1./12.)*(Omega*Omega); upsilon_omega.template head<3>() = V_inv*se3.translation(); } else { const Matrix & Omega = SO3Group::hat(upsilon_omega.template tail<3>()); const Matrix & V_inv = ( Matrix::Identity() - static_cast(0.5)*Omega + ( static_cast(1) - theta/(static_cast(2)*tan(theta/Scalar(2)))) / (theta*theta)*(Omega*Omega) ); upsilon_omega.template head<3>() = V_inv*se3.translation(); } return upsilon_omega; } /** * \brief vee-operator * * \param Omega 4x4-matrix representation of Lie algebra element * \returns 6-vector representatin of Lie algebra element * * This is the inverse of the hat()-operator. * * \see hat() */ inline static const Tangent vee(const Transformation & Omega) { Tangent upsilon_omega; upsilon_omega.template head<3>() = Omega.col(3).template head<3>(); upsilon_omega.template tail<3>() = SO3Group::vee(Omega.template topLeftCorner<3,3>()); return upsilon_omega; } }; /** * \brief SE3 default type - Constructors and default storage for SE3 Type */ template class SE3Group : public SE3GroupBase > { typedef SE3GroupBase > Base; public: /** \brief scalar type */ typedef typename internal::traits > ::Scalar Scalar; /** \brief SO3 reference type */ typedef typename internal::traits > ::SO3Type & SO3Reference; /** \brief SO3 const reference type */ typedef const typename internal::traits > ::SO3Type & ConstSO3Reference; /** \brief translation reference type */ typedef typename internal::traits > ::TranslationType & TranslationReference; /** \brief translation const reference type */ typedef const typename internal::traits > ::TranslationType & ConstTranslationReference; /** \brief degree of freedom of group */ static const int DoF = Base::DoF; /** \brief number of internal parameters used */ static const int num_parameters = Base::num_parameters; /** \brief group transformations are NxN matrices */ static const int N = Base::N; /** \brief group transfomation type */ typedef typename Base::Transformation Transformation; /** \brief point type */ typedef typename Base::Point Point; /** \brief tangent vector type */ typedef typename Base::Tangent Tangent; /** \brief adjoint transformation type */ typedef typename Base::Adjoint Adjoint; EIGEN_MAKE_ALIGNED_OPERATOR_NEW /** * \brief Default constructor * * Initialize Quaternion to identity rotation and translation to zero. */ inline SE3Group() : translation_( Matrix::Zero() ) { } /** * \brief Copy constructor */ template inline SE3Group(const SE3GroupBase & other) : so3_(other.so3()), translation_(other.translation()) { } /** * \brief Constructor from SO3 and translation vector */ template inline SE3Group(const SO3GroupBase & so3, const Point & translation) : so3_(so3), translation_(translation) { } /** * \brief Constructor from rotation matrix and translation vector * * \pre rotation matrix need to be orthogonal with determinant of 1 */ inline SE3Group(const Matrix & rotation_matrix, const Point & translation) : so3_(rotation_matrix), translation_(translation) { } /** * \brief Constructor from quaternion and translation vector * * \pre quaternion must not be zero */ inline SE3Group(const Quaternion & quaternion, const Point & translation) : so3_(quaternion), translation_(translation) { } /** * \brief Constructor from 4x4 matrix * * \pre top-left 3x3 sub-matrix need to be orthogonal with determinant of 1 */ inline explicit SE3Group(const Eigen::Matrix& T) : so3_(T.template topLeftCorner<3,3>()), translation_(T.template block<3,1>(0,3)) { } /** * \returns pointer to internal data * * This provides unsafe read/write access to internal data. SE3 is represented * by a pair of an SO3 element (4 parameters) and translation vector (three * parameters). The user needs to take care of that the quaternion * stays normalized. * * Note: The first three Scalars represent the imaginary parts, while the * forth Scalar represent the real part. * * /see normalize() */ EIGEN_STRONG_INLINE Scalar* data() { // so3_ and translation_ are layed out sequentially with no padding return so3_.data(); } /** * \returns const pointer to internal data * * Const version of data(). */ EIGEN_STRONG_INLINE const Scalar* data() const { // so3_ and translation_ are layed out sequentially with no padding return so3_.data(); } /** * \brief Accessor of SO3 */ EIGEN_STRONG_INLINE SO3Reference so3() { return so3_; } /** * \brief Mutator of SO3 */ EIGEN_STRONG_INLINE ConstSO3Reference so3() const { return so3_; } /** * \brief Mutator of translation vector */ EIGEN_STRONG_INLINE TranslationReference translation() { return translation_; } /** * \brief Accessor of translation vector */ EIGEN_STRONG_INLINE ConstTranslationReference translation() const { return translation_; } protected: Sophus::SO3Group so3_; Matrix translation_; }; } // end namespace namespace Eigen { /** * \brief Specialisation of Eigen::Map for SE3GroupBase * * Allows us to wrap SE3 Objects around POD array * (e.g. external c style quaternion) */ template class Map, _Options> : public Sophus::SE3GroupBase, _Options> > { typedef Sophus::SE3GroupBase, _Options> > Base; public: /** \brief scalar type */ typedef typename internal::traits::Scalar Scalar; /** \brief translation reference type */ typedef typename internal::traits::TranslationType & TranslationReference; /** \brief translation const reference type */ typedef const typename internal::traits::TranslationType & ConstTranslationReference; /** \brief SO3 reference type */ typedef typename internal::traits::SO3Type & SO3Reference; /** \brief SO3 const reference type */ typedef const typename internal::traits::SO3Type & ConstSO3Reference; /** \brief degree of freedom of group */ static const int DoF = Base::DoF; /** \brief number of internal parameters used */ static const int num_parameters = Base::num_parameters; /** \brief group transformations are NxN matrices */ static const int N = Base::N; /** \brief group transfomation type */ typedef typename Base::Transformation Transformation; /** \brief point type */ typedef typename Base::Point Point; /** \brief tangent vector type */ typedef typename Base::Tangent Tangent; /** \brief adjoint transformation type */ typedef typename Base::Adjoint Adjoint; EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Map) using Base::operator*=; using Base::operator*; EIGEN_STRONG_INLINE Map(Scalar* coeffs) : so3_(coeffs), translation_(coeffs+Sophus::SO3Group::num_parameters) { } /** * \brief Mutator of SO3 */ EIGEN_STRONG_INLINE SO3Reference so3() { return so3_; } /** * \brief Accessor of SO3 */ EIGEN_STRONG_INLINE ConstSO3Reference so3() const { return so3_; } /** * \brief Mutator of translation vector */ EIGEN_STRONG_INLINE TranslationReference translation() { return translation_; } /** * \brief Accessor of translation vector */ EIGEN_STRONG_INLINE ConstTranslationReference translation() const { return translation_; } protected: Map,_Options> so3_; Map,_Options> translation_; }; /** * \brief Specialisation of Eigen::Map for const SE3GroupBase * * Allows us to wrap SE3 Objects around POD array * (e.g. external c style quaternion) */ template class Map, _Options> : public Sophus::SE3GroupBase< Map, _Options> > { typedef Sophus::SE3GroupBase, _Options> > Base; public: /** \brief scalar type */ typedef typename internal::traits::Scalar Scalar; /** \brief translation const reference type */ typedef const typename internal::traits::TranslationType & ConstTranslationReference; /** \brief SO3 const reference type */ typedef const typename internal::traits::SO3Type & ConstSO3Reference; /** \brief degree of freedom of group */ static const int DoF = Base::DoF; /** \brief number of internal parameters used */ static const int num_parameters = Base::num_parameters; /** \brief group transformations are NxN matrices */ static const int N = Base::N; /** \brief group transfomation type */ typedef typename Base::Transformation Transformation; /** \brief point type */ typedef typename Base::Point Point; /** \brief tangent vector type */ typedef typename Base::Tangent Tangent; /** \brief adjoint transformation type */ typedef typename Base::Adjoint Adjoint; EIGEN_INHERIT_ASSIGNMENT_EQUAL_OPERATOR(Map) using Base::operator*=; using Base::operator*; EIGEN_STRONG_INLINE Map(const Scalar* coeffs) : so3_(coeffs), translation_(coeffs+Sophus::SO3Group::num_parameters) { } EIGEN_STRONG_INLINE Map(const Scalar* trans_coeffs, const Scalar* rot_coeffs) : translation_(trans_coeffs), so3_(rot_coeffs){ } /** * \brief Accessor of SO3 */ EIGEN_STRONG_INLINE ConstSO3Reference so3() const { return so3_; } /** * \brief Accessor of translation vector */ EIGEN_STRONG_INLINE ConstTranslationReference translation() const { return translation_; } protected: const Map,_Options> so3_; const Map,_Options> translation_; }; } #endif