.. _program_listing_file_sophus_so2.hpp: Program Listing for File so2.hpp ================================ |exhale_lsh| :ref:`Return to documentation for file ` (``sophus/so2.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #pragma once #include // Include only the selective set of Eigen headers that we need. // This helps when using Sophus with unusual compilers, like nvcc. #include #include "rotation_matrix.hpp" #include "types.hpp" namespace Sophus { template class SO2; using SO2d = SO2; using SO2f = SO2; } // namespace Sophus namespace Eigen { namespace internal { template struct traits> { static constexpr int Options = Options_; using Scalar = Scalar_; using ComplexType = Sophus::Vector2; }; template struct traits, Options_>> : traits> { static constexpr int Options = Options_; using Scalar = Scalar_; using ComplexType = Map, Options>; }; template struct traits const, Options_>> : traits const> { static constexpr int Options = Options_; using Scalar = Scalar_; using ComplexType = Map const, Options>; }; } // namespace internal } // namespace Eigen namespace Sophus { template class SO2Base { public: static constexpr int Options = Eigen::internal::traits::Options; using Scalar = typename Eigen::internal::traits::Scalar; using ComplexT = typename Eigen::internal::traits::ComplexType; using ComplexTemporaryType = Sophus::Vector2; static int constexpr DoF = 1; static int constexpr num_parameters = 2; static int constexpr N = 2; static int constexpr Dim = 2; using Transformation = Matrix; using Point = Vector2; using HomogeneousPoint = Vector3; using Line = ParametrizedLine2; using Hyperplane = Hyperplane2; using Tangent = Scalar; using Adjoint = Scalar; template using ReturnScalar = typename Eigen::ScalarBinaryOpTraits< Scalar, typename OtherDerived::Scalar>::ReturnType; template using SO2Product = SO2>; template using PointProduct = Vector2>; template using HomogeneousPointProduct = Vector3>; SOPHUS_FUNC Adjoint Adj() const { return Scalar(1); } template SOPHUS_FUNC SO2 cast() const { return SO2(unit_complex().template cast()); } SOPHUS_FUNC Scalar* data() { return unit_complex_nonconst().data(); } SOPHUS_FUNC Scalar const* data() const { return unit_complex().data(); } SOPHUS_FUNC SO2 inverse() const { return SO2(unit_complex().x(), -unit_complex().y()); } SOPHUS_FUNC Scalar log() const { using std::atan2; return atan2(unit_complex().y(), unit_complex().x()); } SOPHUS_FUNC void normalize() { using std::hypot; // Avoid under/overflows for higher precision Scalar length = hypot(unit_complex().x(), unit_complex().y()); SOPHUS_ENSURE(length >= Constants::epsilon(), "%s", "Complex number should not be close to zero!"); unit_complex_nonconst() /= length; } SOPHUS_FUNC Transformation matrix() const { Scalar const& real = unit_complex().x(); Scalar const& imag = unit_complex().y(); Transformation R; // clang-format off R << real, -imag, imag, real; // clang-format on return R; } template SOPHUS_FUNC SO2Base& operator=(SO2Base const& other) { unit_complex_nonconst() = other.unit_complex(); return *this; } template SOPHUS_FUNC SO2Product operator*( SO2Base const& other) const { using ResultT = ReturnScalar; Scalar const lhs_real = unit_complex().x(); Scalar const lhs_imag = unit_complex().y(); typename OtherDerived::Scalar const& rhs_real = other.unit_complex().x(); typename OtherDerived::Scalar const& rhs_imag = other.unit_complex().y(); // complex multiplication ResultT const result_real = lhs_real * rhs_real - lhs_imag * rhs_imag; ResultT const result_imag = lhs_real * rhs_imag + lhs_imag * rhs_real; ResultT const squared_norm = result_real * result_real + result_imag * result_imag; // We can assume that the squared-norm is close to 1 since we deal with a // unit complex number. Due to numerical precision issues, there might // be a small drift after pose concatenation. Hence, we need to renormalizes // the complex number here. // Since squared-norm is close to 1, we do not need to calculate the costly // square-root, but can use an approximation around 1 (see // http://stackoverflow.com/a/12934750 for details). if (squared_norm != ResultT(1.0)) { ResultT const scale = ResultT(2.0) / (ResultT(1.0) + squared_norm); return SO2Product(result_real * scale, result_imag * scale); } return SO2Product(result_real, result_imag); } template ::value>::type> SOPHUS_FUNC PointProduct operator*( Eigen::MatrixBase const& p) const { Scalar const& real = unit_complex().x(); Scalar const& imag = unit_complex().y(); return PointProduct(real * p[0] - imag * p[1], imag * p[0] + real * p[1]); } template ::value>::type> SOPHUS_FUNC HomogeneousPointProduct operator*( Eigen::MatrixBase const& p) const { Scalar const& real = unit_complex().x(); Scalar const& imag = unit_complex().y(); return HomogeneousPointProduct( real * p[0] - imag * p[1], imag * p[0] + real * p[1], p[2]); } SOPHUS_FUNC Line operator*(Line const& l) const { return Line((*this) * l.origin(), (*this) * l.direction()); } SOPHUS_FUNC Hyperplane operator*(Hyperplane const& p) const { return Hyperplane((*this) * p.normal(), p.offset()); } template >::value>::type> SOPHUS_FUNC SO2Base operator*=(SO2Base const& other) { *static_cast(this) = *this * other; return *this; } SOPHUS_FUNC Matrix Dx_this_mul_exp_x_at_0() const { return Matrix(-unit_complex()[1], unit_complex()[0]); } SOPHUS_FUNC Sophus::Vector params() const { return unit_complex(); } SOPHUS_FUNC Matrix Dx_log_this_inv_by_x_at_this() const { return Matrix(-unit_complex()[1], unit_complex()[0]); } SOPHUS_FUNC void setComplex(Point const& complex) { unit_complex_nonconst() = complex; normalize(); } SOPHUS_FUNC ComplexT const& unit_complex() const { return static_cast(this)->unit_complex(); } private: SOPHUS_FUNC ComplexT& unit_complex_nonconst() { return static_cast(this)->unit_complex_nonconst(); } }; template class SO2 : public SO2Base> { public: using Base = SO2Base>; 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 ComplexMember = Vector2; friend class SO2Base>; using Base::operator=; SOPHUS_FUNC SO2& operator=(SO2 const& other) = default; EIGEN_MAKE_ALIGNED_OPERATOR_NEW SOPHUS_FUNC SO2() : unit_complex_(Scalar(1), Scalar(0)) {} SOPHUS_FUNC SO2(SO2 const& other) = default; template SOPHUS_FUNC SO2(SO2Base const& other) : unit_complex_(other.unit_complex()) {} SOPHUS_FUNC explicit SO2(Transformation const& R) : unit_complex_(Scalar(0.5) * (R(0, 0) + R(1, 1)), Scalar(0.5) * (R(1, 0) - R(0, 1))) { SOPHUS_ENSURE(isOrthogonal(R), "R is not orthogonal:\n {}", SOPHUS_FMT_ARG(R)); SOPHUS_ENSURE(R.determinant() > Scalar(0), "det(R) is not positive: {}", SOPHUS_FMT_ARG(R.determinant())); } SOPHUS_FUNC SO2(Scalar const& real, Scalar const& imag) : unit_complex_(real, imag) { Base::normalize(); } template SOPHUS_FUNC explicit SO2(Eigen::MatrixBase const& complex) : unit_complex_(complex) { static_assert(std::is_same::value, "must be same Scalar type"); Base::normalize(); } SOPHUS_FUNC explicit SO2(Scalar theta) { unit_complex_nonconst() = SO2::exp(theta).unit_complex(); } SOPHUS_FUNC ComplexMember const& unit_complex() const { return unit_complex_; } SOPHUS_FUNC static SO2 exp(Tangent const& theta) { using std::cos; using std::sin; return SO2(cos(theta), sin(theta)); } SOPHUS_FUNC static Sophus::Matrix Dx_exp_x( Tangent const& theta) { using std::cos; using std::sin; return Sophus::Matrix(-sin(theta), cos(theta)); } SOPHUS_FUNC static Sophus::Matrix Dx_exp_x_at_0() { return Sophus::Matrix(Scalar(0), Scalar(1)); } SOPHUS_FUNC static Sophus::Matrix Dx_exp_x_times_point_at_0( Point const& point) { return Point(-point.y(), point.x()); } SOPHUS_FUNC static Transformation Dxi_exp_x_matrix_at_0(int) { return generator(); } SOPHUS_FUNC static Transformation generator() { return hat(Scalar(1)); } SOPHUS_FUNC static Transformation hat(Tangent const& theta) { Transformation Omega; // clang-format off Omega << Scalar(0), -theta, theta, Scalar(0); // clang-format on return Omega; } template static SOPHUS_FUNC enable_if_t::value, SO2> fitToSO2(Transformation const& R) { return SO2(makeRotationMatrix(R)); } SOPHUS_FUNC static Tangent lieBracket(Tangent const&, Tangent const&) { return Scalar(0); } template static SO2 sampleUniform(UniformRandomBitGenerator& generator) { static_assert(IsUniformRandomBitGenerator::value, "generator must meet the UniformRandomBitGenerator concept"); std::uniform_real_distribution uniform(-Constants::pi(), Constants::pi()); return SO2(uniform(generator)); } SOPHUS_FUNC static Tangent vee(Transformation const& Omega) { using std::abs; return Omega(1, 0); } protected: SOPHUS_FUNC ComplexMember& unit_complex_nonconst() { return unit_complex_; } ComplexMember unit_complex_; }; } // namespace Sophus namespace Eigen { template class Map, Options> : public Sophus::SO2Base, Options>> { public: using Base = Sophus::SO2Base, 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::SO2Base, Options>>; using Base::operator=; using Base::operator*=; using Base::operator*; SOPHUS_FUNC explicit Map(Scalar* coeffs) : unit_complex_(coeffs) {} SOPHUS_FUNC Map, Options> const& unit_complex() const { return unit_complex_; } protected: SOPHUS_FUNC Map, Options>& unit_complex_nonconst() { return unit_complex_; } Map, Options> unit_complex_; }; template class Map const, Options> : public Sophus::SO2Base const, Options>> { public: using Base = Sophus::SO2Base 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) : unit_complex_(coeffs) {} SOPHUS_FUNC Map const, Options> const& unit_complex() const { return unit_complex_; } protected: Map const, Options> const unit_complex_; }; } // namespace Eigen