/* ---------------------------------------------------------------------------- * GTSAM Copyright 2010, Georgia Tech Research Corporation, * Atlanta, Georgia 30332-0415 * All Rights Reserved * Authors: Frank Dellaert, et al. (see THANKS for the full author list) * See LICENSE for the license information * -------------------------------------------------------------------------- */ /** * @file BetweenFactor.h * @author Frank Dellaert, Viorela Ila **/ #pragma once #include #include #include #include namespace gtsam { /** * A class for a measurement predicted by "between(config[key1],config[key2])" * @tparam POSE the Pose type * @ingroup slam */ template class PoseBetweenFactor: public NoiseModelFactorN { private: typedef PoseBetweenFactor This; typedef NoiseModelFactorN Base; POSE measured_; /** The measurement */ std::optional body_P_sensor_; ///< The pose of the sensor in the body frame /** concept check by type */ GTSAM_CONCEPT_TESTABLE_TYPE(POSE) GTSAM_CONCEPT_POSE_TYPE(POSE) public: // Provide access to the Matrix& version of evaluateError: using Base::evaluateError; // shorthand for a smart pointer to a factor typedef typename std::shared_ptr shared_ptr; /** default constructor - only use for serialization */ PoseBetweenFactor() {} /** Constructor */ PoseBetweenFactor(Key key1, Key key2, const POSE& measured, const SharedNoiseModel& model, std::optional body_P_sensor = {}) : Base(model, key1, key2), measured_(measured), body_P_sensor_(body_P_sensor) { } ~PoseBetweenFactor() override {} /// @return a deep copy of this factor gtsam::NonlinearFactor::shared_ptr clone() const override { return std::static_pointer_cast( gtsam::NonlinearFactor::shared_ptr(new This(*this))); } /** implement functions needed for Testable */ /** print */ void print(const std::string& s, const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override { std::cout << s << "BetweenFactor(" << keyFormatter(this->key1()) << "," << keyFormatter(this->key2()) << ")\n"; measured_.print(" measured: "); if(this->body_P_sensor_) this->body_P_sensor_->print(" sensor pose in body frame: "); this->noiseModel_->print(" noise model: "); } /** equals */ bool equals(const NonlinearFactor& expected, double tol=1e-9) const override { const This *e = dynamic_cast (&expected); return e != nullptr && Base::equals(*e, tol) && this->measured_.equals(e->measured_, tol) && ((!body_P_sensor_ && !e->body_P_sensor_) || (body_P_sensor_ && e->body_P_sensor_ && body_P_sensor_->equals(*e->body_P_sensor_))); } /** implement functions needed to derive from Factor */ /** vector of errors */ Vector evaluateError(const POSE& p1, const POSE& p2, OptionalMatrixType H1, OptionalMatrixType H2) const override { if(body_P_sensor_) { POSE hx; if(H1 || H2) { Matrix H3; hx = p1.compose(*body_P_sensor_,H3).between(p2.compose(*body_P_sensor_), H1, H2); // h(x) if(H1) (*H1) *= H3; if(H2) (*H2) *= H3; } else { hx = p1.compose(*body_P_sensor_).between(p2.compose(*body_P_sensor_)); // h(x) } // manifold equivalent of h(x)-z -> log(z,h(x)) return measured_.localCoordinates(hx); } else { POSE hx = p1.between(p2, H1, H2); // h(x) // manifold equivalent of h(x)-z -> log(z,h(x)) return measured_.localCoordinates(hx); } } /** return the measured */ const POSE& measured() const { return measured_; } private: #if GTSAM_ENABLE_BOOST_SERIALIZATION /** Serialization function */ friend class boost::serialization::access; template void serialize(ARCHIVE & ar, const unsigned int /*version*/) { ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base); ar & BOOST_SERIALIZATION_NVP(measured_); } #endif }; // \class PoseBetweenFactor } /// namespace gtsam