diff --git a/include/core/math/SE2.h b/include/core/math/SE2.h index 34ff6727a74a5e364348538b921b6f32094b665c..95631a8a6fb82ac22595b64d3e1d5b4fe7849cb4 100644 --- a/include/core/math/SE2.h +++ b/include/core/math/SE2.h @@ -102,6 +102,38 @@ inline VectorComposite identity() return v; } +template<typename D1, typename D2> +inline void inverse(const MatrixBase<D1>& p, const typename D1::Scalar& o, + MatrixBase<D2>& ip, typename D2::Scalar& io) +{ + MatrixSizeCheck<2, 1>::check(p); + MatrixSizeCheck<2, 1>::check(ip); + + ip = SO2::exp(-o) * -p; + io = -o; +} + +template<typename D1, typename D2> +inline void inverse(const MatrixBase<D1>& d, + MatrixBase<D2>& id) +{ + MatrixSizeCheck<3, 1>::check(d); + MatrixSizeCheck<3, 1>::check(id); + + Map<const Matrix<typename D1::Scalar, 2, 1> > p ( & d( 0 ) ); + Map<Matrix<typename D2::Scalar, 2, 1> > ip ( & id( 0 ) ); + + inverse(p, d(2), ip, id(2)); +} + +template<typename D> +inline Matrix<typename D::Scalar, 3, 1> inverse(const MatrixBase<D>& d) +{ + Matrix<typename D::Scalar, 3, 1> id; + inverse(d, id); + return id; +} + template<class D1, class D2> inline void exp(const Eigen::MatrixBase<D1>& _tau, Eigen::MatrixBase<D2>& _delta) { diff --git a/test/gtest_SE2.cpp b/test/gtest_SE2.cpp index 751637ed33b9ef406c11e20356f13f0e624c61fc..690a5f373e2259c8cc2268c898b04f28c7c8fdc4 100644 --- a/test/gtest_SE2.cpp +++ b/test/gtest_SE2.cpp @@ -28,6 +28,102 @@ using namespace Eigen; using namespace wolf; using namespace SE2; +TEST(SE2, exp) +{ + for (auto i = 1; i<10; i++) + { + double o = Vector1d::Random()(0) * M_PI; + ASSERT_MATRIX_APPROX(SO2::exp(o), Rotation2Dd(o).matrix(), 1e-8); + } +} + +TEST(SE2, invBlocks) +{ + Vector2d p, ip; + double o, io; + + // zero + p = Vector2d::Zero(); + o = 0; + + SE2::inverse(p,o,ip,io); + + ASSERT_MATRIX_APPROX(ip, Vector2d::Zero(), 1e-8); + ASSERT_NEAR(io, 0, 1e-8); + + // zero angle + p = Vector2d::Random(); + o = 0; + + SE2::inverse(p,o,ip,io); + + ASSERT_MATRIX_APPROX(ip, -p, 1e-8); + ASSERT_NEAR(io, 0, 1e-8); + + // zero translation + p = Vector2d::Zero(); + o = Vector1d::Random()(0) * M_PI; + + SE2::inverse(p,o,ip,io); + + ASSERT_MATRIX_APPROX(ip, Vector2d::Zero(), 1e-8); + ASSERT_NEAR(io, -o, 1e-8); + + // random + for (auto i = 0; i < 10; i++) + { + p = Vector2d::Random(); + o = Vector1d::Random()(0) * M_PI; + + SE2::inverse(p,o,ip,io); + + ASSERT_MATRIX_APPROX(ip, Rotation2Dd(-o).matrix() * -p, 1e-8); + ASSERT_NEAR(io, -o, 1e-8); + } +} + +TEST(SE2, invVector) +{ + Vector3d d, id; + + // zero + d = Vector3d::Zero(); + + SE2::inverse(d,id); + + ASSERT_MATRIX_APPROX(id, Vector3d::Zero(), 1e-8); + + // zero angle + d = Vector3d::Random(); + d(2) = 0; + + SE2::inverse(d,id); + + ASSERT_MATRIX_APPROX(id.head<2>(), -d.head<2>(), 1e-8); + ASSERT_NEAR(id(2), 0, 1e-8); + + // zero translation + d = Vector3d::Zero(); + d(2) = Vector1d::Random()(0) * M_PI; + + SE2::inverse(d,id); + + ASSERT_MATRIX_APPROX(id.head<2>(), Vector2d::Zero(), 1e-8); + ASSERT_NEAR(id(2), -d(2), 1e-8); + + // random + for (auto i = 0; i < 10; i++) + { + d = Vector3d::Random(); + d(2) *= M_PI; + + SE2::inverse(d,id); + + ASSERT_MATRIX_APPROX(id.head<2>(), Rotation2Dd(-d(2)) * -d.head<2>(), 1e-8); + ASSERT_NEAR(id(2), -d(2), 1e-8); + } +} + TEST(SE2, betweenBlocks) { Vector2d p1, p2, pd; @@ -40,7 +136,7 @@ TEST(SE2, betweenBlocks) o2 = o1; between(p1, o1, p2, o2, pd, od); - ASSERT_MATRIX_APPROX(pd, Eigen::Vector2d::Zero(), 1e-8); + ASSERT_MATRIX_APPROX(pd, Vector2d::Zero(), 1e-8); ASSERT_NEAR(od, 0, 1e-8); // both same random pose: relative pose zero @@ -53,7 +149,7 @@ TEST(SE2, betweenBlocks) between(p1, o1, p2, o2, pd, od); - ASSERT_MATRIX_APPROX(pd, Eigen::Vector2d::Zero(), 1e-8); + ASSERT_MATRIX_APPROX(pd, Vector2d::Zero(), 1e-8); ASSERT_NEAR(od, 0, 1e-8); } @@ -84,7 +180,7 @@ TEST(SE2, betweenVectors) p2 = p1; between(p1, p2, pd); - ASSERT_MATRIX_APPROX(pd, Eigen::Vector3d::Zero(), 1e-8); + ASSERT_MATRIX_APPROX(pd, Vector3d::Zero(), 1e-8); // both same random pose: relative pose zero for (auto i = 0; i < 10; i++) @@ -95,7 +191,7 @@ TEST(SE2, betweenVectors) between(p1, p2, pd); - ASSERT_MATRIX_APPROX(pd, Eigen::Vector3d::Zero(), 1e-8); + ASSERT_MATRIX_APPROX(pd, Vector3d::Zero(), 1e-8); } // random relative pose @@ -124,7 +220,7 @@ TEST(SE2, betweenVectorsReturn) p2 = p1; pd = between(p1, p2); - ASSERT_MATRIX_APPROX(pd, Eigen::Vector3d::Zero(), 1e-8); + ASSERT_MATRIX_APPROX(pd, Vector3d::Zero(), 1e-8); // both same random pose: relative pose zero for (auto i = 0; i < 10; i++) @@ -135,7 +231,7 @@ TEST(SE2, betweenVectorsReturn) pd = between(p1, p2); - ASSERT_MATRIX_APPROX(pd, Eigen::Vector3d::Zero(), 1e-8); + ASSERT_MATRIX_APPROX(pd, Vector3d::Zero(), 1e-8); } // random relative pose