Main MRPT website > C++ reference for MRPT 1.9.9
CNetworkOfPoses.h
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 #ifndef CONSTRAINED_POSE_NETWORK_H
10 #define CONSTRAINED_POSE_NETWORK_H
11 
12 /** \file The main class in this file is mrpt::poses::CNetworkOfPoses<>, a
13  generic
14  basic template for predefined 2D/3D graphs of pose contraints.
15 */
16 
17 #include <iostream>
18 
24 #include <mrpt/utils/TParameters.h>
25 #include <mrpt/utils/traits_map.h>
27 #include <mrpt/math/utils.h>
28 #include <mrpt/poses/poses_frwds.h>
29 #include <mrpt/system/os.h>
31 #include <mrpt/graphs/dijkstra.h>
35 
36 #include <iterator>
37 #include <algorithm>
38 #include <type_traits> // is_base_of()
39 #include <memory>
40 
41 namespace mrpt
42 {
43 namespace graphs
44 {
45 /** Internal functions for MRPT */
46 namespace detail
47 {
48 template <class GRAPH_T>
49 struct graph_ops;
50 
51 // forward declaration of CVisualizer
52 template <class CPOSE, // Type of edges
53  class MAPS_IMPLEMENTATION, class NODE_ANNOTATIONS,
54  class EDGE_ANNOTATIONS>
56 // forward declaration of CMRVisualizer
57 template <class CPOSE, // Type of edges
58  class MAPS_IMPLEMENTATION, class NODE_ANNOTATIONS,
59  class EDGE_ANNOTATIONS>
60 class CMRVisualizer;
61 }
62 
63 /** A directed graph of pose constraints, with edges being the relative poses
64  *between pairs of nodes identified by their numeric IDs (of type
65  *mrpt::utils::TNodeID).
66  * A link or edge between two nodes "i" and "j", that is, the pose \f$ p_{ij}
67  *\f$, holds the relative position of "j" with respect to "i".
68  * These poses are stored in the edges in the format specified by the template
69  *argument CPOSE. Users should employ the following derived classes
70  * depending on the desired representation of edges:
71  * - mrpt::graphs::CNetworkOfPoses2D : 2D edges as a simple CPose2D (x y
72  *phi)
73  * - mrpt::graphs::CNetworkOfPoses3D : 3D edges as a simple
74  *mrpt::poses::CPose3D (x y z yaw pitch roll)
75  * - mrpt::graphs::CNetworkOfPoses2DInf : 2D edges as a Gaussian PDF with
76  *information matrix (CPosePDFGaussianInf)
77  * - mrpt::graphs::CNetworkOfPoses3DInf : 3D edges as a Gaussian PDF with
78  *information matrix (CPose3DPDFGaussianInf)
79  * - mrpt::graphs::CNetworkOfPoses2DCov : 2D edges as a Gaussian PDF with
80  *covariance matrix (CPosePDFGaussian). It's more efficient to use the
81  *information matrix version instead!
82  * - mrpt::graphs::CNetworkOfPoses3DCov : 3D edges as a Gaussian PDF with
83  *covariance matrix (CPose3DPDFGaussian). It's more efficient to use the
84  *information matrix version instead!
85  *
86  * Two main members store all the information in this class:
87  * - \a edges (in the base class mrpt::graphs::CDirectedGraph::edges): A
88  *map
89  *from pairs of node ID -> pose constraints.
90  * - \a nodes : A map from node ID -> estimated pose of that node
91  *(actually,
92  *read below on the template argument MAPS_IMPLEMENTATION).
93  *
94  * Graphs can be loaded and saved to text file in the format used by TORO &
95  *HoG-man (more on the format <a
96  *href="http://www.mrpt.org/Robotics_file_formats" >here</a>),
97  * using \a loadFromTextFile and \a saveToTextFile.
98  *
99  * This class is the base for representing networks of poses, which are the
100  *main data type of a series
101  * of SLAM algorithms implemented in the library mrpt-slam, in the namespace
102  *mrpt::graphslam.
103  *
104  * The template arguments are:
105  * - CPOSE: The type of the edges, which hold a relative pose (2D/3D, just
106  *a
107  *value or a Gaussian, etc.)
108  * - MAPS_IMPLEMENTATION: Can be either mrpt::utils::map_traits_stdmap or
109  *mrpt::utils::map_traits_map_as_vector. Determines the type of the list of
110  *global poses (member \a nodes).
111  *
112  * \sa mrpt::graphslam
113  * \ingroup mrpt_graphs_grp
114  */
115 template <
116  class CPOSE, // Type of edges
117  class MAPS_IMPLEMENTATION =
118  mrpt::utils::map_traits_stdmap, // Use std::map<> vs. std::vector<>
119  class NODE_ANNOTATIONS = mrpt::graphs::detail::TNodeAnnotationsEmpty,
120  class EDGE_ANNOTATIONS = mrpt::graphs::detail::edge_annotations_empty>
122  : public mrpt::graphs::CDirectedGraph<CPOSE, EDGE_ANNOTATIONS>
123 {
124  public:
125  /** @name Typedef's
126  @{ */
127  /** The base class "CDirectedGraph<CPOSE,EDGE_ANNOTATIONS>" */
129  /** My own type */
130  typedef CNetworkOfPoses<CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS,
131  EDGE_ANNOTATIONS>
133 
134  /** The type of PDF poses in the contraints (edges) (=CPOSE template
135  * argument) */
136  typedef CPOSE constraint_t;
137  /** The extra annotations in nodes, apart from a \a constraint_no_pdf_t */
138  typedef NODE_ANNOTATIONS node_annotations_t;
139  /** The extra annotations in edges, apart from a \a constraint_t */
140  typedef EDGE_ANNOTATIONS edge_annotations_t;
141 
142  /** The type of map's implementation (=MAPS_IMPLEMENTATION template
143  * argument) */
144  typedef MAPS_IMPLEMENTATION maps_implementation_t;
145  /** The type of edges or their means if they are PDFs (that is, a simple
146  * "edge" value) */
147  typedef typename CPOSE::type_value constraint_no_pdf_t;
148 
149  /** The type of each global pose in \a nodes: an extension of the \a
150  * constraint_no_pdf_t pose with any optional user-defined data
151  */
152  struct global_pose_t : public constraint_no_pdf_t, public NODE_ANNOTATIONS
153  {
154  typedef
155  typename CNetworkOfPoses<CPOSE, MAPS_IMPLEMENTATION,
156  NODE_ANNOTATIONS,
157  EDGE_ANNOTATIONS>::global_pose_t self_t;
158 
159  /**\brief Potential class constructors
160  */
161  /**\{ */
163  template <typename ARG1>
164  inline global_pose_t(const ARG1& a1) : constraint_no_pdf_t(a1)
165  {
166  }
167  template <typename ARG1, typename ARG2>
168  inline global_pose_t(const ARG1& a1, const ARG2& a2)
170  {
171  }
172  /**\} */
173 
174  /**\brief Copy constructor - delegate copying to the NODE_ANNOTATIONS
175  * struct
176  */
177  inline global_pose_t(const global_pose_t& other)
178  : constraint_no_pdf_t(other), NODE_ANNOTATIONS(other)
179  {
180  }
181 
182  inline bool operator==(const global_pose_t& other) const
183  {
184  return (
185  static_cast<const constraint_no_pdf_t>(*this) ==
186  static_cast<const constraint_no_pdf_t>(other) &&
187  static_cast<const NODE_ANNOTATIONS>(*this) ==
188  static_cast<const NODE_ANNOTATIONS>(other));
189  }
190  inline bool operator!=(const global_pose_t& other) const
191  {
192  return (!(*this == other));
193  }
194 
195  inline friend std::ostream& operator<<(
196  std::ostream& o, const self_t& global_pose)
197  {
198  o << global_pose.asString() << "| "
199  << global_pose.retAnnotsAsString();
200  return o;
201  }
202  };
203 
204  /** A map from pose IDs to their global coordinate estimates, with
205  * uncertainty */
206  typedef
207  typename MAPS_IMPLEMENTATION::template map<mrpt::utils::TNodeID, CPOSE>
209 
210  /** A map from pose IDs to their global coordinate estimates, without
211  * uncertainty (the "most-likely value") */
212  typedef typename MAPS_IMPLEMENTATION::template map<mrpt::utils::TNodeID,
215 
216  /** @} */
217 
218  /** @name Data members
219  @{ */
220 
221  /** The nodes (vertices) of the graph, with their estimated "global"
222  * (with respect to \a root) position, without an associated covariance.
223  * \sa dijkstra_nodes_estimate
224  */
226 
227  /** The ID of the node that is the origin of coordinates, used as
228  * reference by all coordinates in \a nodes. By default, root is the ID
229  * "0". */
231 
232  /** False (default) if an edge i->j stores the normal relative pose of j
233  * as seen from i: \f$ \Delta_i^j = j \ominus i \f$ True if an edge i->j
234  * stores the inverse relateive pose, that is, i as seen from j: \f$
235  * \Delta_i^j = i \ominus j \f$
236  */
238 
239  /** @} */
240 
241  /** @name I/O file methods
242  @{ */
243 
244  /** Saves to a text file in the format used by TORO & HoG-man (more on
245  * the format <a href="http://www.mrpt.org/Robotics_file_formats" *
246  * >here</a>)
247  * For 2D graphs only VERTEX2 & EDGE2 entries will be saved,
248  * and VERTEX3 & EDGE3 entries for 3D graphs. Note that EQUIV entries
249  * will not be saved, but instead several EDGEs will be stored between
250  * the same node IDs.
251  *
252  * \sa saveToBinaryFile, loadFromTextFile
253  * \exception On any error
254  */
255  inline void saveToTextFile(const std::string& fileName) const
256  {
258  this, fileName);
259  }
260 
261  /** Loads from a text file in the format used by TORO & HoG-man (more on the
262  * format <a href="http://www.mrpt.org/Robotics_file_formats" >here</a>)
263  * Recognized line entries are: VERTEX2, VERTEX3, EDGE2, EDGE3, EQUIV.
264  * If an unknown entry is found, a warning is dumped to std::cerr (only
265  * once for each unknown keyword).
266  * An exception will be raised if trying to load a 3D graph into a 2D
267  * class (in the opposite case, missing 3D data will default to zero).
268  *
269  * \param[in] fileName The file to load.
270  * \param[in] collapse_dup_edges If true, \a collapseDuplicatedEdges will be
271  * called automatically after loading (note that this operation may take
272  * significant time for very large graphs).
273  *
274  * \sa loadFromBinaryFile, saveToTextFile
275  *
276  * \exception On any error, as a malformed line or loading a 3D graph in
277  * a 2D graph.
278  */
279  inline void loadFromTextFile(
280  const std::string& fileName, bool collapse_dup_edges = true)
281  {
283  this, fileName);
284  if (collapse_dup_edges) this->collapseDuplicatedEdges();
285  }
286 
287  /** @} */
288 
289  /** @name Utility methods
290  @{ */
291  /**\brief Return 3D Visual Representation of the edges and nodes in the
292  * network of poses
293  *
294  * Method makes the call to the corresponding method of the CVisualizer
295  * class instance.
296  */
297  inline void getAs3DObject(
299  const mrpt::utils::TParametersDouble& viz_params) const
300  {
301  using visualizer_t = mrpt::graphs::detail::CVisualizer<
302  CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>;
303  using visualizer_multirobot_t = mrpt::graphs::detail::CMRVisualizer<
304  CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>;
305 
306  bool is_multirobot = false;
307  std::unique_ptr<visualizer_t> viz;
308  is_multirobot =
311  if (is_multirobot)
312  {
313  viz.reset(new visualizer_multirobot_t(*this));
314  }
315  else
316  {
317  viz.reset(new visualizer_t(*this));
318  }
319  viz->getAs3DObject(object, viz_params);
320  }
321 
322  /** Spanning tree computation of a simple estimation of the global
323  * coordinates of each node just from the information in all edges,
324  * sorted in a Dijkstra tree based on the current "root" node.
325  *
326  * \note The "global" coordinates are with respect to the node with the
327  * ID specified in \a root.
328  *
329  * \note This method takes into account the
330  * value of \a edges_store_inverse_poses
331  *
332  * \sa node, root
333  */
335  {
337  }
338 
339  /** Look for duplicated edges (even in opposite directions) between all
340  * pairs of nodes and fuse them. Upon return, only one edge remains
341  * between each pair of nodes with the mean & covariance (or information
342  * matrix) corresponding to the Bayesian fusion of all the Gaussians.
343  *
344  * \return Overall number of removed edges.
345  */
346  inline size_t collapseDuplicatedEdges()
347  {
349  this);
350  }
351 
352  /** Computes the overall square error from all the pose constraints (edges)
353  * with respect to the global poses in \a nodes
354  * If \a ignoreCovariances is false, the squared Mahalanobis distance will
355  * be computed instead of the straight square error.
356  * \sa getEdgeSquareError
357  * \exception std::exception On global poses not in \a nodes
358  */
359  double getGlobalSquareError(bool ignoreCovariances = true) const
360  {
361  double sqErr = 0;
362  const typename BASE::edges_map_t::const_iterator last_it =
363  BASE::edges.end();
364  for (typename BASE::edges_map_t::const_iterator itEdge =
365  BASE::edges.begin();
366  itEdge != last_it; ++itEdge)
368  this, itEdge, ignoreCovariances);
369  return sqErr;
370  }
371 
372  /**\brief Find the edges between the nodes in the node_IDs set and fill
373  * given graph pointer accordingly.
374  *
375  * \param[in] node_IDs Set of nodes, between which, edges should be found
376  * and inserted in the given sub_graph pointer
377  * \param[in] root_node_in Node ID to be used as the root node of
378  * sub_graph. If this is not given, the lowest nodeID is to be used.
379  * \param[out] CNetworkOfPoses pointer that is to be filled.
380  *
381  * \param[in] auto_expand_set If true and in case the node_IDs set
382  * contains non-consecutive nodes the returned set is expanded with the
383  * in-between nodes. This makes sure that the final graph is always
384  * connected.
385  * If auto_expand_set is false but there exist
386  * non-consecutive nodes, virtual edges are inserted in the parts that
387  * the graph is not connected
388  */
390  const std::set<TNodeID>& node_IDs, self_t* sub_graph,
391  const TNodeID root_node_in = INVALID_NODEID,
392  const bool& auto_expand_set = true) const
393  {
394  using namespace std;
395  using namespace mrpt;
396  using namespace mrpt::math;
397  using namespace mrpt::graphs::detail;
398 
399  typedef CDijkstra<self_t, MAPS_IMPLEMENTATION> dijkstra_t;
400 
401  // assert that the given pointers are valid
402  ASSERTMSG_(
403  sub_graph,
404  "\nInvalid pointer to a CNetworkOfPoses instance is given. "
405  "Exiting..\n");
406  sub_graph->clear();
407 
408  // assert that the root_node actually exists in the given node_IDs set
409  TNodeID root_node = root_node_in;
410  if (root_node != INVALID_NODEID)
411  {
412  ASSERTMSG_(
413  node_IDs.find(root_node) != node_IDs.end(),
414  "\nRoot_node does not exist in the given node_IDs set. "
415  "Exiting.\n");
416  }
417 
418  // ask for at least 2 nodes
419  ASSERTMSG_(
420  node_IDs.size() >= 2,
421  format(
422  "Very few nodes [%lu] for which to extract a subgraph. "
423  "Exiting\n",
424  static_cast<unsigned long>(node_IDs.size())));
425 
426  // find out if querry contains non-consecutive nodes.
427  // Assumption: Set elements are in standard, ascending order.
428  bool is_fully_connected_graph = true;
429  std::set<TNodeID> node_IDs_real; // actual set of nodes to be used.
430  if (*node_IDs.rbegin() - *node_IDs.begin() + 1 == node_IDs.size())
431  {
432  node_IDs_real = node_IDs;
433  }
434  else
435  { // contains non-consecutive nodes
436  is_fully_connected_graph = false;
437 
438  if (auto_expand_set)
439  { // set auto-expansion
440  for (TNodeID curr_node_ID = *node_IDs.begin();
441  curr_node_ID != *node_IDs.rbegin(); ++curr_node_ID)
442  {
443  node_IDs_real.insert(curr_node_ID);
444  }
445  }
446  else
447  { // virtual_edge_addition strategy
448  node_IDs_real = node_IDs;
449  }
450  }
451 
452  // add all the nodes of the node_IDs_real set to sub_graph
453  for (std::set<TNodeID>::const_iterator node_IDs_it =
454  node_IDs_real.begin();
455  node_IDs_it != node_IDs_real.end(); ++node_IDs_it)
456  {
457  // assert that current node exists in *own* graph
458  typename global_poses_t::const_iterator own_it;
459  for (own_it = nodes.begin(); own_it != nodes.end(); ++own_it)
460  {
461  if (*node_IDs_it == own_it->first)
462  {
463  break; // I throw exception afterwards
464  }
465  }
466  ASSERTMSG_(
467  own_it != nodes.end(),
468  format(
469  "NodeID [%lu] can't be found in the initial graph.",
470  static_cast<unsigned long>(*node_IDs_it)));
471 
472  global_pose_t curr_node(nodes.at(*node_IDs_it));
473  sub_graph->nodes.insert(make_pair(*node_IDs_it, curr_node));
474  }
475  // cout << "Extracting subgraph for nodeIDs: " <<
476  // getSTLContainerAsString(node_IDs_real) << endl;
477 
478  // set the root of the extracted graph
479  if (root_node == INVALID_NODEID)
480  {
481  // smallest nodeID by default
482  // http://stackoverflow.com/questions/1342045/how-do-i-find-the-largest-int-in-a-stdsetint
483  // std::set sorts elements in ascending order
484  root_node = sub_graph->nodes.begin()->first;
485  }
486  sub_graph->root = root_node;
487 
488  // TODO - Remove these lines - not needed
489  // set the corresponding root pose
490  // sub_graph->nodes.at(sub_graph->root) = nodes.at(sub_graph->root);
491 
492  // find all edges (in the initial graph), that exist in the given set
493  // of nodes; add them to the given graph
494  sub_graph->clearEdges();
495  for (typename BASE::const_iterator it = BASE::edges.begin();
496  it != BASE::edges.end(); ++it)
497  {
498  const TNodeID& from = it->first.first;
499  const TNodeID& to = it->first.second;
500  const typename BASE::edge_t& curr_edge = it->second;
501 
502  // if both nodes exist in the given set, add the corresponding edge
503  if (sub_graph->nodes.find(from) != sub_graph->nodes.end() &&
504  sub_graph->nodes.find(to) != sub_graph->nodes.end())
505  {
506  sub_graph->insertEdge(from, to, curr_edge);
507  }
508  }
509 
510  if (!auto_expand_set && !is_fully_connected_graph)
511  {
512  // Addition of virtual edges between non-connected graph parts is
513  // necessary
514 
515  // make sure that the root nodeID is connected to at least one node
516  {
517  std::set<TNodeID> root_neighbors;
518  sub_graph->getNeighborsOf(sub_graph->root, root_neighbors);
519 
520  if (root_neighbors.empty())
521  {
522  // add an edge between the root and an adjacent nodeID
523  typename global_poses_t::iterator root_it =
524  sub_graph->nodes.find(sub_graph->root);
525  ASSERT_(root_it != sub_graph->nodes.end());
526  if ((*root_it == *sub_graph->nodes.rbegin()))
527  { // is the last nodeID
528  // add with previous node
529  TNodeID next_to_root = (--root_it)->first;
531  sub_graph, next_to_root, sub_graph->root);
532  // cout << "next_to_root = " << next_to_root;
533  }
534  else
535  {
536  TNodeID next_to_root = (++root_it)->first;
537  // cout << "next_to_root = " << next_to_root;
539  sub_graph, sub_graph->root, next_to_root);
540  }
541  }
542  }
543 
544  // as long as the graph is unconnected (as indicated by Dijkstra)
545  // add a virtual edge between
546  bool dijkstra_runs_successfully = false;
547 
548  // loop until the graph is fully connected (i.e. I can reach every
549  // node of the graph starting from its root)
550  while (!dijkstra_runs_successfully)
551  {
552  try
553  {
554  dijkstra_t dijkstra(*sub_graph, sub_graph->root);
555  dijkstra_runs_successfully = true;
556  }
558  {
559  dijkstra_runs_successfully = false;
560 
561  set<TNodeID> unconnected_nodeIDs;
562  ex.getUnconnectedNodeIDs(&unconnected_nodeIDs);
563  // cout << "Unconnected nodeIDs: " <<
564  // mrpt::math::getSTLContainerAsString(unconnected_nodeIDs)
565  // << endl;
566  // mainland: set of nodes that the root nodeID is in
567  // island: set of nodes that the Dijkstra graph traversal
568  // can't
569  // reach starting from the root.
570  // [!] There may be multiple sets of these nodes
571 
572  // set::rend() is the element with the highest value
573  // set::begin() is the element with the lowest value
574  const TNodeID& island_highest =
575  *unconnected_nodeIDs.rbegin();
576  const TNodeID& island_lowest = *unconnected_nodeIDs.begin();
577  // cout << "island_highest: " << island_highest << endl;
578  // cout << "island_lowest: " << island_lowest << endl;
579  // cout << "root: " << sub_graph->root << endl;
580 
581  // find out which nodes are in the same partition with the
582  // root
583  // (i.e. mainland)
584  std::set<TNodeID> mainland;
585  // for all nodes in sub_graph
586  for (typename global_poses_t::const_iterator n_it =
587  sub_graph->nodes.begin();
588  n_it != sub_graph->nodes.end(); ++n_it)
589  {
590  bool is_there = false;
591 
592  // for all unconnected nodes
594  uncon_it = unconnected_nodeIDs.begin();
595  uncon_it != unconnected_nodeIDs.end(); ++uncon_it)
596  {
597  if (n_it->first == *uncon_it)
598  {
599  is_there = true;
600  break;
601  }
602  }
603 
604  if (!is_there)
605  {
606  mainland.insert(n_it->first);
607  }
608  }
609 
610  bool is_single_island =
611  (island_highest - island_lowest + 1 ==
612  unconnected_nodeIDs.size());
613 
614  if (is_single_island)
615  { // single island
616  // Possible scenarios:
617  // | island |
618  // | mainland |
619  // | <low nodeIDs> island_highest| --- <virtual_edge>
620  // --->> | mainland_lowest <high nodeIDs> ... root ...|
621  // --- OR ---
622  // | mainland |
623  // | island |
624  // | <low nodeIDs> mainland_highest| ---
625  // <virtual_edge> --->> | island_lowest <high nodeIDs>
626  // |
627 
628  const std::set<TNodeID>& island = unconnected_nodeIDs;
630  sub_graph, island, mainland);
631  }
632  else
633  { // multiple islands
634  // add a virtual edge between the last group before the
635  // mainland and the mainland
636 
637  // split the unconnected_nodeIDs to smaller groups of
638  // nodes
639  // we only care about the nodes that are prior to the
640  // root
641  std::vector<std::set<TNodeID>> vec_of_islands;
642  std::set<TNodeID> curr_island;
643  TNodeID prev_nodeID = *unconnected_nodeIDs.begin();
644  curr_island.insert(
645  prev_nodeID); // add the initial node;
647  ++unconnected_nodeIDs.begin();
648  *it < sub_graph->root &&
649  it != unconnected_nodeIDs.end();
650  ++it)
651  {
652  if (!(absDiff(*it, prev_nodeID) == 1))
653  {
654  vec_of_islands.push_back(curr_island);
655  curr_island.clear();
656  }
657  curr_island.insert(*it);
658 
659  // update the previous nodeID
660  prev_nodeID = *it;
661  }
662  vec_of_islands.push_back(curr_island);
663 
664  // cout << "last_island: " <<
665  // getSTLContainerAsString(vec_of_islands.back()) <<
666  // endl;
667  // cout << "mainland: " <<
668  // getSTLContainerAsString(mainland) << endl;
670  sub_graph, vec_of_islands.back(), mainland);
671  }
672  }
673  }
674  }
675 
676  // estimate the node positions according to the edges - root is (0, 0,
677  // 0)
678  // just execute dijkstra once for grabbing the updated node positions.
679  sub_graph->dijkstra_nodes_estimate();
680 
681  } // end of extractSubGraph
682 
683  /**\brief Integrate given graph into own graph using the list of provided
684  * common THypotheses. Nodes of the other graph are renumbered upon
685  * integration in own graph.
686  *
687  * \param[in] other Graph (of the same type) that is to be integrated with
688  * own graph.
689  * \param[in] Hypotheses that join own and other graph.
690  * \param[in] hypots_from_other_to_self Specify the direction of the
691  * THypothesis objects in the common_hypots. If true (default) they are
692  * directed from other to own graph (other \rightarrow own),
693  *
694  * \param[out] old_to_new_nodeID_mappings_out Map from the old nodeIDs
695  * that are in the given graph to the new nodeIDs that have been inserted
696  * (by this method) in own graph.
697  */
698  inline void mergeGraph(
699  const self_t& other,
700  const typename std::vector<detail::THypothesis<self_t>>& common_hypots,
701  const bool hypots_from_other_to_self = true,
702  std::map<TNodeID, TNodeID>* old_to_new_nodeID_mappings_out = NULL)
703  {
704  MRPT_START;
705  using namespace mrpt::graphs;
706  using namespace mrpt::utils;
707  using namespace mrpt::graphs::detail;
708  using namespace std;
709 
710  typedef
711  typename vector<THypothesis<self_t>>::const_iterator hypots_cit_t;
712  typedef typename global_poses_t::const_iterator nodes_cit_t;
713 
714  const self_t& graph_from = (hypots_from_other_to_self ? other : *this);
715  const self_t& graph_to = (hypots_from_other_to_self ? *this : other);
716 
717  // assert that both own and other graph have at least two nodes.
718  ASSERT_(graph_from.nodes.size() >= 2);
719  ASSERT_(graph_to.nodes.size() >= 2);
720 
721  // Assert that from-nodeIds, to-nodeIDs in common_hypots exist in own
722  // and other graph respectively
723  for (hypots_cit_t h_cit = common_hypots.begin();
724  h_cit != common_hypots.end(); ++h_cit)
725  {
726  ASSERTMSG_(
727  graph_from.nodes.find(h_cit->from) != graph_from.nodes.end(),
728  format("NodeID %lu is not found in (from) graph", h_cit->from))
729  ASSERTMSG_(
730  graph_to.nodes.find(h_cit->to) != graph_to.nodes.end(),
731  format("NodeID %lu is not found in (to) graph", h_cit->to))
732  }
733 
734  // find the max nodeID in existing graph
735  TNodeID max_nodeID = 0;
736  for (nodes_cit_t n_cit = this->nodes.begin();
737  n_cit != this->nodes.end(); ++n_cit)
738  {
739  if (n_cit->first > max_nodeID)
740  {
741  max_nodeID = n_cit->first;
742  }
743  }
744  TNodeID renum_start = max_nodeID + 1;
745  size_t renum_counter = 0;
746  // cout << "renum_start: " << renum_start << endl;
747 
748  // Renumber nodeIDs of other graph so that they don't overlap with own
749  // graph nodeIDs
750  std::map<TNodeID, TNodeID>* old_to_new_nodeID_mappings;
751 
752  // map of TNodeID->TNodeID correspondences to address to if the
753  // old_to_new_nodeID_mappings_out is not given.
754  // Handy for not having to allocate old_to_new_nodeID_mappings in the
755  // heap
756  std::map<TNodeID, TNodeID> mappings_tmp;
757 
758  // If given, use the old_to_new_nodeID_mappings map.
759  if (old_to_new_nodeID_mappings_out)
760  {
761  old_to_new_nodeID_mappings = old_to_new_nodeID_mappings_out;
762  }
763  else
764  {
765  old_to_new_nodeID_mappings = &mappings_tmp;
766  }
767  old_to_new_nodeID_mappings->clear();
768 
769  // add all nodes of other graph - Take care of renumbering them
770  // cout << "Adding nodes of other graph" << endl;
771  // cout << "====================" << endl;
772  for (nodes_cit_t n_cit = other.nodes.begin();
773  n_cit != other.nodes.end(); ++n_cit)
774  {
775  TNodeID new_nodeID = renum_start + renum_counter++;
776  old_to_new_nodeID_mappings->insert(
777  make_pair(n_cit->first, new_nodeID));
778  this->nodes.insert(make_pair(new_nodeID, n_cit->second));
779 
780  // cout << "Adding nodeID: " << new_nodeID << endl;
781  }
782 
783  // add common constraints
784  // cout << "Adding common constraints" << endl;
785  // cout << "====================" << endl;
786  for (hypots_cit_t h_cit = common_hypots.begin();
787  h_cit != common_hypots.end(); ++h_cit)
788  {
789  TNodeID from, to;
790  if (hypots_from_other_to_self)
791  {
792  from = old_to_new_nodeID_mappings->at(h_cit->from);
793  to = h_cit->to;
794  }
795  else
796  {
797  from = h_cit->from;
798  to = old_to_new_nodeID_mappings->at(h_cit->to);
799  }
800  this->insertEdge(from, to, h_cit->getEdge());
801  // cout << from << " -> " << to << " => " << h_cit->getEdge() <<
802  // endl;
803  }
804 
805  // add all constraints of the other graph
806  // cout << "Adding constraints of other graph" << endl;
807  // cout << "====================" << endl;
808  for (typename self_t::const_iterator g_cit = other.begin();
809  g_cit != other.end(); ++g_cit)
810  {
811  TNodeID new_from =
812  old_to_new_nodeID_mappings->at(g_cit->first.first);
813  TNodeID new_to =
814  old_to_new_nodeID_mappings->at(g_cit->first.second);
815  this->insertEdge(new_from, new_to, g_cit->second);
816 
817  // cout << "[" << new_from << "] -> [" << new_to << "]" << " => " <<
818  // g_cit->second << endl;
819  }
820 
821  // run Dijkstra to update the node positions
822  this->dijkstra_nodes_estimate();
823 
824  MRPT_END;
825  }
826 
827  /**\brief Add an edge between the last node of the group with the lower
828  * nodeIDs and the first node of the higher nodeIDs.
829  *
830  * Given groups of nodes should only contain consecutive nodeIDs and
831  * there should be no overlapping between them
832  *
833  * \note It is assumed that the sets of nodes are \b already in ascending
834  * order (default std::set behavior.
835  */
836  inline static void connectGraphPartitions(
837  self_t* sub_graph, const std::set<TNodeID>& groupA,
838  const std::set<TNodeID>& groupB)
839  {
840  using namespace mrpt::math;
841 
842  ASSERTMSG_(
843  sub_graph,
844  "\nInvalid pointer to a CNetworkOfPoses instance is given. "
845  "Exiting..\n");
846  ASSERTMSG_(!groupA.empty(), "\ngroupA is empty.");
847  ASSERTMSG_(!groupB.empty(), "\ngroupB is empty.");
848 
849  // assertion - non-overlapping groups
850  ASSERTMSG_(
851  *groupA.rend() < *groupB.rbegin() ||
852  *groupA.rbegin() > *groupB.rend(),
853  "Groups A, B contain overlapping nodeIDs");
854 
855  // decide what group contains the low/high nodeIDs
856  // just compare any two nodes of the sets (they are non-overlapping
857  const std::set<TNodeID>& low_nodeIDs =
858  *groupA.rbegin() < *groupB.rbegin() ? groupA : groupB;
859  const std::set<TNodeID>& high_nodeIDs =
860  *groupA.rbegin() > *groupB.rbegin() ? groupA : groupB;
861 
862  // add virtual edge
863  const TNodeID& from_nodeID = *low_nodeIDs.rbegin();
864  const TNodeID& to_nodeID = *high_nodeIDs.begin();
865  self_t::addVirtualEdge(sub_graph, from_nodeID, to_nodeID);
866  }
867 
868  /** Computes the square error of one pose constraints (edge) with respect
869  * to the global poses in \a nodes If \a ignoreCovariances is false, the
870  * squared Mahalanobis distance will be computed instead of the straight
871  * square error.
872  *
873  * \exception std::exception On global poses not in \a nodes
874  */
875  inline double getEdgeSquareError(
876  const typename BASE::edges_map_t::const_iterator& itEdge,
877  bool ignoreCovariances = true) const
878  {
880  this, itEdge, ignoreCovariances);
881  }
882 
883  /** Computes the square error of one pose constraints (edge) with respect
884  * to the global poses in \a nodes If \a ignoreCovariances is false, the
885  * squared Mahalanobis distance will be computed instead of the straight
886  * square error.
887  *
888  * \exception std::exception On edge not existing or global poses not in
889  * \a nodes
890  */
892  const mrpt::utils::TNodeID from_id, const mrpt::utils::TNodeID to_id,
893  bool ignoreCovariances = true) const
894  {
895  const typename BASE::edges_map_t::const_iterator itEdge =
896  BASE::edges.find(std::make_pair(from_id, to_id));
897  ASSERTMSG_(
898  itEdge != BASE::edges.end(),
899  format(
900  "Request for edge %u->%u that doesn't exist in graph.",
901  static_cast<unsigned int>(from_id),
902  static_cast<unsigned int>(to_id)));
903  return getEdgeSquareError(itEdge, ignoreCovariances);
904  }
905 
906  /** Empty all edges, nodes and set root to ID 0. */
907  inline void clear()
908  {
909  BASE::edges.clear();
910  nodes.clear();
911  root = 0;
913  }
914 
915  /** Return number of nodes in the list \a nodes of global coordinates
916  * (may be different that all nodes appearing in edges)
917  *
918  * \sa mrpt::graphs::CDirectedGraph::countDifferentNodesInEdges
919  */
920  inline size_t nodeCount() const { return nodes.size(); }
921  /** @} */
922 
923  private:
924  /**\brief Add a virtual edge between two nodes in the given graph.
925  *
926  * Edge is called virtual as its value will be determined solely on the
927  * pose difference of the given nodeIDs
928  */
929  inline static void addVirtualEdge(
930  self_t* graph, const TNodeID& from, const TNodeID& to)
931  {
932  ASSERTMSG_(
933  graph, "Invalid pointer to the graph instance was provided.");
934 
935  typename self_t::global_pose_t& p_from = graph->nodes.at(from);
936  typename self_t::global_pose_t& p_to = graph->nodes.at(to);
937  const typename BASE::edge_t& virt_edge(p_to - p_from);
938 
939  graph->insertEdge(from, to, virt_edge);
940  }
941 };
942 
943 /** Binary serialization (write) operator "stream << graph" */
944 template <class CPOSE, class MAPS_IMPLEMENTATION, class NODE_ANNOTATIONS,
945  class EDGE_ANNOTATIONS>
948  const CNetworkOfPoses<CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS,
949  EDGE_ANNOTATIONS>& obj)
950 {
951  typedef CNetworkOfPoses<CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS,
952  EDGE_ANNOTATIONS>
953  graph_t;
955  return out;
956 }
957 
958 /** Binary serialization (read) operator "stream >> graph" */
959 template <class CPOSE, class MAPS_IMPLEMENTATION, class NODE_ANNOTATIONS,
960  class EDGE_ANNOTATIONS>
963  CNetworkOfPoses<CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS,
964  EDGE_ANNOTATIONS>& obj)
965 {
966  typedef CNetworkOfPoses<CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS,
967  EDGE_ANNOTATIONS>
968  graph_t;
970  return in;
971 }
972 
973 /** \addtogroup mrpt_graphs_grp
974  * \name Handy typedefs for CNetworkOfPoses commonly used types
975  @{ */
976 
977 /** The specialization of CNetworkOfPoses for poses of type CPose2D (not a
978  * PDF!), also implementing serialization. */
981 /** The specialization of CNetworkOfPoses for poses of type mrpt::poses::CPose3D
982  * (not a PDF!), also implementing serialization. */
985 /** The specialization of CNetworkOfPoses for poses of type CPosePDFGaussian,
986  * also implementing serialization. */
990 /** The specialization of CNetworkOfPoses for poses of type CPose3DPDFGaussian,
991  * also implementing serialization. */
995 /** The specialization of CNetworkOfPoses for poses of type CPosePDFGaussianInf,
996  * also implementing serialization. */
1000 /** The specialization of CNetworkOfPoses for poses of type
1001  * CPose3DPDFGaussianInf, also implementing serialization. */
1005 
1006 /**\brief Specializations of CNetworkOfPoses for graphs whose nodes inherit from
1007  * TMRSlamNodeAnnotations struct */
1008 /**\{ */
1017 /**\} */
1018 
1019 /** @} */ // end of grouping
1020 
1021 } // End of namespace
1022 
1023 // Specialization of TTypeName must occur in the same namespace:
1024 namespace utils
1025 {
1026 // Extensions to mrpt::utils::TTypeName for matrices:
1027 template <class CPOSE, class MAPS_IMPLEMENTATION, class NODE_ANNOTATIONS,
1028  class EDGE_ANNOTATIONS>
1030  CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>>
1031 {
1032  static std::string get()
1033  {
1034  return std::string("mrpt::graphs::CNetworkOfPoses<") +
1039  }
1040 };
1041 
1044 }
1045 
1046 } // End of namespace
1047 
1048 // Implementation of templates (in a separate file for clarity)
1049 #include "CNetworkOfPoses_impl.h"
1050 
1051 // Visualization related template classes
1052 #include <mrpt/graphs/CVisualizer.h>
1053 #include <mrpt/graphs/CMRVisualizer.h>
1054 
1055 #endif
A directed graph with the argument of the template specifying the type of the annotations in the edge...
CNetworkOfPoses< mrpt::poses::CPosePDFGaussianInf, mrpt::utils::map_traits_stdmap > CNetworkOfPoses2DInf
The specialization of CNetworkOfPoses for poses of type CPosePDFGaussianInf, also implementing serial...
double getGlobalSquareError(bool ignoreCovariances=true) const
Computes the overall square error from all the pose constraints (edges) with respect to the global po...
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
CNetworkOfPoses< CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS >::global_pose_t self_t
void dijkstra_nodes_estimate()
Spanning tree computation of a simple estimation of the global coordinates of each node just from the...
CNetworkOfPoses< mrpt::poses::CPosePDFGaussianInf, mrpt::utils::map_traits_stdmap, mrpt::graphs::detail::TMRSlamNodeAnnotations > CNetworkOfPoses2DInf_NA
Specializations of CNetworkOfPoses for graphs whose nodes inherit from TMRSlamNodeAnnotations struct...
global_pose_t(const global_pose_t &other)
Copy constructor - delegate copying to the NODE_ANNOTATIONS struct.
NODE_ANNOTATIONS node_annotations_t
The extra annotations in nodes, apart from a constraint_no_pdf_t.
void clear()
Empty all edges, nodes and set root to ID 0.
CNetworkOfPoses< mrpt::poses::CPose2D, mrpt::utils::map_traits_stdmap > CNetworkOfPoses2D
The specialization of CNetworkOfPoses for poses of type CPose2D (not a PDF!), also implementing seria...
A template to obtain the type of its argument as a string at compile time.
Definition: TTypeName.h:55
Traits for using a mrpt::utils::map_as_vector<> (dense, fastest representation)
Definition: traits_map.h:39
CNetworkOfPoses< mrpt::poses::CPose3DPDFGaussianInf, mrpt::utils::map_traits_stdmap > CNetworkOfPoses3DInf
The specialization of CNetworkOfPoses for poses of type CPose3DPDFGaussianInf, also implementing seri...
size_t collapseDuplicatedEdges()
Look for duplicated edges (even in opposite directions) between all pairs of nodes and fuse them...
edges_map_t edges
The public member with the directed edges in the graph.
GLint * first
Definition: glext.h:3827
void saveToTextFile(const std::string &fileName) const
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) For 2D graphs only VERTEX2 & EDGE2 entries will be saved, and VERTEX3 & EDGE3 entries for 3D graphs.
friend std::ostream & operator<<(std::ostream &o, const self_t &global_pose)
Abstract graph and tree data structures, plus generic graph algorithms.
void getNeighborsOf(const TNodeID nodeID, std::set< TNodeID > &neighborIDs) const
Return the list of all neighbors of "nodeID", by creating a list of their node IDs.
void loadFromTextFile(const std::string &fileName, bool collapse_dup_edges=true)
Loads from a text file in the format used by TORO & HoG-man (more on the format here) Recognized line...
Scalar * iterator
Definition: eigen_plugins.h:26
#define INVALID_NODEID
STL namespace.
const Scalar * const_iterator
Definition: eigen_plugins.h:27
static void read_graph_of_poses_from_binary_file(graph_t *g, mrpt::utils::CStream &in)
CNetworkOfPoses< mrpt::poses::CPose3DPDFGaussianInf, mrpt::utils::map_traits_stdmap, mrpt::graphs::detail::TMRSlamNodeAnnotations > CNetworkOfPoses3DInf_NA
GLsizei GLsizei GLuint * obj
Definition: glext.h:4070
double getEdgeSquareError(const typename BASE::edges_map_t::const_iterator &itEdge, bool ignoreCovariances=true) const
Computes the square error of one pose constraints (edge) with respect to the global poses in nodes If...
void clearEdges()
Erase all edges.
static void graph_of_poses_dijkstra_init(graph_t *g)
Base class for C*Visualizer classes.
A directed graph of pose constraints, with edges being the relative poses between pairs of nodes iden...
MAPS_IMPLEMENTATION::template map< mrpt::utils::TNodeID, global_pose_t > global_poses_t
A map from pose IDs to their global coordinate estimates, without uncertainty (the "most-likely value...
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:41
Internal functions for MRPT.
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:19
static void save_graph_of_poses_to_binary_file(const graph_t *g, mrpt::utils::CStream &out)
Declares a class that represents a Probability Density function (PDF) of a 2D pose ...
uint64_t TNodeID
The type for node IDs in graphs of different types.
#define MRPT_END
CNetworkOfPoses< mrpt::poses::CPose3D, mrpt::utils::map_traits_stdmap > CNetworkOfPoses3D
The specialization of CNetworkOfPoses for poses of type mrpt::poses::CPose3D (not a PDF!)...
CNetworkOfPoses< mrpt::poses::CPose3DPDFGaussian, mrpt::utils::map_traits_stdmap > CNetworkOfPoses3DCov
The specialization of CNetworkOfPoses for poses of type CPose3DPDFGaussian, also implementing seriali...
void getUnconnectedNodeIDs(std::set< mrpt::utils::TNodeID > *set_nodeIDs) const
Fill set with the nodeIDs Dijkstra algorithm could not reach starting from the root node...
Definition: dijkstra.h:49
The type of each global pose in nodes: an extension of the constraint_no_pdf_t pose with any optional...
MAPS_IMPLEMENTATION::template map< mrpt::utils::TNodeID, CPOSE > global_poses_pdf_t
A map from pose IDs to their global coordinate estimates, with uncertainty.
void insertEdge(TNodeID from_nodeID, TNodeID to_nodeID, const edge_t &edge_value)
Insert an edge (from -> to) with the given edge value.
std::shared_ptr< CSetOfObjects > Ptr
Definition: CSetOfObjects.h:32
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:19
uint64_t TNodeID
The type for node IDs in graphs of different types.
Definition: types_simple.h:49
bool operator!=(const global_pose_t &other) const
static void connectGraphPartitions(self_t *sub_graph, const std::set< TNodeID > &groupA, const std::set< TNodeID > &groupB)
Add an edge between the last node of the group with the lower nodeIDs and the first node of the highe...
CPOSE::type_value constraint_no_pdf_t
The type of edges or their means if they are PDFs (that is, a simple "edge" value) ...
mrpt::graphs::CDirectedGraph< CPOSE, EDGE_ANNOTATIONS > BASE
The base class "CDirectedGraph<CPOSE,EDGE_ANNOTATIONS>".
GLsizei const GLchar ** string
Definition: glext.h:4101
size_t nodeCount() const
Return number of nodes in the list nodes of global coordinates (may be different that all nodes appea...
void extractSubGraph(const std::set< TNodeID > &node_IDs, self_t *sub_graph, const TNodeID root_node_in=INVALID_NODEID, const bool &auto_expand_set=true) const
Find the edges between the nodes in the node_IDs set and fill given graph pointer accordingly...
global_pose_t()
Potential class constructors.
static size_t graph_of_poses_collapse_dup_edges(graph_t *g)
static void save_graph_of_poses_to_text_file(const graph_t *g, const std::string &fil)
#define MRPT_START
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
A Probability Density function (PDF) of a 2D pose as a Gaussian with a mean and the inverse of the c...
CPOSE constraint_t
The type of PDF poses in the contraints (edges) (=CPOSE template argument)
void mergeGraph(const self_t &other, const typename std::vector< detail::THypothesis< self_t >> &common_hypots, const bool hypots_from_other_to_self=true, std::map< TNodeID, TNodeID > *old_to_new_nodeID_mappings_out=NULL)
Integrate given graph into own graph using the list of provided common THypotheses.
CNetworkOfPoses< CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS > self_t
My own type.
static 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)
a helper struct with static template functions
mrpt::utils::CStream & operator>>(mrpt::utils::CStream &in, CNetworkOfPoses< CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS > &obj)
Binary serialization (read) operator "stream >> graph".
Declares a class that represents a Probability Density function (PDF) of a 3D pose as a Gaussian des...
GLuint in
Definition: glext.h:7274
#define ASSERT_(f)
Declares a class that represents a Probability Density function (PDF) of a 3D pose ...
static void load_graph_of_poses_from_text_file(graph_t *g, const std::string &fil)
global_poses_t nodes
The nodes (vertices) of the graph, with their estimated "global" (with respect to root) position...
global_pose_t(const ARG1 &a1, const ARG2 &a2)
The Dijkstra algorithm for finding the shortest path between a given source node in a (weighted) dire...
Definition: dijkstra.h:101
mrpt::utils::TNodeID root
The ID of the node that is the origin of coordinates, used as reference by all coordinates in nodes...
T absDiff(const T &lhs, const T &rhs)
Absolute difference between two numbers.
Traits for using a std::map<> (sparse representation)
Definition: traits_map.h:27
bool edges_store_inverse_poses
False (default) if an edge i->j stores the normal relative pose of j as seen from i: True if an edge...
GLsizei const GLfloat * value
Definition: glext.h:4117
bool operator==(const global_pose_t &other) const
EDGE_ANNOTATIONS edge_annotations_t
The extra annotations in edges, apart from a constraint_t.
double getEdgeSquareError(const mrpt::utils::TNodeID from_id, const mrpt::utils::TNodeID to_id, bool ignoreCovariances=true) const
Computes the square error of one pose constraints (edge) with respect to the global poses in nodes If...
An edge hypothesis between two nodeIDs.
Definition: THypothesis.h:37
Struct to be used as the NODE_ANNOTATIONS template argument in CNetworkOfPoses class instances for us...
mrpt::utils::CStream & operator<<(mrpt::utils::CStream &out, const CNetworkOfPoses< CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS > &obj)
Binary serialization (write) operator "stream << graph".
#define ASSERTMSG_(f, __ERROR_MSG)
Struct to be used as the NODE_ANNOTATIONS template argument in CNetworkOfPoses class instances for us...
Wrapper class that provides visualization of a network of poses that have been registered by many gra...
Definition: CMRVisualizer.h:40
Custom exception class that passes information in case an unconnected graph is passed to a Dijkstra i...
Definition: dijkstra.h:33
MAPS_IMPLEMENTATION maps_implementation_t
The type of map&#39;s implementation (=MAPS_IMPLEMENTATION template argument)
CNetworkOfPoses< mrpt::poses::CPosePDFGaussian, mrpt::utils::map_traits_stdmap > CNetworkOfPoses2DCov
The specialization of CNetworkOfPoses for poses of type CPosePDFGaussian, also implementing serializa...
#define MRPT_DECLARE_TTYPENAME(_TYPE)
Definition: TTypeName.h:72
void getAs3DObject(mrpt::opengl::CSetOfObjects::Ptr object, const mrpt::utils::TParametersDouble &viz_params) const
Return 3D Visual Representation of the edges and nodes in the network of poses.
static void addVirtualEdge(self_t *graph, const TNodeID &from, const TNodeID &to)
Add a virtual edge between two nodes in the given graph.



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019