.. _program_listing_file_sophus_rxso3.hpp: Program Listing for File rxso3.hpp ================================== |exhale_lsh| :ref:`Return to documentation for file ` (``sophus/rxso3.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #pragma once #include "so3.hpp" namespace Sophus { template class RxSO3; using RxSO3d = RxSO3; using RxSO3f = RxSO3; } // namespace Sophus namespace Eigen { namespace internal { template struct traits> { static constexpr int Options = Options_; using Scalar = Scalar_; using QuaternionType = Eigen::Quaternion; }; template struct traits, Options_>> : traits> { static constexpr int Options = Options_; using Scalar = Scalar_; using QuaternionType = Map, Options>; }; template struct traits const, Options_>> : traits const> { static constexpr int Options = Options_; using Scalar = Scalar_; using QuaternionType = Map const, Options>; }; } // namespace internal } // namespace Eigen namespace Sophus { template class RxSO3Base { public: static constexpr int Options = Eigen::internal::traits::Options; using Scalar = typename Eigen::internal::traits::Scalar; using QuaternionType = typename Eigen::internal::traits::QuaternionType; using QuaternionTemporaryType = Eigen::Quaternion; static int constexpr DoF = 4; static int constexpr num_parameters = 4; static int constexpr N = 3; static int constexpr Dim = 3; using Transformation = Matrix; using Point = Vector3; using HomogeneousPoint = Vector4; using Line = ParametrizedLine3; using Hyperplane = Hyperplane3; using Tangent = Vector; using Adjoint = Matrix; struct TangentAndTheta { EIGEN_MAKE_ALIGNED_OPERATOR_NEW Tangent tangent; Scalar theta; }; template using ReturnScalar = typename Eigen::ScalarBinaryOpTraits< Scalar, typename OtherDerived::Scalar>::ReturnType; template using RxSO3Product = RxSO3>; template using PointProduct = Vector3>; template using HomogeneousPointProduct = Vector4>; SOPHUS_FUNC Adjoint Adj() const { Adjoint res; res.setIdentity(); res.template topLeftCorner<3, 3>() = rotationMatrix(); return res; } template SOPHUS_FUNC RxSO3 cast() const { return RxSO3(quaternion().template cast()); } SOPHUS_FUNC Scalar* data() { return quaternion_nonconst().coeffs().data(); } SOPHUS_FUNC Scalar const* data() const { return quaternion().coeffs().data(); } SOPHUS_FUNC RxSO3 inverse() const { return RxSO3(quaternion().inverse()); } SOPHUS_FUNC Tangent log() const { return logAndTheta().tangent; } SOPHUS_FUNC TangentAndTheta logAndTheta() const { using std::log; Scalar scale = quaternion().squaredNorm(); TangentAndTheta result; result.tangent[3] = log(scale); auto omega_and_theta = SO3(quaternion()).logAndTheta(); result.tangent.template head<3>() = omega_and_theta.tangent; result.theta = omega_and_theta.theta; return result; } SOPHUS_FUNC Transformation matrix() const { Transformation sR; Scalar const vx_sq = quaternion().vec().x() * quaternion().vec().x(); Scalar const vy_sq = quaternion().vec().y() * quaternion().vec().y(); Scalar const vz_sq = quaternion().vec().z() * quaternion().vec().z(); Scalar const w_sq = quaternion().w() * quaternion().w(); Scalar const two_vx = Scalar(2) * quaternion().vec().x(); Scalar const two_vy = Scalar(2) * quaternion().vec().y(); Scalar const two_vz = Scalar(2) * quaternion().vec().z(); Scalar const two_vx_vy = two_vx * quaternion().vec().y(); Scalar const two_vx_vz = two_vx * quaternion().vec().z(); Scalar const two_vx_w = two_vx * quaternion().w(); Scalar const two_vy_vz = two_vy * quaternion().vec().z(); Scalar const two_vy_w = two_vy * quaternion().w(); Scalar const two_vz_w = two_vz * quaternion().w(); sR(0, 0) = vx_sq - vy_sq - vz_sq + w_sq; sR(1, 0) = two_vx_vy + two_vz_w; sR(2, 0) = two_vx_vz - two_vy_w; sR(0, 1) = two_vx_vy - two_vz_w; sR(1, 1) = -vx_sq + vy_sq - vz_sq + w_sq; sR(2, 1) = two_vx_w + two_vy_vz; sR(0, 2) = two_vx_vz + two_vy_w; sR(1, 2) = -two_vx_w + two_vy_vz; sR(2, 2) = -vx_sq - vy_sq + vz_sq + w_sq; return sR; } template SOPHUS_FUNC RxSO3Base& operator=( RxSO3Base const& other) { quaternion_nonconst() = other.quaternion(); return *this; } template SOPHUS_FUNC RxSO3Product operator*( RxSO3Base const& other) const { using std::sqrt; using ResultT = ReturnScalar; using QuaternionProductType = typename RxSO3Product::QuaternionType; QuaternionProductType result_quaternion( Sophus::SO3::QuaternionProduct( quaternion(), other.quaternion())); ResultT scale = result_quaternion.squaredNorm(); if (scale < Constants::epsilon()) { SOPHUS_ENSURE(scale > ResultT(0), "Scale must be greater zero."); result_quaternion.normalize(); result_quaternion.coeffs() *= sqrt(Constants::epsilonPlus()); } if (scale > ResultT(1.) / Constants::epsilon()) { result_quaternion.normalize(); result_quaternion.coeffs() /= sqrt(Constants::epsilonPlus()); } return RxSO3Product(result_quaternion); } template ::value>::type> SOPHUS_FUNC PointProduct operator*( Eigen::MatrixBase const& p) const { // Follows http:///eigen.tuxfamily.org/bz/show_bug.cgi?id=459 Scalar scale = quaternion().squaredNorm(); PointProduct two_vec_cross_p = quaternion().vec().cross(p); two_vec_cross_p += two_vec_cross_p; return scale * p + (quaternion().w() * two_vec_cross_p + quaternion().vec().cross(two_vec_cross_p)); } template ::value>::type> SOPHUS_FUNC HomogeneousPointProduct operator*( Eigen::MatrixBase const& p) const { const auto rsp = *this * p.template head<3>(); return HomogeneousPointProduct(rsp(0), rsp(1), rsp(2), p(3)); } SOPHUS_FUNC Line operator*(Line const& l) const { return Line((*this) * l.origin(), (*this) * l.direction() / quaternion().squaredNorm()); } SOPHUS_FUNC Hyperplane operator*(Hyperplane const& p) const { const auto this_scale = scale(); return Hyperplane((*this) * p.normal() / this_scale, this_scale * p.offset()); } template >::value>::type> SOPHUS_FUNC RxSO3Base& operator*=( RxSO3Base const& other) { *static_cast(this) = *this * other; return *this; } SOPHUS_FUNC Sophus::Vector params() const { return quaternion().coeffs(); } SOPHUS_FUNC void setQuaternion(Eigen::Quaternion const& quat) { SOPHUS_ENSURE(quat.squaredNorm() > Constants::epsilon() * Constants::epsilon(), "Scale factor must be greater-equal epsilon."); SOPHUS_ENSURE( quat.squaredNorm() < Scalar(1.) / (Constants::epsilon() * Constants::epsilon()), "Inverse scale factor must be greater-equal epsilon."); static_cast(this)->quaternion_nonconst() = quat; } SOPHUS_FUNC QuaternionType const& quaternion() const { return static_cast(this)->quaternion(); } SOPHUS_FUNC Transformation rotationMatrix() const { QuaternionTemporaryType norm_quad = quaternion(); norm_quad.normalize(); return norm_quad.toRotationMatrix(); } SOPHUS_FUNC Scalar scale() const { return quaternion().squaredNorm(); } SOPHUS_FUNC void setRotationMatrix(Transformation const& R) { using std::sqrt; Scalar saved_scale = scale(); quaternion_nonconst() = R; quaternion_nonconst().coeffs() *= sqrt(saved_scale); } SOPHUS_FUNC void setScale(Scalar const& scale) { using std::sqrt; quaternion_nonconst().normalize(); quaternion_nonconst().coeffs() *= sqrt(scale); } SOPHUS_FUNC void setScaledRotationMatrix(Transformation const& sR) { Transformation squared_sR = sR * sR.transpose(); Scalar squared_scale = Scalar(1. / 3.) * (squared_sR(0, 0) + squared_sR(1, 1) + squared_sR(2, 2)); SOPHUS_ENSURE(squared_scale >= Constants::epsilon() * Constants::epsilon(), "Scale factor must be greater-equal epsilon."); SOPHUS_ENSURE(squared_scale < Scalar(1.) / (Constants::epsilon() * Constants::epsilon()), "Inverse scale factor must be greater-equal epsilon."); Scalar scale = sqrt(squared_scale); quaternion_nonconst() = sR / scale; quaternion_nonconst().coeffs() *= sqrt(scale); } SOPHUS_FUNC void setSO3(SO3 const& so3) { using std::sqrt; Scalar saved_scale = scale(); quaternion_nonconst() = so3.unit_quaternion(); quaternion_nonconst().coeffs() *= sqrt(saved_scale); } SOPHUS_FUNC SO3 so3() const { return SO3(quaternion()); } SOPHUS_FUNC Matrix Dx_this_mul_exp_x_at_0() const { Matrix J; Eigen::Quaternion const q = quaternion(); J.col(3) = q.coeffs() * Scalar(0.5); Scalar const c0 = Scalar(0.5) * q.w(); Scalar const c1 = Scalar(0.5) * q.z(); Scalar const c2 = -c1; Scalar const c3 = Scalar(0.5) * q.y(); Scalar const c4 = Scalar(0.5) * q.x(); Scalar const c5 = -c4; Scalar const c6 = -c3; J(0, 0) = c0; J(0, 1) = c2; J(0, 2) = c3; J(1, 0) = c1; J(1, 1) = c0; J(1, 2) = c5; J(2, 0) = c6; J(2, 1) = c4; J(2, 2) = c0; J(3, 0) = c5; J(3, 1) = c6; J(3, 2) = c2; return J; } SOPHUS_FUNC Matrix Dx_log_this_inv_by_x_at_this() const { auto& q = quaternion(); Matrix J; // clang-format off J << q.w(), q.z(), -q.y(), -q.x(), -q.z(), q.w(), q.x(), -q.y(), q.y(), -q.x(), q.w(), -q.z(), q.x(), q.y(), q.z(), q.w(); // clang-format on const Scalar scaler = Scalar(2.) / q.squaredNorm(); return J * scaler; } private: SOPHUS_FUNC QuaternionType& quaternion_nonconst() { return static_cast(this)->quaternion_nonconst(); } }; template class RxSO3 : public RxSO3Base> { public: using Base = RxSO3Base>; static int constexpr DoF = Base::DoF; static int constexpr num_parameters = Base::num_parameters; using Scalar = Scalar_; using Transformation = typename Base::Transformation; using Point = typename Base::Point; using HomogeneousPoint = typename Base::HomogeneousPoint; using Tangent = typename Base::Tangent; using Adjoint = typename Base::Adjoint; using QuaternionMember = Eigen::Quaternion; friend class RxSO3Base>; using Base::operator=; SOPHUS_FUNC RxSO3& operator=(RxSO3 const& other) = default; EIGEN_MAKE_ALIGNED_OPERATOR_NEW SOPHUS_FUNC RxSO3() : quaternion_(Scalar(1), Scalar(0), Scalar(0), Scalar(0)) {} SOPHUS_FUNC RxSO3(RxSO3 const& other) = default; template SOPHUS_FUNC RxSO3(RxSO3Base const& other) : quaternion_(other.quaternion()) {} SOPHUS_FUNC explicit RxSO3(Transformation const& sR) { this->setScaledRotationMatrix(sR); } SOPHUS_FUNC RxSO3(Scalar const& scale, Transformation const& R) : quaternion_(R) { SOPHUS_ENSURE(scale >= Constants::epsilon(), "Scale factor must be greater-equal epsilon."); SOPHUS_ENSURE(scale < Scalar(1.) / Constants::epsilon(), "Inverse scale factor must be greater-equal epsilon."); using std::sqrt; quaternion_.coeffs() *= sqrt(scale); } SOPHUS_FUNC RxSO3(Scalar const& scale, SO3 const& so3) : quaternion_(so3.unit_quaternion()) { SOPHUS_ENSURE(scale >= Constants::epsilon(), "Scale factor must be greater-equal epsilon."); SOPHUS_ENSURE(scale < Scalar(1.) / Constants::epsilon(), "Inverse scale factor must be greater-equal epsilon."); using std::sqrt; quaternion_.coeffs() *= sqrt(scale); } template SOPHUS_FUNC explicit RxSO3(Eigen::QuaternionBase const& quat) : quaternion_(quat) { static_assert(std::is_same::value, "must be same Scalar type."); SOPHUS_ENSURE(quaternion_.squaredNorm() >= Constants::epsilon(), "Scale factor must be greater-equal epsilon."); SOPHUS_ENSURE( quat.squaredNorm() < Scalar(1.) / Constants::epsilon(), "Inverse scale factor must be greater-equal epsilon."); } template SOPHUS_FUNC explicit RxSO3(Scalar const& scale, Eigen::QuaternionBase const& unit_quat) : RxSO3(scale, SO3(unit_quat)) {} SOPHUS_FUNC QuaternionMember const& quaternion() const { return quaternion_; } SOPHUS_FUNC static Sophus::Matrix Dx_exp_x_at_0() { static Scalar const h(0.5); return h * Sophus::Matrix::Identity(); } SOPHUS_FUNC static Sophus::Matrix Dx_exp_x( const Tangent& a) { using std::exp; using std::sqrt; Sophus::Matrix J; Vector3 const omega = a.template head<3>(); Scalar const sigma = a[3]; Eigen::Quaternion quat = SO3::exp(omega).unit_quaternion(); Scalar const scale = sqrt(exp(sigma)); Scalar const scale_half = scale * Scalar(0.5); J.template block<4, 3>(0, 0) = SO3::Dx_exp_x(omega) * scale; J.col(3) = quat.coeffs() * scale_half; return J; } SOPHUS_FUNC static Sophus::Matrix Dx_exp_x_times_point_at_0( Point const& point) { Sophus::Matrix j; j << Sophus::SO3::hat(-point), point; return j; } SOPHUS_FUNC static Transformation Dxi_exp_x_matrix_at_0(int i) { return generator(i); } SOPHUS_FUNC static RxSO3 exp(Tangent const& a) { Scalar theta; return expAndTheta(a, &theta); } SOPHUS_FUNC static RxSO3 expAndTheta(Tangent const& a, Scalar* theta) { SOPHUS_ENSURE(theta != nullptr, "must not be nullptr."); using std::exp; using std::max; using std::min; using std::sqrt; Vector3 const omega = a.template head<3>(); Scalar sigma = a[3]; Scalar scale = exp(sigma); // Ensure that scale-factor constraint is always valid scale = max(scale, Constants::epsilonPlus()); scale = min(scale, Scalar(1.) / Constants::epsilonPlus()); Scalar sqrt_scale = sqrt(scale); Eigen::Quaternion quat = SO3::expAndTheta(omega, theta).unit_quaternion(); quat.coeffs() *= sqrt_scale; return RxSO3(quat); } SOPHUS_FUNC static Transformation generator(int i) { SOPHUS_ENSURE(i >= 0 && i <= 3, "i should be in range [0,3]."); Tangent e; e.setZero(); e[i] = Scalar(1); return hat(e); } SOPHUS_FUNC static Transformation hat(Tangent const& a) { Transformation A; // clang-format off A << a(3), -a(2), a(1), a(2), a(3), -a(0), -a(1), a(0), a(3); // clang-format on return A; } SOPHUS_FUNC static Tangent lieBracket(Tangent const& a, Tangent const& b) { Vector3 const omega1 = a.template head<3>(); Vector3 const omega2 = b.template head<3>(); Vector4 res; res.template head<3>() = omega1.cross(omega2); res[3] = Scalar(0); return res; } template static RxSO3 sampleUniform(UniformRandomBitGenerator& generator) { std::uniform_real_distribution uniform(Scalar(-1), Scalar(1)); using std::exp2; return RxSO3(exp2(uniform(generator)), SO3::sampleUniform(generator)); } SOPHUS_FUNC static Tangent vee(Transformation const& Omega) { using std::abs; return Tangent(Omega(2, 1), Omega(0, 2), Omega(1, 0), Omega(0, 0)); } protected: SOPHUS_FUNC QuaternionMember& quaternion_nonconst() { return quaternion_; } QuaternionMember quaternion_; }; } // namespace Sophus namespace Eigen { template class Map, Options> : public Sophus::RxSO3Base, Options>> { public: using Base = Sophus::RxSO3Base, Options>>; using Scalar = Scalar_; using Transformation = typename Base::Transformation; using Point = typename Base::Point; using HomogeneousPoint = typename Base::HomogeneousPoint; using Tangent = typename Base::Tangent; using Adjoint = typename Base::Adjoint; friend class Sophus::RxSO3Base, Options>>; using Base::operator=; using Base::operator*=; using Base::operator*; SOPHUS_FUNC explicit Map(Scalar* coeffs) : quaternion_(coeffs) {} SOPHUS_FUNC Map, Options> const& quaternion() const { return quaternion_; } protected: SOPHUS_FUNC Map, Options>& quaternion_nonconst() { return quaternion_; } Map, Options> quaternion_; }; template class Map const, Options> : public Sophus::RxSO3Base const, Options>> { public: using Base = Sophus::RxSO3Base const, Options>>; using Scalar = Scalar_; using Transformation = typename Base::Transformation; using Point = typename Base::Point; using HomogeneousPoint = typename Base::HomogeneousPoint; using Tangent = typename Base::Tangent; using Adjoint = typename Base::Adjoint; using Base::operator*=; using Base::operator*; SOPHUS_FUNC explicit Map(Scalar const* coeffs) : quaternion_(coeffs) {} SOPHUS_FUNC Map const, Options> const& quaternion() const { return quaternion_; } protected: Map const, Options> const quaternion_; }; } // namespace Eigen