Main MRPT website > C++ reference
MRPT logo
CNetworkOfPoses.h
Go to the documentation of this file.
00001 /* +---------------------------------------------------------------------------+
00002    |          The Mobile Robot Programming Toolkit (MRPT) C++ library          |
00003    |                                                                           |
00004    |                       http://www.mrpt.org/                                |
00005    |                                                                           |
00006    |   Copyright (C) 2005-2011  University of Malaga                           |
00007    |                                                                           |
00008    |    This software was written by the Machine Perception and Intelligent    |
00009    |      Robotics Lab, University of Malaga (Spain).                          |
00010    |    Contact: Jose-Luis Blanco  <jlblanco@ctima.uma.es>                     |
00011    |                                                                           |
00012    |  This file is part of the MRPT project.                                   |
00013    |                                                                           |
00014    |     MRPT is free software: you can redistribute it and/or modify          |
00015    |     it under the terms of the GNU General Public License as published by  |
00016    |     the Free Software Foundation, either version 3 of the License, or     |
00017    |     (at your option) any later version.                                   |
00018    |                                                                           |
00019    |   MRPT is distributed in the hope that it will be useful,                 |
00020    |     but WITHOUT ANY WARRANTY; without even the implied warranty of        |
00021    |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
00022    |     GNU General Public License for more details.                          |
00023    |                                                                           |
00024    |     You should have received a copy of the GNU General Public License     |
00025    |     along with MRPT.  If not, see <http://www.gnu.org/licenses/>.         |
00026    |                                                                           |
00027    +---------------------------------------------------------------------------+ */
00028 #ifndef CONSTRAINED_POSE_NETWORK_H
00029 #define CONSTRAINED_POSE_NETWORK_H
00030 
00031 #include <mrpt/poses/CPosePDFGaussian.h>
00032 #include <mrpt/poses/CPose3DPDFGaussian.h>
00033 #include <mrpt/poses/CPosePDFGaussianInf.h>
00034 #include <mrpt/poses/CPose3DPDFGaussianInf.h>
00035 #include <mrpt/graphs/CDirectedGraph.h>
00036 #include <mrpt/graphs/CDirectedTree.h>
00037 
00038 #include <mrpt/utils/CSerializable.h>
00039 #include <mrpt/utils/CFileGZInputStream.h>
00040 #include <mrpt/utils/CFileGZOutputStream.h>
00041 
00042 #include <mrpt/utils/traits_map.h>
00043 #include <mrpt/utils/stl_extensions.h>
00044 
00045 #include <mrpt/graphs/link_pragmas.h>
00046 
00047 // The main class in this file is CNetworkOfPoses, a generic basic template for
00048 //  predefined 2D/3D graphs of pose contraints.
00049 namespace mrpt
00050 {
00051         namespace graphs
00052         {
00053                 using mrpt::utils::TNodeID;
00054                 using namespace mrpt::utils;
00055 
00056                 /** Internal functions for MRPT */
00057                 namespace detail
00058                 {
00059                         template <class GRAPH_T> struct graph_ops;
00060 //                      template<class GRAPH_T> void save_graph_of_poses_from_text_file(const GRAPH_T *g, const std::string &fil);
00061 //                      template<class GRAPH_T> void load_graph_of_poses_from_text_file(GRAPH_T* g, const std::string &fil);
00062 //                      template<class GRAPH_T> void graph_of_poses_dijkstra_init(GRAPH_T *g);
00063 //                      template<class GRAPH_T> size_t graph_of_poses_collapse_dup_edges(GRAPH_T *g);
00064 //                      template<class GRAPH_T> double graph_edge_sqerror(const GRAPH_T *g, const typename mrpt::graphs::CDirectedGraph<typename GRAPH_T::constraint_t>::edges_map_t::const_iterator &itEdge, bool ignoreCovariances );
00065 
00066                         /** An empty structure */
00067                         struct node_annotations_empty {  };
00068                 }
00069 
00070                 /** A directed graph of pose constraints, with edges being the relative pose between pairs of nodes indentified by their numeric IDs (of type TNodeID).
00071                   *  A link or edge between two nodes "i" and "j", that is, the pose \f$ p_{ij} \f$, holds the relative position of "j" with respect to "i".
00072                   *   These poses are stored in the edges in the format specified by the template argument CPOSE. Users should employ the following derived classes
00073                   *   depending on the desired representation of edges:
00074                   *      - mrpt::graphs::CNetworkOfPoses2D    : 2D edges as a simple CPose2D (x y phi)
00075                   *      - mrpt::graphs::CNetworkOfPoses3D    : 3D edges as a simple CPose3D (x y z yaw pitch roll)
00076                   *      - mrpt::graphs::CNetworkOfPoses2DInf : 2D edges as a Gaussian PDF with information matrix ( CPosePDFGaussianInf )
00077                   *      - mrpt::graphs::CNetworkOfPoses3DInf : 3D edges as a Gaussian PDF with information matrix ( CPose3DPDFGaussianInf )
00078                   *      - mrpt::graphs::CNetworkOfPoses2DCov : 2D edges as a Gaussian PDF with covariance matrix ( CPosePDFGaussian ). It's more efficient to use the information matrix version instead!
00079                   *      - mrpt::graphs::CNetworkOfPoses3DCov : 3D edges as a Gaussian PDF with covariance matrix ( CPose3DPDFGaussian ). It's more efficient to use the information matrix version instead!
00080                   *
00081                   *  Two main members store all the information in this class:
00082                   *             - \a edge  (in the base class mrpt::graphs::CDirectedGraph::edge): A map from pairs of node ID -> pose constraints.
00083                   *             - \a nodes : A map from node ID -> estimated pose of that node (actually, read below on the template argument MAPS_IMPLEMENTATION).
00084                   *
00085                   *  Graphs can be loaded and saved to text file in the format used by TORO & HoG-man (more on the format <a href="http://www.mrpt.org/Robotics_file_formats" >here</a> ),
00086                   *   using \a loadFromTextFile and \a saveToTextFile.
00087                   *
00088                   *  This class is the base for representing networks of poses, which are the main data type of a series
00089                   *   of SLAM algorithms implemented in the library mrpt-slam, in the namespace mrpt::graphslam.
00090                   *
00091                   *  For tools to visualize graphs as 2D/3D plots, see the namespace mrpt::opengl::graph_tools in the library mrpt-opengl.
00092                   *
00093                   *  The template arguments are:
00094                   *             - CPOSE: The type of the edges, which hold a relative pose (2D/3D, just a value or a Gaussian, etc.)
00095                   *             - MAPS_IMPLEMENTATION: Can be either mrpt::utils::map_traits_stdmap or mrpt::utils::map_traits_map_as_vector. Determines the type of the list of global poses (member \a nodes).
00096                   *
00097                   * \sa mrpt::graphslam
00098                   * \ingroup mrpt_graphs_grp
00099                   */
00100                 template<
00101                         class CPOSE, // Type of edges
00102                         class MAPS_IMPLEMENTATION = map_traits_stdmap, // Use std::map<> vs. std::vector<>
00103                         class NODE_ANNOTATIONS = mrpt::graphs::detail::node_annotations_empty,
00104                         class EDGE_ANNOTATIONS = mrpt::graphs::detail::edge_annotations_empty
00105                         >
00106                 class CNetworkOfPoses : public mrpt::graphs::CDirectedGraph< CPOSE, EDGE_ANNOTATIONS >
00107                 {
00108                 public:
00109                         /** @name Typedef's
00110                             @{ */
00111                         typedef mrpt::graphs::CDirectedGraph<CPOSE,EDGE_ANNOTATIONS> BASE;      //!< The base class "CDirectedGraph<CPOSE,EDGE_ANNOTATIONS>" */
00112                         typedef CNetworkOfPoses<CPOSE,MAPS_IMPLEMENTATION,NODE_ANNOTATIONS,EDGE_ANNOTATIONS> self_t; //!< My own type
00113 
00114                         typedef CPOSE              constraint_t;        //!< The type of PDF poses in the contraints (edges) (=CPOSE template argument)
00115                         typedef NODE_ANNOTATIONS   node_annotations_t;  //!< The extra annotations in nodes, apart from a \a constraint_no_pdf_t
00116                         typedef EDGE_ANNOTATIONS   edge_annotations_t;  //!< The extra annotations in edges, apart from a \a constraint_t
00117 
00118                         typedef MAPS_IMPLEMENTATION         maps_implementation_t; //!< The type of map's implementation (=MAPS_IMPLEMENTATION template argument)
00119                         typedef typename CPOSE::type_value  constraint_no_pdf_t;   //!< The type of edges or their means if they are PDFs (that is, a simple "edge" value)
00120 
00121                         /** The type of each global pose in \a nodes: an extension of the \a constraint_no_pdf_t pose with any optional user-defined data */
00122                         struct global_pose_t : public constraint_no_pdf_t, public NODE_ANNOTATIONS
00123                         {
00124                                 // Replicate possible constructors:
00125                                 inline global_pose_t() : constraint_no_pdf_t() { }
00126                                 template <typename ARG1> inline global_pose_t(const ARG1 &a1) : constraint_no_pdf_t(a1) { }
00127                                 template <typename ARG1,typename ARG2> inline global_pose_t(const ARG1 &a1,const ARG2 &a2) : constraint_no_pdf_t(a1,a2) { }
00128                         };
00129 
00130                         /** A map from pose IDs to their global coordinates estimates, with uncertainty */
00131                         typedef typename MAPS_IMPLEMENTATION::template map<TNodeID,CPOSE>     global_poses_pdf_t;
00132 
00133                         /** A map from pose IDs to their global coordinates estimates, without uncertainty (the "most-likely value") */
00134                         typedef typename MAPS_IMPLEMENTATION::template map<TNodeID,global_pose_t> global_poses_t;
00135 
00136                         /** @} */
00137 
00138 
00139                         /** @name Data members
00140                             @{ */
00141 
00142                         /** The nodes (vertices) of the graph, with their estimated "global" (with respect to \a root) position, without an associated covariance.
00143                           * \sa dijkstra_nodes_estimate
00144                           */
00145                         global_poses_t  nodes;
00146 
00147                         /** The ID of the node that is the origin of coordinates, used as reference by all coordinates in \nodes. By default, root is the ID "0". */
00148                         TNodeID         root;
00149 
00150                         /** False (default) if an edge i->j stores the normal relative pose of j as seen from i: \f$ \Delta_i^j = j \ominus i \f$
00151                           * True if an edge i->j stores the inverse relateive pose, that is, i as seen from j: \f$ \Delta_i^j = i \ominus j \f$
00152                           */
00153                         bool            edges_store_inverse_poses;
00154 
00155                         /** @} */
00156 
00157 
00158                         /** @name I/O file methods
00159                             @{ */
00160 
00161                         /** Saves to a text file in the format used by TORO & HoG-man (more on the format <a href="http://www.mrpt.org/Robotics_file_formats" >here</a> )
00162                           *  For 2D graphs only VERTEX2 & EDGE2 entries will be saved, and VERTEX3 & EDGE3 entries for 3D graphs.
00163                           *  Note that EQUIV entries will not be saved, but instead several EDGEs will be stored between the same node IDs.
00164                           * \sa saveToBinaryFile, loadFromTextFile
00165                           * \exception On any error
00166                           */
00167                         inline void saveToTextFile( const std::string &fileName ) const {
00168                                 detail::graph_ops<self_t>::save_graph_of_poses_from_text_file(this,fileName);
00169                         }
00170 
00171                         /** Loads from a text file in the format used by TORO & HoG-man (more on the format <a href="http://www.mrpt.org/Robotics_file_formats" >here</a> )
00172                           *   Recognized line entries are: VERTEX2, VERTEX3, EDGE2, EDGE3, EQUIV.
00173                           *   If an unknown entry is found, a warning is dumped to std::cerr (only once for each unknown keyword).
00174                           *   An exception will be raised if trying to load a 3D graph into a 2D class (in the opposite case, missing 3D data will default to zero).
00175                           * \param fileName The file to load.
00176                           * \param collapse_dup_edges If true, \a collapseDuplicatedEdges will be called automatically after loading (note that this operation may take significant time for very large graphs).
00177                           * \sa loadFromBinaryFile, saveToTextFile
00178                           * \exception On any error, as a malformed line or loading a 3D graph in a 2D graph.
00179                           */
00180                         inline void loadFromTextFile( const std::string &fileName, bool collapse_dup_edges = true ) {
00181                                 detail::graph_ops<self_t>::load_graph_of_poses_from_text_file(this,fileName);
00182                                 if (collapse_dup_edges) this->collapseDuplicatedEdges();
00183                         }
00184 
00185                         /** @} */
00186 
00187                         /** @name Utility methods
00188                             @{ */
00189 
00190                         /** Spanning tree computation of a simple estimation of the global coordinates of each node just from the information in all edges, sorted in a Dijkstra tree based on the current "root" node.
00191                           *  Note that "global" coordinates are with respect to the node with the ID specified in \a root.
00192                           * \note This method takes into account the value of \a edges_store_inverse_poses
00193                           * \sa node, root
00194                           */
00195                         inline void dijkstra_nodes_estimate() { detail::graph_ops<self_t>::graph_of_poses_dijkstra_init(this); }
00196 
00197                         /** Look for duplicated edges (even in opposite directions) between all pairs of nodes and fuse them.
00198                           *  Upon return, only one edge remains between each pair of nodes with the mean & covariance (or information matrix) corresponding to the Bayesian fusion of all the Gaussians.
00199                           * \return Overall number of removed edges.
00200                           */
00201                         inline size_t collapseDuplicatedEdges() { return detail::graph_ops<self_t>::graph_of_poses_collapse_dup_edges(this); }
00202 
00203                         /** Computes the overall square error from all the pose constraints (edges) with respect to the global poses in \nodes
00204                           *  If \a ignoreCovariances is false, the squared Mahalanobis distance will be computed instead of the straight square error.
00205                           * \sa getEdgeSquareError
00206                           * \exception std::exception On global poses not in \a nodes
00207                           */
00208                         double getGlobalSquareError(bool ignoreCovariances = true) const {
00209                                 double sqErr=0;
00210                                 const typename BASE::edges_map_t::const_iterator last_it=BASE::edges.end();
00211                                 for (typename BASE::edges_map_t::const_iterator itEdge=BASE::edges.begin();itEdge!=last_it;++itEdge)
00212                                         sqErr+=detail::graph_ops<self_t>::graph_edge_sqerror(this,itEdge,ignoreCovariances);
00213                                 return sqErr;
00214                         }
00215 
00216                         /** Computes the square error of one pose constraints (edge) with respect to the global poses in \nodes
00217                           *  If \a ignoreCovariances is false, the squared Mahalanobis distance will be computed instead of the straight square error.
00218                           * \exception std::exception On global poses not in \a nodes
00219                           */
00220                         inline double getEdgeSquareError(const typename BASE::edges_map_t::const_iterator &itEdge, bool ignoreCovariances = true) const { return detail::graph_ops<self_t>::graph_edge_sqerror(this,itEdge,ignoreCovariances); }
00221 
00222                         /** Computes the square error of one pose constraints (edge) with respect to the global poses in \nodes
00223                           *  If \a ignoreCovariances is false, the squared Mahalanobis distance will be computed instead of the straight square error.
00224                           * \exception std::exception On edge not existing or global poses not in \a nodes
00225                           */
00226                         double getEdgeSquareError(const TNodeID from_id, const TNodeID to_id, bool ignoreCovariances = true ) const
00227                         {
00228                                 const typename BASE::edges_map_t::const_iterator itEdge = BASE::edges.find( std::make_pair(from_id,to_id) );
00229                                 ASSERTMSG_(itEdge!=BASE::edges.end(),format("Request for edge %u->%u that doesn't exist in graph.",static_cast<unsigned int>(from_id),static_cast<unsigned int>(to_id)));
00230                                 return getEdgeSquareError(itEdge,ignoreCovariances);
00231                         }
00232 
00233                         /** Empty all edges, nodes and set root to ID 0. */
00234                         inline void clear() {
00235                                 BASE::edges.clear();
00236                                 nodes.clear();
00237                                 root = 0;
00238                                 edges_store_inverse_poses = false;
00239                         }
00240 
00241                         /** Return number of nodes in the list \nodes of global coordinates (may be differente that all nodes appearing in edges)
00242                           * \sa mrpt::graphs::CDirectedGraph::countDifferentNodesInEdges
00243                           */
00244                         inline size_t nodeCount() const { return nodes.size(); }
00245 
00246                         /**  @} */
00247 
00248                         /** @name Ctors & Dtors
00249                             @{ */
00250 
00251                         /** Default constructor (just sets root to "0" and edges_store_inverse_poses to "false") */
00252                         inline CNetworkOfPoses() : root(0), edges_store_inverse_poses(false) { }
00253                         ~CNetworkOfPoses() { }
00254                         /** @} */
00255                 };
00256 
00257 #define DEFINE_SERIALIZABLE_GRAPH  \
00258                 protected: \
00259                         virtual void  writeToStream(CStream &out, int *version) const { \
00260                                 if (version) *version = 0; \
00261                                 else out << nodes << edges << root;  \
00262                         } \
00263                         virtual void readFromStream(CStream &in, int version) { \
00264                                 switch(version) \
00265                                 { \
00266                                 case 0: { in >> nodes >> edges >> root; } break; \
00267                                 default: MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(version) \
00268                                 }; \
00269                         }
00270 
00271 
00272 
00273                 /** \addtogroup mrpt_graphs_grp
00274                     @{ */
00275 
00276                 // Define serializable versions of the template above for each specific kind of "edge":
00277 
00278                 // This must be added to any CSerializable derived class:
00279                 DEFINE_SERIALIZABLE_PRE_CUSTOM_LINKAGE( CNetworkOfPoses2D, GRAPHS_IMPEXP )
00280                 DEFINE_SERIALIZABLE_PRE_CUSTOM_LINKAGE( CNetworkOfPoses3D, GRAPHS_IMPEXP )
00281                 DEFINE_SERIALIZABLE_PRE_CUSTOM_LINKAGE( CNetworkOfPoses2DCov, GRAPHS_IMPEXP )
00282                 DEFINE_SERIALIZABLE_PRE_CUSTOM_LINKAGE( CNetworkOfPoses3DCov, GRAPHS_IMPEXP )
00283                 DEFINE_SERIALIZABLE_PRE_CUSTOM_LINKAGE( CNetworkOfPoses2DInf, GRAPHS_IMPEXP )
00284                 DEFINE_SERIALIZABLE_PRE_CUSTOM_LINKAGE( CNetworkOfPoses3DInf, GRAPHS_IMPEXP )
00285 
00286                 /** The specialization of CNetworkOfPoses for poses of type CPose2D (not a PDF!), also implementing serialization.
00287                   * \sa CNetworkOfPoses, CNetworkOfPoses2D, CNetworkOfPoses3D, CNetworkOfPoses2DInf, CNetworkOfPoses3DInf
00288                   */
00289                 class GRAPHS_IMPEXP CNetworkOfPoses2D : public CNetworkOfPoses<CPose2D,map_traits_stdmap>, public mrpt::utils::CSerializable
00290                 {
00291                         DEFINE_MRPT_OBJECT( CNetworkOfPoses2D ) // Should be DEFINE_SERIALIZABLE but the next macro defines what that macro only declared.
00292                         DEFINE_SERIALIZABLE_GRAPH
00293                 };
00294 
00295                 /** The specialization of CNetworkOfPoses for poses of type CPose3D (not a PDF!), also implementing serialization.
00296                   * \sa CNetworkOfPoses, CNetworkOfPoses2D, CNetworkOfPoses3D, CNetworkOfPoses2DInf, CNetworkOfPoses3DInf
00297                   */
00298                 class GRAPHS_IMPEXP CNetworkOfPoses3D : public CNetworkOfPoses<CPose3D,map_traits_stdmap>, public mrpt::utils::CSerializable
00299                 {
00300                         DEFINE_MRPT_OBJECT( CNetworkOfPoses3D ) // Should be DEFINE_SERIALIZABLE but the next macro defines what that macro only declared.
00301                         DEFINE_SERIALIZABLE_GRAPH
00302                 };
00303 
00304                 /** The specialization of CNetworkOfPoses for poses of type CPosePDFGaussian, also implementing serialization.
00305                   * \sa CNetworkOfPoses, CNetworkOfPoses2D, CNetworkOfPoses3D, CNetworkOfPoses2DInf, CNetworkOfPoses3DInf
00306                   */
00307                 class GRAPHS_IMPEXP CNetworkOfPoses2DCov : public CNetworkOfPoses<CPosePDFGaussian,map_traits_stdmap>, public mrpt::utils::CSerializable
00308                 {
00309                         DEFINE_MRPT_OBJECT( CNetworkOfPoses2DCov )      // Should be DEFINE_SERIALIZABLE but the next macro defines what that macro only declared.
00310                         DEFINE_SERIALIZABLE_GRAPH
00311                 };
00312 
00313                 /** The specialization of CNetworkOfPoses for poses of type CPose3DPDFGaussian, also implementing serialization.
00314                   * \sa CNetworkOfPoses, CNetworkOfPoses2D, CNetworkOfPoses3D, CNetworkOfPoses2DInf, CNetworkOfPoses3DInf
00315                   */
00316                 class GRAPHS_IMPEXP CNetworkOfPoses3DCov : public CNetworkOfPoses<CPose3DPDFGaussian,map_traits_stdmap>, public mrpt::utils::CSerializable
00317                 {
00318                         DEFINE_MRPT_OBJECT( CNetworkOfPoses3DCov )      // Should be DEFINE_SERIALIZABLE but the next macro defines what that macro only declared.
00319                         DEFINE_SERIALIZABLE_GRAPH
00320                 };
00321 
00322                 /** The specialization of CNetworkOfPoses for poses of type CPosePDFGaussianInf, also implementing serialization.
00323                   * \sa CNetworkOfPoses, CNetworkOfPoses2D, CNetworkOfPoses3D, CNetworkOfPoses2DInf, CNetworkOfPoses3DInf
00324                   */
00325                 class GRAPHS_IMPEXP CNetworkOfPoses2DInf : public CNetworkOfPoses<CPosePDFGaussianInf,map_traits_stdmap>, public mrpt::utils::CSerializable
00326                 {
00327                         DEFINE_MRPT_OBJECT( CNetworkOfPoses2DInf )      // Should be DEFINE_SERIALIZABLE but the next macro defines what that macro only declared.
00328                         DEFINE_SERIALIZABLE_GRAPH
00329                 };
00330 
00331                 /** The specialization of CNetworkOfPoses for poses of type CPose3DPDFGaussianInf, also implementing serialization.
00332                   * \sa CNetworkOfPoses, CNetworkOfPoses2D, CNetworkOfPoses3D, CNetworkOfPoses2DInf, CNetworkOfPoses3DInf
00333                   */
00334                 class GRAPHS_IMPEXP CNetworkOfPoses3DInf : public CNetworkOfPoses<CPose3DPDFGaussianInf,map_traits_stdmap>, public mrpt::utils::CSerializable
00335                 {
00336                         DEFINE_MRPT_OBJECT( CNetworkOfPoses3DInf )      // Should be DEFINE_SERIALIZABLE but the next macro defines what that macro only declared.
00337                         DEFINE_SERIALIZABLE_GRAPH
00338                 };
00339 
00340                 /** @} */  // end of grouping
00341         } // End of namespace
00342 } // End of namespace
00343 
00344 
00345 // Implementation of templates (in a separate file for clarity)
00346 #include "CNetworkOfPoses_impl.h"
00347 
00348 #endif



Page generated by Doxygen 1.7.5 for MRPT 0.9.5 SVN: at Thu Oct 13 21:25:36 UTC 2011