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>
55 class CVisualizer;
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
#define MRPT_DECLARE_TTYPENAME(_TYPE)
Definition: TTypeName.h:72
The Dijkstra algorithm for finding the shortest path between a given source node in a (weighted) dire...
Definition: dijkstra.h:102
A directed graph with the argument of the template specifying the type of the annotations in the edge...
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.
edges_map_t edges
The public member with the directed edges in the graph.
edges_map_t::const_iterator const_iterator
void insertEdge(TNodeID from_nodeID, TNodeID to_nodeID, const edge_t &edge_value)
Insert an edge (from -> to) with the given edge value.
void clearEdges()
Erase all edges.
A directed graph of pose constraints, with edges being the relative poses between pairs of nodes iden...
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...
void clear()
Empty all edges, nodes and set root to ID 0.
MAPS_IMPLEMENTATION maps_implementation_t
The type of map's implementation (=MAPS_IMPLEMENTATION template argument)
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...
global_poses_t nodes
The nodes (vertices) of the graph, with their estimated "global" (with respect to root) position,...
size_t collapseDuplicatedEdges()
Look for duplicated edges (even in opposite directions) between all pairs of nodes and fuse them.
EDGE_ANNOTATIONS edge_annotations_t
The extra annotations in edges, apart from a constraint_t.
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...
static void addVirtualEdge(self_t *graph, const TNodeID &from, const TNodeID &to)
Add a virtual edge between two nodes in the given graph.
void dijkstra_nodes_estimate()
Spanning tree computation of a simple estimation of the global coordinates of each node just from the...
mrpt::utils::TNodeID root
The ID of the node that is the origin of coordinates, used as reference by all coordinates in nodes.
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.
CPOSE::type_value constraint_no_pdf_t
The type of edges or their means if they are PDFs (that is, a simple "edge" value)
CPOSE constraint_t
The type of PDF poses in the contraints (edges) (=CPOSE template argument)
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::graphs::CDirectedGraph< CPOSE, EDGE_ANNOTATIONS > BASE
The base class "CDirectedGraph<CPOSE,EDGE_ANNOTATIONS>".
NODE_ANNOTATIONS node_annotations_t
The extra annotations in nodes, apart from a constraint_no_pdf_t.
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.
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...
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.
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...
size_t nodeCount() const
Return number of nodes in the list nodes of global coordinates (may be different that all nodes appea...
double getGlobalSquareError(bool ignoreCovariances=true) const
Computes the overall square error from all the pose constraints (edges) with respect to the global po...
MAPS_IMPLEMENTATION::template map< mrpt::utils::TNodeID, CPOSE > global_poses_pdf_t
A map from pose IDs to their global coordinate estimates, with uncertainty.
CNetworkOfPoses< CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS > self_t
My own type.
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...
Wrapper class that provides visualization of a network of poses that have been registered by many gra...
Definition: CMRVisualizer.h:42
Base class for C*Visualizer classes.
Definition: CVisualizer.h:38
virtual void getAs3DObject(mrpt::opengl::CSetOfObjects::Ptr &object, mrpt::utils::TParametersDouble viz_params) const
Common visualization stuff for all derived classes.
Custom exception class that passes information in case an unconnected graph is passed to a Dijkstra i...
Definition: dijkstra.h:34
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
std::shared_ptr< CSetOfObjects > Ptr
Definition: CSetOfObjects.h:32
Declares a class that represents a Probability Density function (PDF) of a 3D pose .
Declares a class that represents a Probability Density function (PDF) of a 3D pose as a Gaussian des...
Declares a class that represents a Probability Density function (PDF) of a 2D pose .
A Probability Density function (PDF) of a 2D pose as a Gaussian with a mean and the inverse of the c...
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:42
Scalar * iterator
Definition: eigen_plugins.h:26
const Scalar * const_iterator
Definition: eigen_plugins.h:27
GLsizei GLsizei GLuint * obj
Definition: glext.h:4070
GLuint in
Definition: glext.h:7274
GLint * first
Definition: glext.h:3827
GLenum GLsizei GLenum format
Definition: glext.h:3531
GLsizei const GLfloat * value
Definition: glext.h:4117
GLsizei const GLchar ** string
Definition: glext.h:4101
uint64_t TNodeID
The type for node IDs in graphs of different types.
Definition: types_simple.h:49
#define INVALID_NODEID
Definition: types_simple.h:52
#define MRPT_START
Definition: mrpt_macros.h:425
#define ASSERT_(f)
Definition: mrpt_macros.h:309
#define MRPT_END
Definition: mrpt_macros.h:429
#define ASSERTMSG_(f, __ERROR_MSG)
Definition: mrpt_macros.h:306
Internal functions for MRPT.
Abstract graph and tree data structures, plus generic graph algorithms.
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...
mrpt::utils::CStream & operator<<(mrpt::utils::CStream &out, const CNetworkOfPoses< CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS > &obj)
Binary serialization (write) operator "stream << graph".
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.
CNetworkOfPoses< mrpt::poses::CPose3DPDFGaussianInf, mrpt::utils::map_traits_stdmap, mrpt::graphs::detail::TMRSlamNodeAnnotations > CNetworkOfPoses3DInf_NA
CNetworkOfPoses< mrpt::poses::CPosePDFGaussian, mrpt::utils::map_traits_stdmap > CNetworkOfPoses2DCov
The specialization of CNetworkOfPoses for poses of type CPosePDFGaussian, also implementing serializa...
CNetworkOfPoses< mrpt::poses::CPosePDFGaussianInf, mrpt::utils::map_traits_stdmap > CNetworkOfPoses2DInf
The specialization of CNetworkOfPoses for poses of type CPosePDFGaussianInf, also implementing serial...
CNetworkOfPoses< mrpt::poses::CPose3DPDFGaussianInf, mrpt::utils::map_traits_stdmap > CNetworkOfPoses3DInf
The specialization of CNetworkOfPoses for poses of type CPose3DPDFGaussianInf, also implementing seri...
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...
mrpt::utils::CStream & operator>>(mrpt::utils::CStream &in, CNetworkOfPoses< CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS > &obj)
Binary serialization (read) operator "stream >> graph".
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:20
T absDiff(const T &lhs, const T &rhs)
Absolute difference between two numbers.
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values,...
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:19
The type of each global pose in nodes: an extension of the TYPE_EDGES pose with any optional user-def...
The type of each global pose in nodes: an extension of the constraint_no_pdf_t pose with any optional...
global_pose_t(const global_pose_t &other)
Copy constructor - delegate copying to the NODE_ANNOTATIONS struct.
bool operator==(const global_pose_t &other) const
bool operator!=(const global_pose_t &other) const
global_pose_t(const ARG1 &a1, const ARG2 &a2)
friend std::ostream & operator<<(std::ostream &o, const self_t &global_pose)
CNetworkOfPoses< CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS >::global_pose_t self_t
global_pose_t()
Potential class constructors.
An edge hypothesis between two nodeIDs.
Definition: THypothesis.h:38
Struct to be used as the NODE_ANNOTATIONS template argument in CNetworkOfPoses class instances for us...
Struct to be used as the NODE_ANNOTATIONS template argument in CNetworkOfPoses class instances for us...
a helper struct with static template functions
static void graph_of_poses_dijkstra_init(graph_t *g)
static void read_graph_of_poses_from_binary_file(graph_t *g, mrpt::utils::CStream &in)
static size_t graph_of_poses_collapse_dup_edges(graph_t *g)
static void load_graph_of_poses_from_text_file(graph_t *g, const std::string &fil)
static void save_graph_of_poses_to_binary_file(const graph_t *g, mrpt::utils::CStream &out)
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)
static void save_graph_of_poses_to_text_file(const graph_t *g, const std::string &fil)
A template to obtain the type of its argument as a string at compile time.
Definition: TTypeName.h:56
Traits for using a mrpt::utils::map_as_vector<> (dense, fastest representation)
Definition: traits_map.h:40
Traits for using a std::map<> (sparse representation)
Definition: traits_map.h:28



Page generated by Doxygen 1.9.1 for MRPT 1.9.9 Git: 63ea9d1f1 Thu Nov 23 00:06:53 2017 +0100 at mar 26 may 2026 12:19:29 CEST