From c72ef7f2295e74ea1eed1c6e26bfa4caf61b618f Mon Sep 17 00:00:00 2001 From: joanvallve <jvallve@iri.upc.edu> Date: Tue, 6 Feb 2024 11:38:02 +0100 Subject: [PATCH] hotfixes --- include/core/landmark/landmark_external.h | 24 ++- .../processor/processor_landmark_external.h | 4 +- src/landmark/landmark_base.cpp | 192 +++++++++++++++++- src/landmark/landmark_external.cpp | 9 +- src/processor/processor_landmark_external.cpp | 2 +- test/gtest_processor_landmark_external.cpp | 36 ++-- 6 files changed, 242 insertions(+), 25 deletions(-) diff --git a/include/core/landmark/landmark_external.h b/include/core/landmark/landmark_external.h index 3ff6df805..a96c9bc5e 100644 --- a/include/core/landmark/landmark_external.h +++ b/include/core/landmark/landmark_external.h @@ -56,12 +56,32 @@ class LandmarkExternal : public LandmarkBase * Caution: This creator does not set the landmark's anchor frame and sensor. * These need to be set afterwards. */ - static LandmarkExternalPtr create(const YAML::Node& _node); + static LandmarkBasePtr create(const YAML::Node& _node); void setExternalId(const int& _external_id); int getExternalId() const; - void setExternalType(const int& _external_id); + void setExternalType(const int& _external_type); int getExternalType() const; }; +void LandmarkExternal::setExternalId(const int& _external_id) +{ + external_id_ = _external_id; +} + +int LandmarkExternal::getExternalId() const +{ + return external_id_; +} + +void LandmarkExternal::setExternalType(const int& _external_type) +{ + external_type_ = _external_type; +} + +int LandmarkExternal::getExternalType() const +{ + return external_type_; +} + } // namespace wolf diff --git a/include/core/processor/processor_landmark_external.h b/include/core/processor/processor_landmark_external.h index 917b53fab..06d0f1103 100644 --- a/include/core/processor/processor_landmark_external.h +++ b/include/core/processor/processor_landmark_external.h @@ -129,13 +129,13 @@ class ProcessorLandmarkExternal : public ProcessorTracker /** \brief Emplaces a landmark or modifies (if needed) a landmark * \param _feature_ptr pointer to the Feature */ - LandmarkExternalPtr emplaceLandmark(FeatureExternalPtr _feature_ptr); + LandmarkExternalPtr emplaceLandmark(FeatureLandmarkExternalPtr _feature_ptr); /** \brief Modifies (if needed) a landmark * \param _landmark pointer to the landmark * \param _feature pointer to the Feature. */ - void modifyLandmark(LandmarkExternalPtr _landmark, FeatureExternalPtr _feature); + void modifyLandmark(LandmarkExternalPtr _landmark, FeatureLandmarkExternalPtr _feature); /** Post-process * diff --git a/src/landmark/landmark_base.cpp b/src/landmark/landmark_base.cpp index 4ce1c2c26..7bec4d89f 100644 --- a/src/landmark/landmark_base.cpp +++ b/src/landmark/landmark_base.cpp @@ -51,6 +51,44 @@ LandmarkBase::LandmarkBase(const std::string& _type, StateBlockPtr _p_ptr, State } +LandmarkBase::~LandmarkBase() +{ + removeStateBlocks(getProblem()); +} + +void LandmarkBase::remove(bool viral_remove_empty_parent) +{ + /* Order of removing: + * Factors are removed first, and afterwards the rest of nodes containing state blocks. + * In case multi-threading, solver can be called while removing. + * This order avoids SolverManager to ignore notifications (efficiency) + */ + if (!is_removing_) + { + is_removing_ = true; + LandmarkBasePtr this_L = shared_from_this(); // keep this alive while removing it + + // remove constrained by + while (!constrained_by_list_.empty()) + { + constrained_by_list_.front()->remove(viral_remove_empty_parent); + } + + // Remove State Blocks + removeStateBlocks(getProblem()); + + // remove from upstream + auto M = map_ptr_.lock(); + if (M) + M->removeLandmark(this_L); + } +} + +bool LandmarkBase::getCovariance(Eigen::MatrixXd& _cov) const +{ + return getProblem()->getLandmarkCovariance(shared_from_this(), _cov); +} + YAML::Node LandmarkBase::saveToYaml() const { YAML::Node node; @@ -70,6 +108,70 @@ YAML::Node LandmarkBase::saveToYaml() const return node; } +void LandmarkBase::link(MapBasePtr _map_ptr) +{ + assert(!is_removing_ && "linking a removed landmark"); + assert(this->getMap() == nullptr && "linking an already linked landmark"); + + if(_map_ptr) + { + this->setMap(_map_ptr); + _map_ptr->addLandmark(shared_from_this()); + this->setProblem(_map_ptr->getProblem()); + } + else + { + WOLF_WARN("Linking with nullptr"); + } +} + +void LandmarkBase::setProblem(ProblemPtr _problem) +{ + if (_problem == nullptr || _problem == this->getProblem()) + return; + + NodeBase::setProblem(_problem); + registerNewStateBlocks(_problem); +} + +FactorBasePtr LandmarkBase::addConstrainedBy(FactorBasePtr _fac_ptr) +{ + constrained_by_list_.push_back(_fac_ptr); + return _fac_ptr; +} + +void LandmarkBase::removeConstrainedBy(FactorBasePtr _fac_ptr) +{ + constrained_by_list_.remove(_fac_ptr); +} + +bool LandmarkBase::isConstrainedBy(const FactorBaseConstPtr &_factor) const +{ + return std::find(constrained_by_list_.begin(), + constrained_by_list_.end(), + _factor) != constrained_by_list_.end(); +} + +void LandmarkBase::printHeader(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + _stream << _tabs << "Lmk" << id() << " " << getType(); + if (_constr_by) + { + _stream << "\t<-- "; + for (auto cby : getConstrainedByList()) + if (cby) + _stream << "Fac" << cby->id() << " \t"; + } + _stream << std::endl; + + printState(_metric, _state_blocks, _stream, _tabs); +} + +void LandmarkBase::print(int _depth, bool _constr_by, bool _metric, bool _state_blocks, std::ostream& _stream, std::string _tabs) const +{ + printHeader(_depth, _constr_by, _metric, _state_blocks, _stream, _tabs); +} + LandmarkBasePtr LandmarkBase::create(const YAML::Node& _node) { unsigned int id = _node["id"] .as< unsigned int >(); @@ -96,10 +198,98 @@ LandmarkBasePtr LandmarkBase::create(const YAML::Node& _node) return lmk; } +CheckLog LandmarkBase::localCheck(bool _verbose, LandmarkBaseConstPtr _lmk_ptr, std::ostream& _stream, std::string _tabs) const +{ + CheckLog log; + std::stringstream inconsistency_explanation; + + if (_verbose) + { + _stream << _tabs << "Lmk" << id() << " @ " << _lmk_ptr.get() << std::endl; + _stream << _tabs << " -> Prb @ " << getProblem().get() << std::endl; + _stream << _tabs << " -> Map @ " << getMap().get() << std::endl; + for (auto pair : getStateBlockMap()) + { + auto sb = pair.second; + _stream << _tabs << " " << pair.first << " sb @ " << sb.get(); + if (sb) + { + auto lp = sb->getLocalParametrization(); + if (lp) + _stream << " (lp @ " << lp.get() << ")"; + } + _stream << std::endl; + } + } + + auto map_ptr = getMap(); + // check problem and map pointers + inconsistency_explanation << "Landmarks' problem ptr " + << getProblem().get() << " different from Map's problem ptr " + << map_ptr->getProblem().get() << "\n"; + + log.assertTrue((getProblem() == map_ptr->getProblem()), inconsistency_explanation); + + // check constrained-by factors + for (auto cby : getConstrainedByList()) + { + if (_verbose) + { + _stream << _tabs << " " << "<- Fac" << cby->id() << " ->"; + + for (auto Low : cby->getLandmarkOtherList()) + { + if (!Low.expired()) + { + auto Lo = Low.lock(); + _stream << " Lmk" << Lo->id(); + } + } + _stream << std::endl; + } + + inconsistency_explanation << "constrained-by landmark " << id() << " @ " << _lmk_ptr.get() + << " not found among constrained-by factors\n"; + log.assertTrue((cby->hasLandmarkOther(_lmk_ptr)), inconsistency_explanation); + + for (auto sb : cby->getStateBlockPtrVector()) { + if (_verbose) { + _stream << _tabs << " " << "sb @ " << sb.get(); + if (sb) { + auto lp = sb->getLocalParametrization(); + if (lp) + _stream << " (lp @ " << lp.get() << ")"; + } + _stream << std::endl; + } + } + } + + // check map + inconsistency_explanation << "Lmk" << id() << " @ " << _lmk_ptr + << " ---> Map" << map_ptr + << " -X-> Lmk" << id(); + auto map_lmk_list = map_ptr->getLandmarkList(); + auto map_has_lmk = std::find(map_lmk_list.begin(), + map_lmk_list.end(), + _lmk_ptr); + log.assertTrue(map_has_lmk != map_lmk_list.end(), inconsistency_explanation); + + return log; +} +bool LandmarkBase::check(CheckLog& _log, NodeBaseConstPtr _node_ptr, bool _verbose, std::ostream& _stream, std::string _tabs) const +{ + auto lmk_ptr = std::static_pointer_cast<const LandmarkBase>(_node_ptr); + auto local_log = localCheck(_verbose, lmk_ptr, _stream, _tabs); + _log.compose(local_log); + + return _log.is_consistent_; +} + // Register landmark creator namespace { -const bool WOLF_UNUSED registered_lmk_external = FactoryLandmark::registerCreator("LandmarkExternal", LandmarkExternal::create); +const bool WOLF_UNUSED registered_lmk_base = FactoryLandmark::registerCreator("LandmarkBase", LandmarkBase::create); } } // namespace wolf diff --git a/src/landmark/landmark_external.cpp b/src/landmark/landmark_external.cpp index 3dd8334a5..8bbd6eaa6 100644 --- a/src/landmark/landmark_external.cpp +++ b/src/landmark/landmark_external.cpp @@ -21,6 +21,11 @@ //--------LICENSE_END-------- #include "core/landmark/landmark_external.h" +#include "core/state_block/state_block_derived.h" +#include "core/state_block/state_angle.h" +#include "core/state_block/state_quaternion.h" +#include "core/state_block/factory_state_block.h" +#include "core/yaml/yaml_conversion.h" namespace wolf { @@ -28,7 +33,7 @@ namespace wolf LandmarkExternal::LandmarkExternal(const int& _external_id, const int& _external_type, StateBlockPtr _p_ptr, - StateBlockPtr _o_ptr = nullptr) + StateBlockPtr _o_ptr) : LandmarkBase("LandmarkExternal", _p_ptr, _o_ptr), external_id_(_external_id), external_type_(_external_type) { assert(external_id_ >= 0 or external_id_ == -1); @@ -70,7 +75,7 @@ LandmarkBasePtr LandmarkExternal::create(const YAML::Node& _node) // Register landmark creator namespace { -const bool WOLF_UNUSED registered_lmk_base = +const bool WOLF_UNUSED registered_lmk_external = FactoryLandmark::registerCreator("LandmarkExternal", LandmarkExternal::create); } diff --git a/src/processor/processor_landmark_external.cpp b/src/processor/processor_landmark_external.cpp index fe9f4f6bf..f12dffc60 100644 --- a/src/processor/processor_landmark_external.cpp +++ b/src/processor/processor_landmark_external.cpp @@ -497,7 +497,7 @@ FactorBasePtr ProcessorLandmarkExternal::emplaceFactor(FeatureBasePtr _feature, return nullptr; // not going to happen } -LandmarkExternalPtr ProcessorLandmarkExternal::emplaceLandmark(FeatureExternalPtr _feature) +LandmarkExternalPtr ProcessorLandmarkExternal::emplaceLandmark(FeatureLandmarkExternalPtr _feature) { assert(_feature); assert(_feature->getCapture()); diff --git a/test/gtest_processor_landmark_external.cpp b/test/gtest_processor_landmark_external.cpp index 1e43f1618..b3278fc86 100644 --- a/test/gtest_processor_landmark_external.cpp +++ b/test/gtest_processor_landmark_external.cpp @@ -23,7 +23,7 @@ #include "core/utils/utils_gtest.h" #include "core/problem/problem.h" #include "core/capture/capture_landmarks_external.h" -#include "core/landmark/landmark_base.h" +#include "core/landmark/landmark_external.h" #include "core/sensor/sensor_odom_2d.h" #include "core/sensor/sensor_odom_3d.h" #include "core/processor/processor_odom_2d.h" @@ -51,12 +51,12 @@ class ProcessorLandmarkExternalTest : public testing::Test TimeStamp t; double dt; - ProblemPtr problem; - SolverManagerPtr solver; - SensorBasePtr sensor, sensor_odom; - ProcessorLandmarkExternalPtr processor; - ProcessorMotionPtr processor_motion; - std::vector<LandmarkBasePtr> landmarks; + ProblemPtr problem; + SolverManagerPtr solver; + SensorBasePtr sensor, sensor_odom; + ProcessorLandmarkExternalPtr processor; + ProcessorMotionPtr processor_motion; + std::vector<LandmarkExternalPtr> landmarks; // Groundtruth states VectorComposite state_robot, state_sensor; @@ -171,21 +171,22 @@ void ProcessorLandmarkExternalTest::initProblem(int _dim, // Emplace 3 random landmarks for (auto i = 0; i < 3; i++) { - LandmarkBasePtr lmk; + LandmarkExternalPtr lmk; if (dim == 2) - lmk = LandmarkBase::emplace<LandmarkBase>( + lmk = LandmarkBase::emplace<LandmarkExternal>( _init_landmarks ? problem->getMap() : nullptr, - (orientation ? "LandmarkPose2d" : "LandmarkPosition2d"), + i + 1, + i + 1, std::make_shared<StatePoint2d>(Vector2d::Random() * 10), (orientation ? std::make_shared<StateAngle>(Vector1d::Random() * M_PI) : nullptr)); else - lmk = LandmarkBase::emplace<LandmarkBase>( + lmk = LandmarkBase::emplace<LandmarkExternal>( _init_landmarks ? problem->getMap() : nullptr, - (orientation ? "LandmarkPose3d" : "LandmarkPosition3d"), + i + 1, + i + 1, std::make_shared<StatePoint3d>(Vector3d::Random() * 10), (orientation ? std::make_shared<StateQuaternion>(Vector4d::Random().normalized()) : nullptr)); - lmk->setExternalId(i + 1); // TODO LandmarkExternal landmarks.push_back(lmk); state_landmarks.push_back(lmk->getState()); } @@ -373,9 +374,9 @@ void ProcessorLandmarkExternalTest::testConfiguration(int _dim, // check state correctly initialized for (auto lmk_map : landmarks_map) { - ASSERT_TRUE(lmk_map->id() <= landmarks.size()); - ASSERT_EQ(lmk_map->id(), landmarks.at(lmk_map->id() - 1)->id()); - assertVectorComposite(lmk_map->getState(), state_landmarks.at(lmk_map->id() - 1)); + auto lmk_ext = std::static_pointer_cast<LandmarkExternal>(lmk_map); + ASSERT_EQ(lmk_ext->getExternalId(), landmarks.at(lmk_ext->getExternalId() - 1)->getExternalId()); + assertVectorComposite(lmk_map->getState(), state_landmarks.at(lmk_ext->getExternalId() - 1)); } } } @@ -409,7 +410,8 @@ void ProcessorLandmarkExternalTest::testConfiguration(int _dim, // check values for (auto lmk_map : problem->getMap()->getLandmarkList()) { - assertVectorComposite(lmk_map->getState(), state_landmarks.at(lmk_map->id() - 1)); + auto lmk_ext = std::static_pointer_cast<LandmarkExternal>(lmk_map); + assertVectorComposite(lmk_map->getState(), state_landmarks.at(lmk_ext->getExternalId() - 1)); } } } -- GitLab