123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- #include <iostream>
- #include <sophus/so2.hpp>
- #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<Sophus::SO2<double>>;
- template class Map<Sophus::SO2<double> const>;
- } // namespace Eigen
- namespace Sophus {
- template class SO2<double, Eigen::AutoAlign>;
- template class SO2<float, Eigen::DontAlign>;
- #if SOPHUS_CERES
- template class SO2<ceres::Jet<double, 3>>;
- #endif
- template <class Scalar>
- class Tests {
- public:
- using SO2Type = SO2<Scalar>;
- using Point = typename SO2<Scalar>::Point;
- using Tangent = typename SO2<Scalar>::Tangent;
- Scalar const kPi = Constants<Scalar>::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<SO2Type> 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<Scalar>::epsilon(), "Magnitude drift");
- return passed;
- }
- bool testRawDataAcces() {
- bool passed = true;
- Vector2<Scalar> raw = {0, 1};
- Eigen::Map<SO2Type const> map_of_const_so2(raw.data());
- SOPHUS_TEST_APPROX(passed, map_of_const_so2.unit_complex().eval(), raw,
- Constants<Scalar>::epsilon());
- SOPHUS_TEST_EQUAL(passed, map_of_const_so2.unit_complex().data(),
- raw.data());
- Eigen::Map<SO2Type const> 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<Scalar> raw2 = {1, 0};
- Eigen::Map<SO2Type> map_of_so2(raw.data());
- map_of_so2.setComplex(raw2);
- SOPHUS_TEST_APPROX(passed, map_of_so2.unit_complex().eval(), raw2,
- Constants<Scalar>::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<SO2Type> 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<Scalar> data1 = {1, 0}, data2 = {0, 1};
- Eigen::Map<SO2Type> 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<Scalar> R = so2_vec_.front().matrix();
- SO2Type so2(R);
- SOPHUS_TEST_APPROX(passed, R, so2.matrix(), Constants<Scalar>::epsilon());
- return passed;
- }
- template <class S = Scalar>
- enable_if_t<std::is_floating_point<S>::value, bool> testFit() {
- bool passed = true;
- for (int i = 0; i < 100; ++i) {
- Matrix2<Scalar> R = Matrix2<Scalar>::Random();
- SO2Type so2 = SO2Type::fitToSO2(R);
- SO2Type so2_2 = SO2Type::fitToSO2(so2.matrix());
- SOPHUS_TEST_APPROX(passed, so2.matrix(), so2_2.matrix(),
- Constants<Scalar>::epsilon());
- }
- return passed;
- }
- template <class S = Scalar>
- enable_if_t<!std::is_floating_point<S>::value, bool> testFit() {
- return true;
- }
- std::vector<SO2Type, Eigen::aligned_allocator<SO2Type>> so2_vec_;
- std::vector<Tangent, Eigen::aligned_allocator<Tangent>> tangent_vec_;
- std::vector<Point, Eigen::aligned_allocator<Point>> point_vec_;
- };
- int test_so2() {
- using std::cerr;
- using std::endl;
- cerr << "Test SO2" << endl << endl;
- cerr << "Double tests: " << endl;
- Tests<double>().runAll();
- cerr << "Float tests: " << endl;
- Tests<float>().runAll();
- #if SOPHUS_CERES
- cerr << "ceres::Jet<double, 3> tests: " << endl;
- Tests<ceres::Jet<double, 3>>().runAll();
- #endif
- return 0;
- }
- } // namespace Sophus
- int main() { return Sophus::test_so2(); }
|