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 |