#include #include #include "tests.hpp" // Explicit instantiate all class templates so that all member methods // get compiled and for code coverage analysis. namespace Eigen { template class Map>; template class Map const>; } // namespace Eigen namespace Sophus { template class SO2; template class SO2; #if SOPHUS_CERES template class SO2>; #endif template class Tests { public: using SO2Type = SO2; using Point = typename SO2::Point; using Tangent = typename SO2::Tangent; Scalar const kPi = Constants::pi(); Tests() { so2_vec_.push_back(SO2Type::exp(Scalar(0.0))); so2_vec_.push_back(SO2Type::exp(Scalar(0.2))); so2_vec_.push_back(SO2Type::exp(Scalar(10.))); so2_vec_.push_back(SO2Type::exp(Scalar(0.00001))); so2_vec_.push_back(SO2Type::exp(kPi)); so2_vec_.push_back(SO2Type::exp(Scalar(0.2)) * SO2Type::exp(kPi) * SO2Type::exp(Scalar(-0.2))); so2_vec_.push_back(SO2Type::exp(Scalar(-0.3)) * SO2Type::exp(kPi) * SO2Type::exp(Scalar(0.3))); tangent_vec_.push_back(Tangent(Scalar(0))); tangent_vec_.push_back(Tangent(Scalar(1))); tangent_vec_.push_back(Tangent(Scalar(kPi / 2.))); tangent_vec_.push_back(Tangent(Scalar(-1))); tangent_vec_.push_back(Tangent(Scalar(20))); tangent_vec_.push_back(Tangent(Scalar(kPi / 2. + 0.0001))); point_vec_.push_back(Point(Scalar(1), Scalar(2))); point_vec_.push_back(Point(Scalar(1), Scalar(-3))); } void runAll() { bool passed = testLieProperties(); passed &= testUnity(); passed &= testRawDataAcces(); passed &= testConstructors(); passed &= testFit(); processTestResult(passed); } private: bool testLieProperties() { LieGroupTests tests(so2_vec_, tangent_vec_, point_vec_); return tests.doAllTestsPass(); } bool testUnity() { bool passed = true; // Test that the complex number magnitude stays close to one. SO2Type current_q; for (std::size_t i = 0; i < 1000; ++i) { for (SO2Type const& q : so2_vec_) { current_q *= q; } } SOPHUS_TEST_APPROX(passed, current_q.unit_complex().norm(), Scalar(1), Constants::epsilon(), "Magnitude drift"); return passed; } bool testRawDataAcces() { bool passed = true; Vector2 raw = {0, 1}; Eigen::Map map_of_const_so2(raw.data()); SOPHUS_TEST_APPROX(passed, map_of_const_so2.unit_complex().eval(), raw, Constants::epsilon()); SOPHUS_TEST_EQUAL(passed, map_of_const_so2.unit_complex().data(), raw.data()); Eigen::Map const_shallow_copy = map_of_const_so2; SOPHUS_TEST_EQUAL(passed, const_shallow_copy.unit_complex().eval(), map_of_const_so2.unit_complex().eval()); Vector2 raw2 = {1, 0}; Eigen::Map map_of_so2(raw.data()); map_of_so2.setComplex(raw2); SOPHUS_TEST_APPROX(passed, map_of_so2.unit_complex().eval(), raw2, Constants::epsilon()); SOPHUS_TEST_EQUAL(passed, map_of_so2.unit_complex().data(), raw.data()); SOPHUS_TEST_NEQ(passed, map_of_so2.unit_complex().data(), raw2.data()); Eigen::Map shallow_copy = map_of_so2; SOPHUS_TEST_EQUAL(passed, shallow_copy.unit_complex().eval(), map_of_so2.unit_complex().eval()); SO2Type const const_so2(raw2); for (int i = 0; i < 2; ++i) { SOPHUS_TEST_EQUAL(passed, const_so2.data()[i], raw2.data()[i]); } SO2Type so2(raw2); for (int i = 0; i < 2; ++i) { so2.data()[i] = raw[i]; } for (int i = 0; i < 2; ++i) { SOPHUS_TEST_EQUAL(passed, so2.data()[i], raw.data()[i]); } Vector2 data1 = {1, 0}, data2 = {0, 1}; Eigen::Map map1(data1.data()), map2(data2.data()); // map -> map assignment map2 = map1; SOPHUS_TEST_EQUAL(passed, map1.matrix(), map2.matrix()); // map -> type assignment SO2Type copy; copy = map1; SOPHUS_TEST_EQUAL(passed, map1.matrix(), copy.matrix()); // type -> map assignment copy = SO2Type(Scalar(0.5)); map1 = copy; SOPHUS_TEST_EQUAL(passed, map1.matrix(), copy.matrix()); return passed; } bool testConstructors() { bool passed = true; Matrix2 R = so2_vec_.front().matrix(); SO2Type so2(R); SOPHUS_TEST_APPROX(passed, R, so2.matrix(), Constants::epsilon()); return passed; } template enable_if_t::value, bool> testFit() { bool passed = true; for (int i = 0; i < 100; ++i) { Matrix2 R = Matrix2::Random(); SO2Type so2 = SO2Type::fitToSO2(R); SO2Type so2_2 = SO2Type::fitToSO2(so2.matrix()); SOPHUS_TEST_APPROX(passed, so2.matrix(), so2_2.matrix(), Constants::epsilon()); } return passed; } template enable_if_t::value, bool> testFit() { return true; } std::vector> so2_vec_; std::vector> tangent_vec_; std::vector> point_vec_; }; int test_so2() { using std::cerr; using std::endl; cerr << "Test SO2" << endl << endl; cerr << "Double tests: " << endl; Tests().runAll(); cerr << "Float tests: " << endl; Tests().runAll(); #if SOPHUS_CERES cerr << "ceres::Jet tests: " << endl; Tests>().runAll(); #endif return 0; } } // namespace Sophus int main() { return Sophus::test_so2(); }