MRPT  1.9.9
CLoopCloserERD_impl.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-2018, 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 
10 #ifndef CLOOPCLOSERERD_IMPL_H
11 #define CLOOPCLOSERERD_IMPL_H
12 #include <mrpt/math/utils.h>
14 #include <mrpt/opengl/CEllipsoid.h>
15 #include <mrpt/opengl/CSphere.h>
16 #include <mrpt/math/data_utils.h>
17 
19 {
20 // Ctors, Dtors
21 // //////////////////////////////////
22 template <class GRAPH_T>
24  : m_visualize_curr_node_covariance(false),
25  m_curr_node_covariance_color(160, 160, 160, /*alpha = */ 255),
26  m_partitions_full_update(false),
27  m_is_first_time_node_reg(true),
28  m_dijkstra_node_count_thresh(3)
29 {
30  this->initializeLoggers("CLoopCloserERD");
31  m_edge_types_to_nums["ICP2D"] = 0;
32  m_edge_types_to_nums["LC"] = 0;
33  MRPT_LOG_DEBUG_STREAM("Initialized class object");
34 }
35 
36 template <class GRAPH_T>
38 {
39  using namespace mrpt::graphslam;
40 
41  // release memory of m_node_optimal_paths map.
42  MRPT_LOG_DEBUG_STREAM("Releasing memory of m_node_optimal_paths map...");
43  for (auto it = m_node_optimal_paths.begin();
44  it != m_node_optimal_paths.end(); ++it)
45  {
46  delete it->second;
47  }
48 }
49 
50 // Methods implementations
51 // //////////////////////////////////
52 
53 template <class GRAPH_T>
56  mrpt::obs::CSensoryFrame::Ptr observations,
57  mrpt::obs::CObservation::Ptr observation)
58 {
59  MRPT_START;
60  MRPT_UNUSED_PARAM(action);
61  this->m_time_logger.enter("updateState");
62  using namespace std;
63  using namespace mrpt;
64  using namespace mrpt::obs;
65  using namespace mrpt::obs::utils;
66  using namespace mrpt::opengl;
67  using namespace mrpt::poses;
68  using namespace mrpt::math;
69 
70  // Track the last recorded laser scan
71  {
73  getObservation<CObservation2DRangeScan>(observations, observation);
74  if (scan)
75  {
76  m_last_laser_scan2D = scan;
77  }
78  }
79 
80  if (!m_first_laser_scan)
81  {
82  m_first_laser_scan = m_last_laser_scan2D;
83  }
84 
85  // check possible prior node registration
86  size_t num_registered =
87  absDiff(this->m_last_total_num_nodes, this->m_graph->nodeCount());
88  bool registered_new_node = num_registered > 0;
89 
90  if (registered_new_node)
91  {
92  MRPT_LOG_DEBUG_STREAM("New node has been registered in the graph!");
93  registered_new_node = true;
94 
95  // either single node registration, or double node registration for the
96  // first time only, unless we override this check.
97  if (!this->m_override_registered_nodes_check)
98  {
99  if (!((num_registered == 1) ^
100  (num_registered == 2 && m_is_first_time_node_reg)))
101  {
103  "Invalid number of registered nodes since last call to "
104  "updateStates| "
105  "Found \""
106  << num_registered << "\" new nodes.");
107  THROW_EXCEPTION("Invalid number of registered nodes.");
108  }
109  }
110 
111  // first time call:
112  // NRD should have registered *2* nodes; one for the root node and one
113  // for
114  // the first added constraint. Add the first measurement taken to the
115  // root
116  // and the second as usual
117  if (m_is_first_time_node_reg)
118  {
120  "Assigning first laserScan to the graph root node.");
121  this->m_nodes_to_laser_scans2D[this->m_graph->root] =
122  m_first_laser_scan;
123  m_is_first_time_node_reg = false;
124  }
125 
126  // register the new node-laserScan pair
127  this->m_nodes_to_laser_scans2D[this->m_graph->nodeCount() - 1] =
128  m_last_laser_scan2D;
129 
130  if (m_laser_params.use_scan_matching)
131  {
132  // scan match with previous X nodes
133  this->addScanMatchingEdges(this->m_graph->nodeCount() - 1);
134  }
135 
136  // update partitioning scheme with the latest pose/measurement
137  m_partitions_full_update =
138  ((this->m_graph->nodeCount() %
139  m_lc_params.full_partition_per_nodes) == 0 ||
140  this->m_just_inserted_lc)
141  ? true
142  : false;
143  this->updateMapPartitions(
144  m_partitions_full_update,
145  /* is_first_time_node_reg = */ num_registered == 2);
146 
147  // check for loop closures
148  partitions_t partitions_for_LC;
149  this->checkPartitionsForLC(&partitions_for_LC);
150  this->evaluatePartitionsForLC(partitions_for_LC);
151 
152  if (m_visualize_curr_node_covariance)
153  {
154  this->execDijkstraProjection();
155  }
156 
157  this->m_last_total_num_nodes = this->m_graph->nodeCount();
158  }
159 
160  this->m_time_logger.leave("updateState");
161  return true;
162  MRPT_END;
163 }
164 
165 template <class GRAPH_T>
167  const mrpt::graphs::TNodeID& curr_nodeID,
168  std::set<mrpt::graphs::TNodeID>* nodes_set)
169 {
170  ASSERTDEB_(nodes_set);
171 
172  // deal with the case that less than `prev_nodes_for_ICP` nodes have been
173  // registered
174  int fetched_nodeIDs = 0;
175  for (int nodeID_i = static_cast<int>(curr_nodeID) - 1;
176  ((fetched_nodeIDs <= this->m_laser_params.prev_nodes_for_ICP) &&
177  (nodeID_i >= 0)); // <----- I *have* to use int (instead of unsigned)
178  // if I use this condition
179  --nodeID_i)
180  {
181  nodes_set->insert(nodeID_i);
182  fetched_nodeIDs++;
183  }
184 } // end of fetchNodeIDsForScanMatching
185 
186 template <class GRAPH_T>
188  const mrpt::graphs::TNodeID& curr_nodeID)
189 {
190  MRPT_START;
191  using namespace std;
192  using namespace mrpt;
193  using namespace mrpt::obs;
194  using namespace mrpt::math;
195  using mrpt::graphs::TNodeID;
196 
197  // get a list of nodes to check ICP against
198  MRPT_LOG_DEBUG_STREAM("Adding ICP Constraints for nodeID: " << curr_nodeID);
199 
200  std::set<TNodeID> nodes_set;
201  this->fetchNodeIDsForScanMatching(curr_nodeID, &nodes_set);
202 
203  // try adding ICP constraints with each node in the previous set
204  for (std::set<TNodeID>::const_iterator node_it = nodes_set.begin();
205  node_it != nodes_set.end(); ++node_it)
206  {
207  constraint_t rel_edge;
209 
211  "Fetching laser scan for nodes: " << *node_it << "==> "
212  << curr_nodeID);
213 
214  bool found_edge =
215  this->getICPEdge(*node_it, curr_nodeID, &rel_edge, &icp_info);
216  if (!found_edge) continue;
217 
218  // keep track of the recorded goodness values
219  // TODO - rethink on these condition.
220  if (!isnan(icp_info.goodness) ||
221  !approximatelyEqual(static_cast<double>(icp_info.goodness), 0.0))
222  {
223  m_laser_params.goodness_threshold_win.addNewMeasurement(
224  icp_info.goodness);
225  }
226  double goodness_thresh =
227  m_laser_params.goodness_threshold_win.getMedian() *
228  m_consec_icp_constraint_factor;
229  bool accept_goodness = icp_info.goodness > goodness_thresh;
231  "Curr. Goodness: " << icp_info.goodness
232  << "|\t Threshold: " << goodness_thresh << " => "
233  << (accept_goodness ? "ACCEPT" : "REJECT"));
234 
235  // make sure that the suggested edge makes sense with regards to current
236  // graph config - check against the current position difference
237  bool accept_mahal_distance = this->mahalanobisDistanceOdometryToICPEdge(
238  *node_it, curr_nodeID, rel_edge);
239 
240  // criterion for registering a new node
241  if (accept_goodness && accept_mahal_distance)
242  {
243  this->registerNewEdge(*node_it, curr_nodeID, rel_edge);
244  }
245  }
246 
247  MRPT_END;
248 } // end of addScanMatchingEdges
249 template <class GRAPH_T>
251  const mrpt::graphs::TNodeID& from, const mrpt::graphs::TNodeID& to,
252  constraint_t* rel_edge, mrpt::slam::CICP::TReturnInfo* icp_info,
253  const TGetICPEdgeAdParams* ad_params /*=NULL*/)
254 {
255  MRPT_START;
256  ASSERTDEB_(rel_edge);
257  this->m_time_logger.enter("getICPEdge");
258 
259  using namespace mrpt::obs;
260  using namespace std;
261  using namespace mrpt::graphslam::detail;
262 
263  // fetch the relevant laser scans and poses of the nodeIDs
264  // If given in the additional params struct, use those values instead of
265  // searching in the class std::map(s)
266  CObservation2DRangeScan::Ptr from_scan, to_scan;
267  global_pose_t from_pose;
268  global_pose_t to_pose;
269 
270  MRPT_LOG_DEBUG_STREAM("****In getICPEdge method: ");
271  if (ad_params)
272  {
274  "TGetICPEdgeAdParams:\n"
275  << ad_params->getAsString() << endl);
276  }
277 
278  // from-node parameters
279  const node_props_t* from_params =
280  ad_params ? &ad_params->from_params : NULL;
281  bool from_success = this->getPropsOfNodeID(
282  from, &from_pose, from_scan, from_params); // TODO
283  // to-node parameters
284  const node_props_t* to_params = ad_params ? &ad_params->to_params : NULL;
285  bool to_success = this->getPropsOfNodeID(to, &to_pose, to_scan, to_params);
286 
287  if (!from_success || !to_success)
288  {
290  "Either node #"
291  << from << " or node #" << to
292  << " doesn't contain a valid LaserScan. Ignoring this...");
293  return false;
294  }
295 
296  // make use of initial node position difference for the ICP edge
297  // from_node pose
298  pose_t initial_estim;
299  if (ad_params)
300  {
301  initial_estim = ad_params->init_estim;
302  }
303  else
304  {
305  initial_estim = to_pose - from_pose;
306  }
307 
309  "from_pose: " << from_pose << "| to_pose: " << to_pose
310  << "| init_estim: " << initial_estim);
311 
312  range_ops_t::getICPEdge(
313  *from_scan, *to_scan, rel_edge, &initial_estim, icp_info);
314  MRPT_LOG_DEBUG_STREAM("*************");
315 
316  this->m_time_logger.leave("getICPEdge");
317  return true;
318  MRPT_END;
319 } // end of getICPEdge
320 
321 template <class GRAPH_T>
323  const mrpt::graphs::TNodeID& nodeID,
324  const std::map<mrpt::graphs::TNodeID, node_props_t>& group_params,
325  node_props_t* node_props)
326 {
327  ASSERTDEB_(node_props);
328 
329  // MRPT_LOG_DEBUG_STREAM(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
330  // MRPT_LOG_DEBUG_STREAM("Running fillNodePropsFromGroupParams for nodeID
331  // \""
332  //<< nodeID << "\"");
333 
334  // Make sure that the given nodeID exists in the group_params
336  search = group_params.find(nodeID);
337  bool res = false;
338  if (search == group_params.end())
339  {
340  // MRPT_LOG_DEBUG_STREAM("Operation failed.");
341  }
342  else
343  {
344  *node_props = search->second;
345  res = true;
346  // MRPT_LOG_DEBUG_STREAM("Properties filled: " <<
347  // node_props->getAsString());
348  }
349 
350  // MRPT_LOG_DEBUG_STREAM("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
351  return res;
352 }
353 
354 template <class GRAPH_T>
356  const mrpt::graphs::TNodeID& nodeID, global_pose_t* pose,
358  const node_props_t* node_props /*=NULL*/) const
359 {
360  // make sure output instances are valid
361  ASSERTDEB_(pose);
362 
363  bool filled_pose = false;
364  bool filled_scan = false;
365 
366  if (node_props)
367  {
368  // Pose
369  if (node_props->pose != global_pose_t())
370  {
371  *pose = node_props->pose;
372  filled_pose = true;
373  }
374  // LaserScan
375  if (node_props->scan)
376  {
377  scan = node_props->scan;
378  filled_scan = true;
379  }
380  }
381 
382  // TODO - What if the node_props->pose is indeed 0?
384  !(filled_pose ^ filled_scan),
385  format(
386  "Either BOTH or NONE of the filled_pose, filled_scan should be set."
387  "NodeID: [%lu]",
388  static_cast<unsigned long>(nodeID)));
389 
390  //
391  // fill with class data if not yet available
392  //
393  if (!filled_pose)
394  {
395  // fill with class data if not yet available
397  this->m_graph->nodes.find(nodeID);
398  if (search != this->m_graph->nodes.end())
399  {
400  *pose = search->second;
401  filled_pose = true;
402  }
403  else
404  {
405  MRPT_LOG_WARN_STREAM("pose not found for nodeID: " << nodeID);
406  }
407  }
408  if (!filled_scan)
409  {
410  typename nodes_to_scans2D_t::const_iterator search =
411  this->m_nodes_to_laser_scans2D.find(nodeID);
412  if (search != this->m_nodes_to_laser_scans2D.end())
413  {
414  scan = search->second;
415  filled_scan = true;
416  }
417  }
418 
419  return filled_pose && filled_scan;
420 }
421 
422 template <class GRAPH_T>
424  partitions_t* partitions_for_LC)
425 {
426  MRPT_START;
427  this->m_time_logger.enter("LoopClosureEvaluation");
428 
429  using namespace std;
430  using namespace mrpt;
431 
432  ASSERTDEB_(partitions_for_LC);
433  partitions_for_LC->clear();
434 
435  // keep track of the previous nodes list of every partition. If this is not
436  // changed - do not mark it as potential for loop closure
437  map<int, std::vector<uint32_t>>::iterator finder;
438  // reset the previous list if full partitioning was issued
439  if (m_partitions_full_update)
440  {
441  m_partitionID_to_prev_nodes_list.clear();
442  }
443 
444  int partitionID = 0;
445  // for every partition...
446  for (partitions_t::const_iterator partitions_it = m_curr_partitions.begin();
447  partitions_it != m_curr_partitions.end();
448  ++partitions_it, ++partitionID)
449  {
450  // check whether the last registered node is in the currently traversed
451  // partition - if not, ignore it.
452  if (m_lc_params.LC_check_curr_partition_only)
453  {
454  bool curr_node_in_curr_partition =
455  ((find(
456  partitions_it->begin(), partitions_it->end(),
457  this->m_graph->nodeCount() - 1)) != partitions_it->end());
458  if (!curr_node_in_curr_partition)
459  {
460  continue;
461  }
462  }
463 
464  // keep track of the previous nodes list
465  finder = m_partitionID_to_prev_nodes_list.find(partitionID);
466  if (finder == m_partitionID_to_prev_nodes_list.end())
467  {
468  // nodes list is not registered yet
469  m_partitionID_to_prev_nodes_list.insert(
470  make_pair(partitionID, *partitions_it));
471  }
472  else
473  {
474  if (*partitions_it == finder->second)
475  {
476  // MRPT_LOG_DEBUG_STREAM("Partition " << partitionID
477  //<< " remained unchanged. ");
478  continue; // same list as before.. no need to check this...
479  }
480  else
481  { // list was changed - update the previous nodes list
482  // MRPT_LOG_DEBUG_STREAM("Partition " << partitionID << "
483  // CHANGED. ");
484  finder->second = *partitions_it;
485  }
486  }
487 
488  // investigate each partition
489  int curr_node_index = 1;
490  size_t prev_nodeID = *(partitions_it->begin());
492  it = partitions_it->begin() + 1;
493  it != partitions_it->end(); ++it, ++curr_node_index)
494  {
495  size_t curr_nodeID = *it;
496 
497  // are there consecutive nodes with large difference inside this
498  // partition? Are these nodes enough to consider LC?
499  if ((curr_nodeID - prev_nodeID) > m_lc_params.LC_min_nodeid_diff)
500  {
501  // there is at least one divergent node..
502 
503  int num_after_nodes = partitions_it->size() - curr_node_index;
504  int num_before_nodes = partitions_it->size() - num_after_nodes;
505  if (num_after_nodes >= m_lc_params.LC_min_remote_nodes &&
506  num_before_nodes >= m_lc_params.LC_min_remote_nodes)
507  { // at least X LC nodes
509  "Found potential loop closures:"
510  << endl
511  << "\tPartitionID: " << partitionID << endl
512  << "\tPartition: "
514  *partitions_it)
515  .c_str()
516  << endl
517  << "\t" << prev_nodeID << " ==> " << curr_nodeID << endl
518  << "\tNumber of LC nodes: " << num_after_nodes);
519  partitions_for_LC->push_back(*partitions_it);
520  break; // no need to check the rest of the nodes in this
521  // partition
522  }
523  }
524 
525  // update the previous node
526  prev_nodeID = curr_nodeID;
527  }
529  "Successfully checked partition: " << partitionID);
530  }
531 
532  this->m_time_logger.leave("LoopClosureEvaluation");
533  MRPT_END;
534 }
535 
536 template <class GRAPH_T>
538  const partitions_t& partitions)
539 {
540  MRPT_START;
541  using namespace mrpt;
542  using namespace mrpt::graphslam::detail;
543  using namespace mrpt::math;
544  using namespace std;
545  this->m_time_logger.enter("LoopClosureEvaluation");
546 
547  if (partitions.size() == 0) return;
548 
550  "Evaluating partitions for loop closures...\n%s\n",
551  this->header_sep.c_str());
552 
553  // for each partition to be evaulated...
554  for (partitions_t::const_iterator p_it = partitions.begin();
555  p_it != partitions.end(); ++p_it)
556  {
557  std::vector<uint32_t> partition(*p_it);
558 
559  // split the partition to groups
560  std::vector<uint32_t> groupA, groupB;
561  this->splitPartitionToGroups(
562  partition, &groupA, &groupB,
563  /*max_nodes_in_group=*/5);
564 
565  // generate hypotheses pool
566  hypotsp_t hypots_pool;
567  this->generateHypotsPool(groupA, groupB, &hypots_pool);
568 
569  // compute the pair-wise consistency matrix
570  CMatrixDouble consist_matrix(hypots_pool.size(), hypots_pool.size());
571  this->generatePWConsistenciesMatrix(
572  groupA, groupB, hypots_pool, &consist_matrix);
573 
574  // evaluate resulting matrix - fill valid hypotheses
575  hypotsp_t valid_hypots;
576  this->evalPWConsistenciesMatrix(
577  consist_matrix, hypots_pool, &valid_hypots);
578 
579  // registering the indicated/valid hypotheses
580  if (valid_hypots.size())
581  {
582  MRPT_LOG_WARN_STREAM("Registering Hypotheses...");
583  for (typename hypotsp_t::iterator it = valid_hypots.begin();
584  it != valid_hypots.end(); ++it)
585  {
586  this->registerHypothesis(**it);
587  }
588  }
589  // delete all hypotheses - generated in the heap...
590  MRPT_LOG_DEBUG_STREAM("Deleting the generated hypotheses pool...");
591  for (typename hypotsp_t::iterator it = hypots_pool.begin();
592  it != hypots_pool.end(); ++it)
593  {
594  delete *it;
595  }
596  } // for each partition
597 
598  MRPT_LOG_DEBUG_STREAM("\n" << this->header_sep);
599  this->m_time_logger.leave("LoopClosureEvaluation");
600 
601  MRPT_END;
602 }
603 
604 template <class GRAPH_T>
606  const mrpt::math::CMatrixDouble& consist_matrix,
607  const hypotsp_t& hypots_pool, hypotsp_t* valid_hypots)
608 {
609  MRPT_START;
610  using namespace std;
611  using namespace mrpt::math;
612 
613  ASSERTDEB_(valid_hypots);
614  valid_hypots->clear();
615 
616  // evaluate the pair-wise consistency matrix
617  // compute dominant eigenvector
619  bool valid_lambda_ratio = this->computeDominantEigenVector(
620  consist_matrix, &u,
621  /*use_power_method=*/false);
622  if (!valid_lambda_ratio) return;
623 
624  // cout << "Dominant eigenvector: " << u.transpose() << endl;
625 
626  // discretize the indicator vector - maximize the dot product of
627  // w_unit .* u
628  ASSERTDEB_(u.size());
629  dynamic_vector<double> w(u.size(), 0); // discretized indicator vector
630  double dot_product = 0;
631  for (int i = 0; i != w.size(); ++i)
632  {
633  // stream for debugging reasons
634  stringstream ss;
635 
636  // make the necessary change and see if the dot product increases
637  w(i) = 1;
638  double potential_dot_product =
639  ((w.transpose() * u) / w.squaredNorm()).value();
640  ss << mrpt::format(
641  "current: %f | potential_dot_product: %f", dot_product,
642  potential_dot_product);
643  if (potential_dot_product > dot_product)
644  {
645  ss << " ==> ACCEPT";
646  dot_product = potential_dot_product;
647  }
648  else
649  {
650  ss << " ==> REJECT";
651  w(i) = 0; // revert the change
652  }
653  ss << endl;
654  // MRPT_LOG_DEBUG_STREAM(ss.str());
655  }
656  cout << "Outcome of discretization: " << w.transpose() << endl;
657  // mrpt::system::pause();
658 
659  // Current hypothesis is to be registered.
660  if (!w.isZero())
661  {
662  for (int wi = 0; wi != w.size(); ++wi)
663  {
664  if (w(wi) == 1)
665  {
666  // search through the potential hypotheses, find the one with
667  // the
668  // correct ID and register it.
669  valid_hypots->push_back(this->findHypotByID(hypots_pool, wi));
670  }
671  }
672  }
673  // mrpt::system::pause();
674 
675  MRPT_END;
676 }
677 
678 template <class GRAPH_T>
680  std::vector<uint32_t>& partition, std::vector<uint32_t>* groupA,
681  std::vector<uint32_t>* groupB, int max_nodes_in_group /*=5*/)
682 {
683  MRPT_START;
684 
685  using namespace mrpt;
686  using namespace mrpt::math;
687  using mrpt::graphs::TNodeID;
688 
689  // assertions
690  ASSERTDEBMSG_(groupA, "Pointer to groupA is not valid");
691  ASSERTDEBMSG_(groupB, "Pointer to groupB is not valid");
693  max_nodes_in_group == -1 || max_nodes_in_group > 0,
694  format(
695  "Value %d not permitted for max_nodes_in_group"
696  "Either use a positive integer, "
697  "or -1 for non-restrictive partition size",
698  max_nodes_in_group));
699 
700  // find a large difference between successive nodeIDs - that's where the cut
701  // is going to be
702  TNodeID prev_nodeID = 0;
703  size_t index_to_split = 1;
704  for (std::vector<uint32_t>::const_iterator it = partition.begin() + 1;
705  it != partition.end(); ++it, ++index_to_split)
706  {
707  TNodeID curr_nodeID = *it;
708 
709  if ((curr_nodeID - prev_nodeID) > m_lc_params.LC_min_nodeid_diff)
710  {
711  break;
712  }
713  // update the last nodeID
714  prev_nodeID = curr_nodeID;
715  }
716  ASSERTDEB_(partition.size() > index_to_split);
717 
718  // Fill the groups
719  *groupA = std::vector<uint32_t>(
720  partition.begin(), partition.begin() + index_to_split);
721  *groupB = std::vector<uint32_t>(
722  partition.begin() + index_to_split, partition.end());
723  // limit the number of nodes in each group
724  if (max_nodes_in_group != -1)
725  {
726  // groupA
727  if (groupA->size() > static_cast<size_t>(max_nodes_in_group))
728  {
729  *groupA = std::vector<uint32_t>(
730  groupA->begin(), groupA->begin() + max_nodes_in_group);
731  }
732  // groupB
733  if (groupB->size() > static_cast<size_t>(max_nodes_in_group))
734  {
735  *groupB = std::vector<uint32_t>(
736  groupB->end() - max_nodes_in_group, groupB->end());
737  }
738  }
739 
740  // mrpt::system::pause();
741  MRPT_END;
742 }
743 
744 template <class GRAPH_T>
746  const std::vector<uint32_t>& groupA, const std::vector<uint32_t>& groupB,
747  hypotsp_t* generated_hypots,
748  const TGenerateHypotsPoolAdParams* ad_params /*=NULL*/)
749 {
750  MRPT_START;
751  using namespace mrpt;
752  using namespace mrpt::containers;
753 
755  generated_hypots,
756  "generateHypotsPool: Given hypotsp_t pointer is invalid.");
757  generated_hypots->clear();
758 
759  MRPT_LOG_DEBUG_STREAM("Generating hypotheses for groups: " << endl);
761  "- groupA:\t" << getSTLContainerAsString(groupA)
762  << " - size: " << groupA.size() << endl);
764  "- groupB:\t" << getSTLContainerAsString(groupB)
765  << " - size: " << groupB.size() << endl);
766 
767  // verify that the number of laserScans is the same as the number of poses
768  // if
769  // the TGenerateHyptsPoolAdParams is used
770  // formulate into function and pass std::vector<uint32_t> and
771  // ad_params->group
772  // TODO
773  if (ad_params)
774  {
776  ad_params->groupA_params;
777  if (params.size())
778  {
779  size_t nodes_count = groupA.size();
780 
781  // map should have same size
783  nodes_count == params.size(),
784  format(
785  "Size mismatch between nodeIDs in group [%lu]"
786  " and corresponding properties map [%lu]",
787  nodes_count, params.size()));
788  }
789  }
790 
791  // use a hypothesis ID with which the consistency matrix will then be
792  // formed
793  int hypot_counter = 0;
794  int invalid_hypots = 0; // just for keeping track of them.
795  {
796  // iterate over all the nodes in both groups
798  b_it = groupB.begin();
799  b_it != groupB.end(); ++b_it)
800  {
802  a_it = groupA.begin();
803  a_it != groupA.end(); ++a_it)
804  {
805  // by default hypotheses will direct bi => ai; If the hypothesis
806  // is
807  // traversed the opposite way, take the opposite of the
808  // constraint
809  hypot_t* hypot = new hypot_t;
810  hypot->from = *b_it;
811  hypot->to = *a_it;
812  hypot->id = hypot_counter++;
813 
814  // [from] *b_it ====[edge]===> [to] *a_it
815 
816  // Fetch and set the pose and LaserScan of from, to nodeIDs
817  //
818  // even if icp_ad_params NULL, it will be handled appropriately
819  // by the
820  // getICPEdge fun.
821  // bool from_success, to_success;
822  TGetICPEdgeAdParams* icp_ad_params = NULL;
823  if (ad_params)
824  {
825  icp_ad_params = new TGetICPEdgeAdParams;
826  // from_success = fillNodePropsFromGroupParams(
827  fillNodePropsFromGroupParams(
828  *b_it, ad_params->groupB_params,
829  &icp_ad_params->from_params);
830  // to_success = fillNodePropsFromGroupParams(
831  fillNodePropsFromGroupParams(
832  *a_it, ad_params->groupA_params,
833  &icp_ad_params->to_params);
834 
835  // MRPT_LOG_DEBUG_STREAM(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
836  // MRPT_LOG_DEBUG_STREAM("From nodeID (other): " << *b_it);
837  // MRPT_LOG_DEBUG_STREAM("From params (other): "
838  //<< icp_ad_params->from_params.getAsString());
839  // MRPT_LOG_DEBUG_STREAM("from_success: " << (from_success?
840  // "TRUE" : "FALSE"));
841  // MRPT_LOG_DEBUG_STREAM("**********");
842  // MRPT_LOG_DEBUG_STREAM("To nodeID (own) : " << *a_it);
843  // MRPT_LOG_DEBUG_STREAM("To params (own) : "
844  //<< icp_ad_params->to_params.getAsString());
845  // MRPT_LOG_DEBUG_STREAM("to_success: " << (to_success?
846  // "TRUE" : "FALSE"));
847  // MRPT_LOG_DEBUG_STREAM("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
848  }
849 
850  // fetch the ICP constraint bi => ai
852  constraint_t edge;
853  bool found_edge = this->getICPEdge(
854  *b_it, *a_it, &edge, &icp_info, icp_ad_params);
855 
856  hypot->setEdge(edge);
857  hypot->goodness =
858  icp_info.goodness; // goodness related to the edge
859 
860  // Check if invalid
861  //
862  // Goodness Threshold
863  double goodness_thresh =
864  m_laser_params.goodness_threshold_win.getMedian() *
865  m_lc_icp_constraint_factor;
866  bool accept_goodness = icp_info.goodness > goodness_thresh;
868  "generateHypotsPool:\nCurr. Goodness: "
869  << icp_info.goodness << "|\t Threshold: " << goodness_thresh
870  << " => " << (accept_goodness ? "ACCEPT" : "REJECT")
871  << endl);
872 
873  if (!found_edge || !accept_goodness)
874  {
875  hypot->is_valid = false;
876  invalid_hypots++;
877  }
878  generated_hypots->push_back(hypot);
879  MRPT_LOG_DEBUG_STREAM(hypot->getAsString());
880 
881  // delete pointer to getICPEdge additional parameters if they
882  // were
883  // initialized
884  delete icp_ad_params;
885  }
886  }
888  "Generated pool of hypotheses...\tsize = "
889  << generated_hypots->size()
890  << "\tinvalid hypotheses: " << invalid_hypots);
891  }
892  // mrpt::system::pause();
893 
894  MRPT_END;
895 } // end of generateHypotsPool
896 
897 template <class GRAPH_T>
899  const mrpt::math::CMatrixDouble& consist_matrix,
900  mrpt::math::dynamic_vector<double>* eigvec, bool use_power_method /*=true*/)
901 {
902  MRPT_START;
903  using namespace mrpt;
904  using namespace mrpt::math;
905  using namespace std;
906  ASSERTDEB_(eigvec);
907 
908  this->m_time_logger.enter("DominantEigenvectorComputation");
909 
910  double lambda1, lambda2; // eigenvalues to use
911  bool is_valid_lambda_ratio = false;
912 
913  if (use_power_method)
914  {
916  "\nPower method for computing the first two "
917  "eigenvectors/eigenvalues hasn't been implemented yet\n");
918  }
919  else
920  { // call to eigenVectors method
921  CMatrixDouble eigvecs, eigvals;
922  consist_matrix.eigenVectors(eigvecs, eigvals);
923 
924  // assert that the eivenvectors, eigenvalues, consistency matrix are of
925  // the
926  // same size
928  eigvecs.size() == eigvals.size() &&
929  consist_matrix.size() == eigvals.size(),
930  mrpt::format(
931  "Size of eigvecs \"%lu\","
932  "eigvalues \"%lu\","
933  "consist_matrix \"%lu\" don't match",
934  static_cast<unsigned long>(eigvecs.size()),
935  static_cast<unsigned long>(eigvals.size()),
936  static_cast<unsigned long>(consist_matrix.size())));
937 
938  eigvecs.extractCol(eigvecs.cols() - 1, *eigvec);
939  lambda1 = eigvals(eigvals.rows() - 1, eigvals.cols() - 1);
940  lambda2 = eigvals(eigvals.rows() - 2, eigvals.cols() - 2);
941  }
942 
943  // I don't care about the sign of the eigenvector element
944  for (int i = 0; i != eigvec->size(); ++i)
945  {
946  (*eigvec)(i) = abs((*eigvec)(i));
947  }
948 
949  // check the ratio of the two eigenvalues - reject hypotheses set if ratio
950  // smaller than threshold
951  if (approximatelyEqual(0.0, lambda2, /**limit = */ 0.00001))
952  {
954  "Bad lambda2 value: "
955  << lambda2 << " => Skipping current evaluation." << endl);
956  return false;
957  }
958  double curr_lambda_ratio = lambda1 / lambda2;
960  "lambda1 = " << lambda1 << " | lambda2 = " << lambda2
961  << "| ratio = " << curr_lambda_ratio << endl);
962 
963  is_valid_lambda_ratio =
964  (curr_lambda_ratio > m_lc_params.LC_eigenvalues_ratio_thresh);
965 
966  this->m_time_logger.leave("DominantEigenvectorComputation");
967  return is_valid_lambda_ratio;
968 
969  MRPT_END;
970 } // end of computeDominantEigenVector
971 
972 template <class GRAPH_T>
974  const std::vector<uint32_t>& groupA, const std::vector<uint32_t>& groupB,
975  const hypotsp_t& hypots_pool, mrpt::math::CMatrixDouble* consist_matrix,
976  const paths_t* groupA_opt_paths /*=NULL*/,
977  const paths_t* groupB_opt_paths /*=NULL*/)
978 {
979  MRPT_START;
980 
981  using namespace mrpt;
982  using namespace mrpt::math;
983  using namespace mrpt::containers;
984  using namespace std;
985  using mrpt::graphs::TNodeID;
986 
988  consist_matrix, "Invalid pointer to the Consistency matrix is given");
990  static_cast<unsigned long>(consist_matrix->rows()) ==
991  hypots_pool.size() &&
992  static_cast<unsigned long>(consist_matrix->rows()) ==
993  hypots_pool.size(),
994  "Consistency matrix dimensions aren't equal to the hypotheses pool "
995  "size");
996 
998  ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
999  << endl
1000  << "In generatePWConsistencyMatrix:\n"
1001  << "\tgroupA: " << getSTLContainerAsString(groupA) << endl
1002  << "\tgroupB: " << getSTLContainerAsString(groupB) << endl
1003  << "\tHypots pool Size: " << hypots_pool.size());
1004 
1005  // b1
1006  for (std::vector<uint32_t>::const_iterator b1_it = groupB.begin();
1007  b1_it != groupB.end(); ++b1_it)
1008  {
1009  TNodeID b1 = *b1_it;
1010 
1011  // b2
1012  for (std::vector<uint32_t>::const_iterator b2_it = b1_it + 1;
1013  b2_it != groupB.end(); ++b2_it)
1014  {
1015  TNodeID b2 = *b2_it;
1016 
1017  // a1
1018  for (std::vector<uint32_t>::const_iterator a1_it = groupA.begin();
1019  a1_it != groupA.end(); ++a1_it)
1020  {
1021  TNodeID a1 = *a1_it;
1022  hypot_t* hypot_b2_a1 =
1023  this->findHypotByEnds(hypots_pool, b2, a1);
1024  // MRPT_LOG_DEBUG_STREAM("hypot_b2_a1: " <<
1025  // hypot_b2_a1->getAsString());
1026 
1027  // a2
1028  for (std::vector<uint32_t>::const_iterator a2_it = a1_it + 1;
1029  a2_it != groupA.end(); ++a2_it)
1030  {
1031  TNodeID a2 = *a2_it;
1032  hypot_t* hypot_b1_a2 =
1033  this->findHypotByEnds(hypots_pool, b1, a2);
1034  // MRPT_LOG_DEBUG_STREAM("hypot_b1_a2: " <<
1035  // hypot_b1_a2->getAsString());
1036 
1037  double consistency;
1038 
1039  // compute consistency element
1040  if (hypot_b2_a1->is_valid && hypot_b1_a2->is_valid)
1041  {
1042  // extract vector of hypotheses that connect the given
1043  // nodes,
1044  // instead of passing the whole hypothesis pool.
1045  hypotsp_t extracted_hypots;
1046  extracted_hypots.push_back(hypot_b2_a1);
1047  extracted_hypots.push_back(hypot_b1_a2);
1048 
1049  paths_t* curr_opt_paths = NULL;
1050  if (groupA_opt_paths || groupB_opt_paths)
1051  { // fill curr_opt_paths
1052  curr_opt_paths = new paths_t();
1053  }
1054 
1055  // decide on additional optimal paths
1056  if (curr_opt_paths)
1057  {
1058  // groupA
1059  if (groupA_opt_paths)
1060  { // a1 -> a2 optimal path
1061  const path_t* p = this->findPathByEnds(
1062  *groupA_opt_paths, a1, a2,
1063  /*throw_exc=*/true);
1064  curr_opt_paths->push_back(*p);
1065  }
1066  else
1067  { // empty
1068  curr_opt_paths->push_back(path_t());
1069  }
1070 
1071  if (groupB_opt_paths)
1072  { // b1 -> b2 optimal path
1073  const path_t* p = this->findPathByEnds(
1074  *groupB_opt_paths, b1, b2,
1075  /*throw_exc=*/true);
1076  curr_opt_paths->push_back(*p);
1077  }
1078  else
1079  { // empty
1080  curr_opt_paths->push_back(path_t());
1081  }
1082  }
1083 
1084  consistency = this->generatePWConsistencyElement(
1085  a1, a2, b1, b2, extracted_hypots, curr_opt_paths);
1086 
1087  delete curr_opt_paths;
1088  }
1089  else
1090  { // null those that don't look good
1091  consistency = 0;
1092  }
1093 
1094  // MRPT_LOG_DEBUG_STREAM(
1095  //"Adding hypothesis consistency for nodeIDs: "
1096  //<< "[b1] " << b1 << ", [b2] -> " << b2
1097  //<< ", [a1] -> " << a1 << ", [a2] -> " << a2
1098  //<< " ==> " << consistency << endl);
1099 
1100  // fill the PW consistency matrix corresponding element -
1101  // symmetrical
1102  int id1 = hypot_b2_a1->id;
1103  int id2 = hypot_b1_a2->id;
1104 
1105  (*consist_matrix)(id1, id2) = consistency;
1106  (*consist_matrix)(id2, id1) = consistency;
1107 
1108  // MRPT_LOG_DEBUG_STREAM("id1 = " << id1 << "\t|"
1109  //<< "id2 = " << id2 << "\t|"
1110  //<< "consistency = " << consistency);
1111  }
1112  }
1113  }
1114  }
1115 
1116  // MRPT_LOG_WARN_STREAM("Consistency matrix:" << endl
1117  //<< this->header_sep << endl
1118  //<< *consist_matrix << endl);
1119 
1120  MRPT_END;
1121 } // end of generatePWConsistenciesMatrix
1122 
1123 template <class GRAPH_T>
1127  const hypotsp_t& hypots, const paths_t* opt_paths /*=NULL*/)
1128 {
1129  MRPT_START;
1130  using namespace std;
1131  using namespace mrpt;
1132  using namespace mrpt::math;
1133  using namespace mrpt::graphslam;
1134  using namespace mrpt::graphslam::detail;
1135 
1136  // MRPT_LOG_DEBUG_STREAM("In generatePWConsistencyElement.\n"
1137  //<< "\t[" << a1 << ", " << a2 << "]\n"
1138  //<< "\t[" << b1 << ", " << b2 << "]");
1139  // MRPT_LOG_DEBUG_STREAM("a1->a2 optimal path:"
1140  //<< (opt_paths && !opt_paths->begin()->isEmpty()?
1141  // opt_paths->begin()->getAsString() :
1142  //"NONE"));
1143  // MRPT_LOG_DEBUG_STREAM("b1->b2 optimal path: "
1144  //<< (opt_paths && !opt_paths->rbegin()->isEmpty()?
1145  // opt_paths->rbegin()->getAsString() :
1146  //"NONE"));
1147 
1148  // standard size assertions
1149  ASSERTDEB_(hypots.size() == 2);
1150  if (opt_paths)
1151  {
1152  ASSERTDEB_(opt_paths->size() == 2);
1153  }
1154 
1155  //
1156  // get the Dijkstra links
1157  //
1158  // a1 ==> a2
1159  const path_t* path_a1_a2;
1160  if (!opt_paths || opt_paths->begin()->isEmpty())
1161  {
1163  "Running dijkstra [a1] " << a1 << " => [a2] " << a2);
1164  execDijkstraProjection(/*starting_node=*/a1, /*ending_node=*/a2);
1165  path_a1_a2 = this->queryOptimalPath(a2);
1166  }
1167  else
1168  { // fetch the path from the opt_paths arg
1169  // TODO dubious practice
1170  path_a1_a2 = &(*opt_paths->begin());
1171  }
1172  ASSERTDEB_(path_a1_a2);
1173  path_a1_a2->assertIsBetweenNodeIDs(/*start=*/a1, /*end*/ a2);
1174 
1175  // b1 ==> b2
1176  const path_t* path_b1_b2;
1177  if (!opt_paths || opt_paths->rend()->isEmpty())
1178  {
1180  "Running djkstra [b1] " << b1 << " => [b2] " << b2);
1181  execDijkstraProjection(/*starting_node=*/b1, /*ending_node=*/b2);
1182  path_b1_b2 = this->queryOptimalPath(b2);
1183  }
1184  else
1185  { // fetch the path from the opt_paths arg
1186  path_b1_b2 = &(*opt_paths->rbegin());
1187  }
1188  ASSERTDEB_(path_b1_b2);
1189  path_b1_b2->assertIsBetweenNodeIDs(/*start=*/b1, /*end*/ b2);
1190  // get the edges of the hypotheses
1191  // by default hypotheses are stored bi => ai
1192  //
1193  // Backwards edge: a2=>b1
1194  hypot_t* hypot_b1_a2 = this->findHypotByEnds(hypots, b1, a2);
1195  // forward edge b2=>a1
1196  hypot_t* hypot_b2_a1 = this->findHypotByEnds(hypots, b2, a1);
1197 
1198  // Composition of Poses
1199  // Order : a1 ==> a2 ==> b1 ==> b2 ==> a1
1200  constraint_t res_transform(path_a1_a2->curr_pose_pdf);
1201  res_transform += hypot_b1_a2->getInverseEdge();
1202  res_transform += path_b1_b2->curr_pose_pdf;
1203  res_transform += hypot_b2_a1->getEdge();
1204 
1206  "\n-----------Resulting Transformation----------- Hypots: #"
1207  << hypot_b1_a2->id << ", #" << hypot_b2_a1->id << endl
1208  << "a1 --> a2 => b1 --> b2 => a1: " << a1 << " --> " << a2 << " => "
1209  << b1 << " --> " << b2 << " => " << a1 << endl
1210  << res_transform << endl
1211  << endl
1212  << "DIJKSTRA: " << a1 << " --> " << a2 << ": "
1213  << path_a1_a2->curr_pose_pdf << endl
1214  << "DIJKSTRA: " << b1 << " --> " << b2 << ": "
1215  << path_b1_b2->curr_pose_pdf << endl
1216  << "hypot_b1_a2(inv):\n"
1217  << hypot_b1_a2->getInverseEdge() << endl
1218  << "hypot_b2_a1:\n"
1219  << hypot_b2_a1->getEdge() << endl);
1220 
1221  // get the vector of the corresponding transformation - [x, y, phi] form
1223  res_transform.getMeanVal().getAsVector(T);
1224 
1225  // information matrix
1226  CMatrixDouble33 cov_mat;
1227  res_transform.getCovariance(cov_mat);
1228 
1229  // there has to be an error with the initial Olson formula - p.15.
1230  // There must be a minus in the exponent and the covariance matrix instead
1231  // of
1232  // the information matrix.
1233  double exponent = (-T.transpose() * cov_mat * T).value();
1234  double consistency_elem = exp(exponent);
1235 
1236  // cout << "T = " << endl << T << endl;
1237  // cout << "exponent = " << exponent << endl;
1238  // cout << "consistency_elem = " << consistency_elem << endl;
1239  // mrpt::system::pause();
1240 
1241  return consistency_elem;
1242  MRPT_END;
1243 } // end of generatePWConsistencyElement
1244 
1245 template <class GRAPH_T>
1248  const paths_t& vec_paths, const mrpt::graphs::TNodeID& src,
1249  const mrpt::graphs::TNodeID& dst, bool throw_exc /*=true*/)
1250 {
1251  using namespace mrpt;
1252 
1253  ASSERTDEB_(vec_paths.size());
1254  const path_t* res = NULL;
1255 
1256  for (typename paths_t::const_iterator cit = vec_paths.begin();
1257  cit != vec_paths.end(); ++cit)
1258  {
1259  if (cit->getSource() == src && cit->getDestination() == dst)
1260  {
1261  res = &(*cit);
1262  break;
1263  }
1264  }
1265  if (throw_exc && !res)
1266  {
1268  format(
1269  "Path for %lu => %lu is not found. Exiting...\n",
1270  static_cast<unsigned long>(src),
1271  static_cast<unsigned long>(dst)));
1272  }
1273 
1274  return res;
1275 }
1276 
1277 template <class GRAPH_T>
1280  const hypotsp_t& vec_hypots, const mrpt::graphs::TNodeID& from,
1281  const mrpt::graphs::TNodeID& to, bool throw_exc /*=true*/)
1282 {
1283  using namespace mrpt::graphslam::detail;
1284  using namespace std;
1285 
1286  for (typename hypotsp_t::const_iterator v_cit = vec_hypots.begin();
1287  v_cit != vec_hypots.end(); v_cit++)
1288  {
1289  if ((*v_cit)->hasEnds(from, to))
1290  {
1291  // cout << "findHypotByEnds: Found hypot " << from
1292  //<< " => " << to << " : " << (*v_cit)->getAsString() << endl;
1293  return *v_cit;
1294  }
1295  }
1296 
1297  // not found.
1298  if (throw_exc)
1299  {
1301  }
1302  else
1303  {
1304  return NULL;
1305  }
1306 } // end of findHypotByEnds
1307 
1308 template <class GRAPH_T>
1311  const hypotsp_t& vec_hypots, const size_t& id, bool throw_exc /*=true*/)
1312 {
1313  using namespace mrpt::graphslam::detail;
1314 
1315  for (typename hypotsp_t::const_iterator v_cit = vec_hypots.begin();
1316  v_cit != vec_hypots.end(); v_cit++)
1317  {
1318  if ((*v_cit)->id == id)
1319  {
1320  return *v_cit;
1321  }
1322  }
1323 
1324  // not found.
1325  if (throw_exc)
1326  {
1328  }
1329  else
1330  {
1331  return NULL;
1332  }
1333 }
1334 
1335 template <class GRAPH_T>
1337  mrpt::graphs::TNodeID starting_node /*=0*/,
1338  mrpt::graphs::TNodeID ending_node /*=INVALID_NODEID*/)
1339 {
1340  MRPT_START;
1341  using namespace std;
1342  using namespace mrpt;
1343  using namespace mrpt::math;
1344  using mrpt::graphs::TNodeID;
1345 
1346  // for the full algorithm see
1347  // - Recognizing places using spectrally clustered local matches - E.Olson,
1348  // p.6
1349 
1350  this->m_time_logger.enter("Dijkstra Projection");
1351  const std::string dijkstra_end =
1352  "----------- Done with Dijkstra Projection... ----------";
1353 
1354  // ending_node is either INVALID_NODEID or one of the already registered
1355  // nodeIDs
1356  ASSERTDEB_(
1357  ending_node == INVALID_NODEID ||
1358  (ending_node >= 0 && ending_node < this->m_graph->nodeCount()));
1359  ASSERTDEBMSG_(
1360  starting_node != ending_node, "Starting and Ending nodes coincede");
1361 
1362  // debugging message
1363  stringstream ss_debug("");
1364  ss_debug << "Executing Dijkstra Projection: " << starting_node << " => ";
1365  if (ending_node == INVALID_NODEID)
1366  {
1367  ss_debug << "..." << endl;
1368  }
1369  else
1370  {
1371  ss_debug << ending_node << endl;
1372  }
1373 
1374  if (this->m_graph->nodeCount() < m_dijkstra_node_count_thresh)
1375  {
1376  return;
1377  }
1378 
1379  // keep track of the nodes that I have visited
1380  std::vector<bool> visited_nodes(this->m_graph->nodeCount(), false);
1381  m_node_optimal_paths.clear();
1382 
1383  // get the neighbors of each node
1384  std::map<TNodeID, std::set<TNodeID>> neighbors_of;
1385  this->m_graph->getAdjacencyMatrix(neighbors_of);
1386 
1387  // initialize a pool of TUncertaintyPaths - draw the minimum-uncertainty
1388  // path during
1389  // execution
1390  std::set<path_t*> pool_of_paths;
1391  // get the edge to each one of the neighboring nodes of the starting node
1392  std::set<TNodeID> starting_node_neighbors(neighbors_of.at(starting_node));
1394  starting_node_neighbors.begin();
1395  n_it != starting_node_neighbors.end(); ++n_it)
1396  {
1397  path_t* path_between_neighbors = new path_t();
1398  this->getMinUncertaintyPath(
1399  starting_node, *n_it, path_between_neighbors);
1400 
1401  pool_of_paths.insert(path_between_neighbors);
1402  }
1403  // just visited the first node
1404  visited_nodes.at(starting_node) = true;
1405 
1406  //// TODO Remove these - >>>>>>>>>>>>>>>>>>>>
1407  //// printing the pool for verification
1408  // cout << "Pool of Paths: " << endl;
1409  // for (typename std::set<path_t*>::const_iterator it =
1410  // pool_of_paths.begin();
1411  // it != pool_of_paths.end(); ++it) {
1412  // printSTLContainer((*it)->nodes_traversed);
1413  //}
1414  // cout << "------ Done with the starting node ... ------" << endl;
1415  // int iters = 0;
1416  //// TODO Remove these - <<<<<<<<<<<<<<<<<<<<< vvvUNCOMMENT BELOW AS WELLvvv
1417 
1418  while (true)
1419  {
1420  // if there is at least one false, exit loop
1421  for (std::vector<bool>::const_iterator it = visited_nodes.begin();
1422  it != visited_nodes.end(); ++it)
1423  {
1424  if (!*it)
1425  {
1426  break;
1427  }
1428  }
1429 
1430  // if an ending nodeID has been specified, end the method when the path
1431  // to
1432  // it is found.
1433  if (ending_node != INVALID_NODEID)
1434  {
1435  if (visited_nodes.at(ending_node))
1436  {
1437  // MRPT_LOG_DEBUG_STREAM(dijkstra_end);
1438  this->m_time_logger.leave("Dijkstra Projection");
1439  return;
1440  }
1441  }
1442 
1443  path_t* optimal_path = this->popMinUncertaintyPath(&pool_of_paths);
1444  TNodeID dest = optimal_path->getDestination();
1445 
1446  //// TODO Remove these - >>>>>>>>>>>>>>>>>>>> ^^^UNCOMMENT ABOVE AS
1447  /// WELL^^^
1448  // cout << iters << " " << std::string(40, '>') << endl;
1449  // cout << "current path Destination: " << dest << endl;
1450  //// printing the pool for verification
1451  // cout << "Pool of Paths: " << endl;
1452  // for (typename std::set<path_t*>::const_iterator
1453  // it = pool_of_paths.begin();
1454  // it != pool_of_paths.end(); ++it) {
1455  // printSTLContainer((*it)->nodes_traversed);
1456  //}
1457  // cout << "Nodes visited: " << endl;
1458  // std::vector<int> tmp_vec;
1459  // for (int i = 0; i != visited_nodes.size(); ++i) {
1460  // tmp_vec.push_back(i);
1461  //}
1462  // printSTLContainer(tmp_vec); cout << endl; // indices of numbers
1463  // printSTLContainer(visited_nodes); // actual flags
1464  // cout << std::string(40, '<') << " " << iters++ << endl;
1465  // mrpt::system::pause();
1466  //// TODO Remove these - <<<<<<<<<<<<<<<<<<<<<
1467 
1468  if (!visited_nodes.at(dest))
1469  {
1470  m_node_optimal_paths[dest] = optimal_path;
1471  visited_nodes.at(dest) = true;
1472 
1473  // for all the edges leaving this node .. compose the transforms
1474  // with the
1475  // current pool of paths.
1476  this->addToPaths(
1477  &pool_of_paths, *optimal_path, neighbors_of.at(dest));
1478  }
1479  }
1480 
1481  // MRPT_LOG_DEBUG_STREAM(dijkstra_end);
1482  this->m_time_logger.leave("Dijkstra Projection");
1483  MRPT_END;
1484 }
1485 
1486 template <class GRAPH_T>
1488  std::set<path_t*>* pool_of_paths, const path_t& current_path,
1489  const std::set<mrpt::graphs::TNodeID>& neighbors) const
1490 {
1491  MRPT_START;
1492  using namespace std;
1493  using namespace mrpt::graphslam;
1494  using mrpt::graphs::TNodeID;
1495 
1496  TNodeID node_to_append_from = current_path.getDestination();
1497 
1498  // compose transforms for every neighbor of node_to_append_from *except*
1499  // for the link connecting node_to_append_from and the second to last node
1500  // in
1501  // the current_path
1502  TNodeID second_to_last_node = current_path.nodes_traversed.rbegin()[1];
1503  for (std::set<TNodeID>::const_iterator neigh_it = neighbors.begin();
1504  neigh_it != neighbors.end(); ++neigh_it)
1505  {
1506  if (*neigh_it == second_to_last_node) continue;
1507 
1508  // get the path between node_to_append_from, *node_it
1509  path_t path_between_nodes;
1510  this->getMinUncertaintyPath(
1511  node_to_append_from, *neigh_it, &path_between_nodes);
1512 
1513  // format the path to append
1514  path_t* path_to_append = new path_t();
1515  *path_to_append = current_path;
1516  *path_to_append += path_between_nodes;
1517 
1518  pool_of_paths->insert(path_to_append);
1519  }
1520 
1521  MRPT_END;
1522 }
1523 
1524 template <class GRAPH_T>
1526  GRAPH_T>::queryOptimalPath(const mrpt::graphs::TNodeID node) const
1527 {
1528  using namespace std;
1529 
1530  path_t* path = NULL;
1532  search = m_node_optimal_paths.find(node);
1533  if (search != m_node_optimal_paths.end())
1534  {
1535  path = search->second;
1536  }
1537 
1538  // MRPT_LOG_DEBUG_STREAM("Queried optimal path for nodeID: " << node
1539  //<< " ==> Path: " << (path? "Found" : "NOT Found"));
1540  return path;
1541 }
1542 
1543 template <class GRAPH_T>
1545  const mrpt::graphs::TNodeID from, const mrpt::graphs::TNodeID to,
1546  path_t* path_between_nodes) const
1547 {
1548  MRPT_START;
1549  using namespace mrpt::math;
1550  using namespace std;
1551 
1552  ASSERTDEBMSG_(
1553  this->m_graph->edgeExists(from, to) ||
1554  this->m_graph->edgeExists(to, from),
1555  mrpt::format(
1556  "\nEdge between the provided nodeIDs"
1557  "(%lu <-> %lu) does not exist\n",
1558  from, to));
1559  ASSERTDEB_(path_between_nodes);
1560 
1561  // cout << "getMinUncertaintyPath: " << from << " => " << to << endl;
1562 
1563  // don't add to the path_between_nodes, just fill it in afterwards
1564  path_between_nodes->clear();
1565 
1566  // iterate over all the edges, ignore the ones that are all 0s - find the
1567  // one that is with the lowest uncertainty
1568  double curr_determinant = 0;
1569  // forward edges from -> to
1570  std::pair<edges_citerator, edges_citerator> fwd_edges_pair =
1571  this->m_graph->getEdges(from, to);
1572 
1573  // cout << "Forward edges: " << endl;
1574  // for (edges_citerator e_it = fwd_edges_pair.first; e_it !=
1575  // fwd_edges_pair.second;
1576  //++e_it) {
1577  // cout << e_it->second << endl;
1578  //}
1579 
1580  for (edges_citerator edges_it = fwd_edges_pair.first;
1581  edges_it != fwd_edges_pair.second; ++edges_it)
1582  {
1583  // operate on a temporary object instead of the real edge - otherwise
1584  // function is non-const
1585  constraint_t curr_edge;
1586  curr_edge.copyFrom(edges_it->second);
1587 
1588  // is it all 0s?
1589  CMatrixDouble33 inf_mat;
1590  curr_edge.getInformationMatrix(inf_mat);
1591 
1592  if (inf_mat == CMatrixDouble33() || std::isnan(inf_mat(0, 0)))
1593  {
1594  inf_mat.unit();
1595  curr_edge.cov_inv = inf_mat;
1596  }
1597 
1598  path_t curr_path(from); // set the starting node
1599  curr_path.addToPath(to, curr_edge);
1600 
1601  // update the resulting path_between_nodes if its determinant is smaller
1602  // than the determinant of the current path_between_nodes
1603  if (curr_determinant < curr_path.getDeterminant())
1604  {
1605  curr_determinant = curr_path.getDeterminant();
1606  *path_between_nodes = curr_path;
1607  }
1608  }
1609  // backwards edges to -> from
1610  std::pair<edges_citerator, edges_citerator> bwd_edges_pair =
1611  this->m_graph->getEdges(to, from);
1612 
1613  // cout << "Backwards edges: " << endl;
1614  // for (edges_citerator e_it = bwd_edges_pair.first; e_it !=
1615  // bwd_edges_pair.second;
1616  //++e_it) {
1617  // cout << e_it->second << endl;
1618  //}
1619 
1620  for (edges_citerator edges_it = bwd_edges_pair.first;
1621  edges_it != bwd_edges_pair.second; ++edges_it)
1622  {
1623  // operate on a temporary object instead of the real edge - otherwise
1624  // function is non-const
1625  constraint_t curr_edge;
1626  (edges_it->second).inverse(curr_edge);
1627 
1628  // is it all 0s?
1629  CMatrixDouble33 inf_mat;
1630  curr_edge.getInformationMatrix(inf_mat);
1631 
1632  if (inf_mat == CMatrixDouble33() || std::isnan(inf_mat(0, 0)))
1633  {
1634  inf_mat.unit();
1635  curr_edge.cov_inv = inf_mat;
1636  }
1637 
1638  path_t curr_path(from); // set the starting node
1639  curr_path.addToPath(to, curr_edge);
1640 
1641  // update the resulting path_between_nodes if its determinant is smaller
1642  // than the determinant of the current path_between_nodes
1643  if (curr_determinant < curr_path.getDeterminant())
1644  {
1645  curr_determinant = curr_path.getDeterminant();
1646  *path_between_nodes = curr_path;
1647  }
1648  }
1649 
1650  MRPT_END;
1651 }
1652 
1653 template <class GRAPH_T>
1655  typename std::set<path_t*>* pool_of_paths) const
1656 {
1657  MRPT_START;
1658  using namespace std;
1659 
1660  // cout << "Determinants: ";
1661  path_t* optimal_path = NULL;
1662  double curr_determinant = 0;
1663  for (typename std::set<path_t*>::const_iterator it = pool_of_paths->begin();
1664  it != pool_of_paths->end(); ++it)
1665  {
1666  // cout << (*it)->getDeterminant() << ", ";
1667 
1668  // keep the largest determinant - we are in INFORMATION form.
1669  if (curr_determinant < (*it)->getDeterminant())
1670  {
1671  curr_determinant = (*it)->getDeterminant();
1672  optimal_path = *it;
1673  }
1674  }
1675 
1676  ASSERTDEB_(optimal_path);
1677  pool_of_paths->erase(optimal_path); // erase it from the pool
1678 
1679  return optimal_path;
1680  MRPT_END;
1681 }
1682 
1683 template <class GRAPH_T>
1685  const mrpt::graphs::TNodeID& from, const mrpt::graphs::TNodeID& to,
1686  const constraint_t& rel_edge)
1687 {
1688  MRPT_START;
1689 
1690  using namespace std;
1691  using namespace mrpt::math;
1692 
1693  // mean difference
1694  pose_t initial_estim =
1695  this->m_graph->nodes.at(to) - this->m_graph->nodes.at(from);
1696  dynamic_vector<double> mean_diff;
1697  (rel_edge.getMeanVal() - initial_estim).getAsVector(mean_diff);
1698 
1699  // covariance matrix
1700  CMatrixDouble33 cov_mat;
1701  rel_edge.getCovariance(cov_mat);
1702 
1703  // mahalanobis distance computation
1704  double mahal_distance =
1705  mrpt::math::mahalanobisDistance2(mean_diff, cov_mat);
1706  bool mahal_distance_null = std::isnan(mahal_distance);
1707  if (!mahal_distance_null)
1708  {
1709  m_laser_params.mahal_distance_ICP_odom_win.addNewMeasurement(
1710  mahal_distance);
1711  }
1712 
1713  // double threshold = m_laser_params.mahal_distance_ICP_odom_win.getMean() +
1714  // 2*m_laser_params.mahal_distance_ICP_odom_win.getStdDev();
1715  double threshold =
1716  m_laser_params.mahal_distance_ICP_odom_win.getMedian() * 4;
1717  bool accept_edge =
1718  (threshold >= mahal_distance && !mahal_distance_null) ? true : false;
1719 
1720  // cout << "Suggested Edge: " << rel_edge.getMeanVal() << "|\tInitial
1721  // Estim.: " << initial_estim
1722  //<< "|\tMahalanobis Dist: " << mahal_distance << "|\tThresh.: " <<
1723  // threshold
1724  //<< " => " << (accept_edge? "ACCEPT": "REJECT") << endl;
1725 
1726  return accept_edge;
1727  MRPT_END;
1728 }
1729 
1730 template <class GRAPH_T>
1732 {
1733  // MRPT_LOG_DEBUG_STREAM("Registering hypothesis: " <<
1734  // hypot.getAsString([>oneline=<] true));
1735  this->registerNewEdge(hypot.from, hypot.to, hypot.getEdge());
1736 }
1737 
1738 template <class GRAPH_T>
1740  const mrpt::graphs::TNodeID& from, const mrpt::graphs::TNodeID& to,
1741  const constraint_t& rel_edge)
1742 {
1743  MRPT_START;
1744  using namespace mrpt::math;
1745  using namespace std;
1746  parent_t::registerNewEdge(from, to, rel_edge);
1747 
1748  // keep track of the registered edges...
1749  m_edge_types_to_nums["ICP2D"]++;
1750 
1751  // keep track of the registered edges...
1752  if (absDiff(to, from) > m_lc_params.LC_min_nodeid_diff)
1753  {
1754  m_edge_types_to_nums["LC"]++;
1755  this->m_just_inserted_lc = true;
1756  MRPT_LOG_INFO("\tLoop Closure edge!");
1757  }
1758  else
1759  {
1760  this->m_just_inserted_lc = false;
1761  }
1762 
1763  // actuall registration
1764  this->m_graph->insertEdge(from, to, rel_edge);
1765 
1766  MRPT_END;
1767 }
1768 
1769 template <class GRAPH_T>
1771  mrpt::graphslam::CWindowManager* win_manager)
1772 {
1773  // call parent_t class method
1774  parent_t::setWindowManagerPtr(win_manager);
1775 
1776  // may still be null..
1777  if (this->m_win_manager)
1778  {
1779  if (this->m_win_observer)
1780  {
1781  this->m_win_observer->registerKeystroke(
1782  m_laser_params.keystroke_laser_scans,
1783  "Toggle LaserScans Visualization");
1784  this->m_win_observer->registerKeystroke(
1785  m_lc_params.keystroke_map_partitions,
1786  "Toggle Map Partitions Visualization");
1787  }
1788 
1790  "Fetched the window manager, window observer successfully.");
1791  }
1792 }
1793 template <class GRAPH_T>
1795  const std::map<std::string, bool>& events_occurred)
1796 {
1797  MRPT_START;
1798  parent_t::notifyOfWindowEvents(events_occurred);
1799 
1800  // laser scans
1801  if (events_occurred.at(m_laser_params.keystroke_laser_scans))
1802  {
1803  this->toggleLaserScansVisualization();
1804  }
1805  // map partitions
1806  if (events_occurred.at(m_lc_params.keystroke_map_partitions))
1807  {
1808  this->toggleMapPartitionsVisualization();
1809  }
1810 
1811  MRPT_END;
1812 }
1813 
1814 template <class GRAPH_T>
1816 {
1817  using namespace mrpt;
1818  using namespace mrpt::gui;
1819  using namespace mrpt::math;
1820  using namespace mrpt::opengl;
1821 
1822  // textmessage - display the number of partitions
1823  this->m_win_manager->assignTextMessageParameters(
1824  /* offset_y* = */ &m_lc_params.offset_y_map_partitions,
1825  /* text_index* = */ &m_lc_params.text_index_map_partitions);
1826 
1827  // just add an empty CSetOfObjects in the scene - going to populate it later
1828  CSetOfObjects::Ptr map_partitions_obj =
1829  mrpt::make_aligned_shared<CSetOfObjects>();
1830  map_partitions_obj->setName("map_partitions");
1831 
1832  COpenGLScene::Ptr& scene = this->m_win->get3DSceneAndLock();
1833  scene->insert(map_partitions_obj);
1834  this->m_win->unlockAccess3DScene();
1835  this->m_win->forceRepaint();
1836 }
1837 
1838 template <class GRAPH_T>
1840 {
1841  using namespace mrpt;
1842  using namespace mrpt::gui;
1843  using namespace mrpt::math;
1844  using namespace mrpt::opengl;
1845  using namespace mrpt::poses;
1846 
1847  // textmessage
1848  std::stringstream title;
1849  title << "# Partitions: " << m_curr_partitions.size();
1850  this->m_win_manager->addTextMessage(
1851  5, -m_lc_params.offset_y_map_partitions, title.str(),
1852  mrpt::img::TColorf(m_lc_params.balloon_std_color),
1853  /* unique_index = */ m_lc_params.text_index_map_partitions);
1854 
1855  // update the partitioning visualization
1856  COpenGLScene::Ptr& scene = this->m_win->get3DSceneAndLock();
1857 
1858  // fetch the partitions CSetOfObjects
1859  CSetOfObjects::Ptr map_partitions_obj;
1860  {
1861  CRenderizable::Ptr obj = scene->getByName("map_partitions");
1862  // do not check for null ptr - must be properly created in the init*
1863  // method
1864  map_partitions_obj = std::dynamic_pointer_cast<CSetOfObjects>(obj);
1865  }
1866 
1867  int partitionID = 0;
1868  bool partition_contains_last_node = false;
1869  bool found_last_node =
1870  false; // last node must exist in one partition at all cost TODO
1872  "Searching for the partition of the last nodeID: "
1873  << (this->m_graph->nodeCount() - 1));
1874 
1875  for (partitions_t::const_iterator p_it = m_curr_partitions.begin();
1876  p_it != m_curr_partitions.end(); ++p_it, ++partitionID)
1877  {
1878  // MRPT_LOG_DEBUG_STREAM("Working on Partition #" << partitionID);
1879  std::vector<uint32_t> nodes_list = *p_it;
1880 
1881  // finding the partition in which the last node is in
1882  if (std::find(
1883  nodes_list.begin(), nodes_list.end(),
1884  this->m_graph->nodeCount() - 1) != nodes_list.end())
1885  {
1886  partition_contains_last_node = true;
1887 
1888  found_last_node = true;
1889  }
1890  else
1891  {
1892  partition_contains_last_node = false;
1893  }
1894 
1895  // fetch the current partition object if it exists - create otherwise
1896  std::string partition_obj_name =
1897  mrpt::format("partition_%d", partitionID);
1898  std::string balloon_obj_name = mrpt::format("#%d", partitionID);
1899 
1901  map_partitions_obj->getByName(partition_obj_name);
1902  CSetOfObjects::Ptr curr_partition_obj;
1903  if (obj)
1904  {
1905  // MRPT_LOG_DEBUG_STREAM(
1906  //"\tFetching CSetOfObjects partition object for partition #" <<
1907  // partitionID);
1908  curr_partition_obj = std::dynamic_pointer_cast<CSetOfObjects>(obj);
1909  if (m_lc_params.LC_check_curr_partition_only)
1910  { // make all but the last partition invisible
1911  curr_partition_obj->setVisibility(partition_contains_last_node);
1912  }
1913  }
1914  else
1915  {
1917  "\tCreating a new CSetOfObjects partition object for partition "
1918  "#"
1919  << partitionID);
1920  curr_partition_obj = mrpt::make_aligned_shared<CSetOfObjects>();
1921  curr_partition_obj->setName(partition_obj_name);
1922  if (m_lc_params.LC_check_curr_partition_only)
1923  {
1924  // make all but the last partition invisible
1925  curr_partition_obj->setVisibility(partition_contains_last_node);
1926  }
1927 
1928  // MRPT_LOG_DEBUG_STREAM("\t\tCreating a new CSphere balloon
1929  // object");
1930  CSphere::Ptr balloon_obj = mrpt::make_aligned_shared<CSphere>();
1931  balloon_obj->setName(balloon_obj_name);
1932  balloon_obj->setRadius(m_lc_params.balloon_radius);
1933  balloon_obj->setColor_u8(m_lc_params.balloon_std_color);
1934  balloon_obj->enableShowName();
1935 
1936  curr_partition_obj->insert(balloon_obj);
1937 
1938  // set of lines connecting the graph nodes to the balloon
1939  // MRPT_LOG_DEBUG_STREAM(
1940  //"\t\tCreating set of lines that will connect to the Balloon");
1941  CSetOfLines::Ptr connecting_lines_obj =
1942  mrpt::make_aligned_shared<CSetOfLines>();
1943  connecting_lines_obj->setName("connecting_lines");
1944  connecting_lines_obj->setColor_u8(
1945  m_lc_params.connecting_lines_color);
1946  connecting_lines_obj->setLineWidth(0.1f);
1947 
1948  curr_partition_obj->insert(connecting_lines_obj);
1949 
1950  // add the created CSetOfObjects to the total CSetOfObjects
1951  // responsible
1952  // for the map partitioning
1953  map_partitions_obj->insert(curr_partition_obj);
1954  // MRPT_LOG_DEBUG_STREAM("\tInserted new CSetOfObjects
1955  // successfully");
1956  }
1957  // up to now the CSetOfObjects exists and the balloon inside it as
1958  // well..
1959 
1960  std::pair<double, double> centroid_coords;
1961  this->computeCentroidOfNodesVector(nodes_list, &centroid_coords);
1962 
1963  TPoint3D balloon_location(
1964  centroid_coords.first, centroid_coords.second,
1965  m_lc_params.balloon_elevation);
1966 
1967  // MRPT_LOG_DEBUG_STREAM("\tUpdating the balloon position");
1968  // set the balloon properties
1969  CSphere::Ptr balloon_obj;
1970  {
1971  // place the partitions baloon at the centroid elevated by a fixed Z
1972  // value
1974  curr_partition_obj->getByName(balloon_obj_name);
1975  balloon_obj = std::dynamic_pointer_cast<CSphere>(obj);
1976  balloon_obj->setLocation(balloon_location);
1977  if (partition_contains_last_node)
1978  balloon_obj->setColor_u8(m_lc_params.balloon_curr_color);
1979  else
1980  balloon_obj->setColor_u8(m_lc_params.balloon_std_color);
1981  }
1982 
1983  // MRPT_LOG_DEBUG_STREAM("\tUpdating the lines connecting nodes to
1984  // balloon");
1985  // set the lines connecting the nodes of the partition to the partition
1986  // balloon - set it from scratch all the times since the node positions
1987  // tend to change according to the dijkstra position estimation
1988  CSetOfLines::Ptr connecting_lines_obj;
1989  {
1990  // place the partitions baloon at the centroid elevated by a fixed Z
1991  // value
1993  curr_partition_obj->getByName("connecting_lines");
1994  connecting_lines_obj = std::dynamic_pointer_cast<CSetOfLines>(obj);
1995 
1996  connecting_lines_obj->clear();
1997 
1998  for (std::vector<uint32_t>::const_iterator it = nodes_list.begin();
1999  it != nodes_list.end(); ++it)
2000  {
2001  CPose3D curr_pose(this->m_graph->nodes.at(*it));
2002  TPoint3D curr_node_location(curr_pose.asTPose());
2003 
2004  TSegment3D connecting_line(
2005  curr_node_location, balloon_location);
2006  connecting_lines_obj->appendLine(connecting_line);
2007  }
2008  }
2009  // MRPT_LOG_DEBUG_STREAM("Done working on partition #" << partitionID);
2010  }
2011 
2012  if (!found_last_node)
2013  {
2014  /// @todo Have some sorts of a string_view instead
2015  THROW_EXCEPTION("Last inserted nodeID was not found in any partition.");
2016  }
2017 
2018  // remove outdated partitions
2019  // these occur when more partitions existed during the previous
2020  // visualization
2021  // update, thus the partitions with higher ID than the maximum partitionID
2022  // would otherwise remain in the visual as zombie partitions
2023  size_t prev_size = m_last_partitions.size();
2024  size_t curr_size = m_curr_partitions.size();
2025  if (curr_size < prev_size)
2026  {
2027  MRPT_LOG_DEBUG_STREAM("Removing outdated partitions in visual");
2028  for (size_t partitionID = curr_size; partitionID != prev_size;
2029  ++partitionID)
2030  {
2031  MRPT_LOG_DEBUG_STREAM("\tRemoving partition " << partitionID);
2032  std::string partition_obj_name = mrpt::format(
2033  "partition_%lu", static_cast<unsigned long>(partitionID));
2034 
2036  map_partitions_obj->getByName(partition_obj_name);
2037  if (!obj)
2038  {
2039  THROW_EXCEPTION_FMT("Partition: %s was not found",
2040  partition_obj_name.c_str())
2041  }
2042  map_partitions_obj->removeObject(obj);
2043  }
2044  }
2045  MRPT_LOG_DEBUG_STREAM("Done working on the partitions visualization.");
2046 
2047  this->m_win->unlockAccess3DScene();
2048  this->m_win->forceRepaint();
2049 } // end of updateMapPartitionsVisualization
2050 
2051 template <class GRAPH_T>
2053 {
2054  MRPT_START;
2055  ASSERTDEBMSG_(this->m_win, "No CDisplayWindow3D* was provided");
2056  ASSERTDEBMSG_(this->m_win_manager, "No CWindowManager* was provided");
2057  using namespace mrpt::opengl;
2058 
2059  MRPT_LOG_INFO("Toggling map partitions visualization...");
2060  mrpt::opengl::COpenGLScene::Ptr scene = this->m_win->get3DSceneAndLock();
2061 
2062  if (m_lc_params.visualize_map_partitions)
2063  {
2065  scene->getByName("map_partitions");
2066  obj->setVisibility(!obj->isVisible());
2067  }
2068  else
2069  {
2070  this->dumpVisibilityErrorMsg("visualize_map_partitions");
2071  }
2072 
2073  this->m_win->unlockAccess3DScene();
2074  this->m_win->forceRepaint();
2075 
2076  MRPT_END;
2077 } // end of toggleMapPartitionsVisualization
2078 
2079 template <class GRAPH_T>
2081  const std::vector<uint32_t>& nodes_list,
2082  std::pair<double, double>* centroid_coords) const
2083 {
2084  MRPT_START;
2085 
2086  // get the poses and find the centroid so that we can place the baloon over
2087  // and at their center
2088  double centroid_x = 0;
2089  double centroid_y = 0;
2090  for (std::vector<uint32_t>::const_iterator node_it = nodes_list.begin();
2091  node_it != nodes_list.end(); ++node_it)
2092  {
2093  pose_t curr_node_pos = this->m_graph->nodes.at(*node_it);
2094  centroid_x += curr_node_pos.x();
2095  centroid_y += curr_node_pos.y();
2096  }
2097 
2098  // normalize by the size - assign to the given pair
2099  centroid_coords->first =
2100  centroid_x / static_cast<double>(nodes_list.size());
2101  centroid_coords->second =
2102  centroid_y / static_cast<double>(nodes_list.size());
2103 
2104  MRPT_END;
2105 } // end of computeCentroidOfNodesVector
2106 
2107 template <class GRAPH_T>
2109 {
2110  MRPT_START;
2111 
2112  // laser scan visualization
2113  if (m_laser_params.visualize_laser_scans)
2114  {
2116  this->m_win->get3DSceneAndLock();
2117 
2118  mrpt::opengl::CPlanarLaserScan::Ptr laser_scan_viz =
2119  mrpt::make_aligned_shared<mrpt::opengl::CPlanarLaserScan>();
2120  laser_scan_viz->enablePoints(true);
2121  laser_scan_viz->enableLine(true);
2122  laser_scan_viz->enableSurface(true);
2123  laser_scan_viz->setSurfaceColor(
2124  m_laser_params.laser_scans_color.R,
2125  m_laser_params.laser_scans_color.G,
2126  m_laser_params.laser_scans_color.B,
2127  m_laser_params.laser_scans_color.A);
2128 
2129  laser_scan_viz->setName("laser_scan_viz");
2130 
2131  scene->insert(laser_scan_viz);
2132  this->m_win->unlockAccess3DScene();
2133  this->m_win->forceRepaint();
2134  }
2135 
2136  MRPT_END;
2137 }
2138 
2139 template <class GRAPH_T>
2141 {
2142  MRPT_START;
2143 
2144  // update laser scan visual
2145  if (m_laser_params.visualize_laser_scans && m_last_laser_scan2D)
2146  {
2148  this->m_win->get3DSceneAndLock();
2149 
2151  scene->getByName("laser_scan_viz");
2152  mrpt::opengl::CPlanarLaserScan::Ptr laser_scan_viz =
2153  std::dynamic_pointer_cast<mrpt::opengl::CPlanarLaserScan>(obj);
2154  laser_scan_viz->setScan(*m_last_laser_scan2D);
2155 
2156  // set the pose of the laser scan
2157  const auto search =
2158  this->m_graph->nodes.find(this->m_graph->nodeCount() - 1);
2159  if (search != this->m_graph->nodes.end())
2160  {
2161  laser_scan_viz->setPose(search->second);
2162  // put the laser scan underneath the graph, so that you can still
2163  // visualize the loop closures with the nodes ahead
2164  laser_scan_viz->setPose(
2166  laser_scan_viz->getPoseX(), laser_scan_viz->getPoseY(),
2167  -0.15, mrpt::DEG2RAD(laser_scan_viz->getPoseYaw()),
2168  mrpt::DEG2RAD(laser_scan_viz->getPosePitch()),
2169  mrpt::DEG2RAD(laser_scan_viz->getPoseRoll())));
2170  }
2171 
2172  this->m_win->unlockAccess3DScene();
2173  this->m_win->forceRepaint();
2174  }
2175 
2176  MRPT_END;
2177 }
2178 
2179 template <class GRAPH_T>
2181 {
2182  MRPT_START;
2183  ASSERTDEBMSG_(this->m_win, "No CDisplayWindow3D* was provided");
2184  ASSERTDEBMSG_(this->m_win_manager, "No CWindowManager* was provided");
2185 
2186  MRPT_LOG_INFO("Toggling LaserScans visualization...");
2187 
2188  mrpt::opengl::COpenGLScene::Ptr scene = this->m_win->get3DSceneAndLock();
2189 
2190  if (m_laser_params.visualize_laser_scans)
2191  {
2193  scene->getByName("laser_scan_viz");
2194  obj->setVisibility(!obj->isVisible());
2195  }
2196  else
2197  {
2198  this->dumpVisibilityErrorMsg("visualize_laser_scans");
2199  }
2200 
2201  this->m_win->unlockAccess3DScene();
2202  this->m_win->forceRepaint();
2203 
2204  MRPT_END;
2205 }
2206 
2207 template <class GRAPH_T>
2209  std::map<std::string, int>* edge_types_to_num) const
2210 {
2211  MRPT_START;
2212  *edge_types_to_num = m_edge_types_to_nums;
2213  MRPT_END;
2214 }
2215 
2216 template <class GRAPH_T>
2218 {
2219  MRPT_START;
2220  parent_t::initializeVisuals();
2221  // MRPT_LOG_DEBUG_STREAM("Initializing visuals");
2222  this->m_time_logger.enter("Visuals");
2223 
2224  ASSERTDEBMSG_(
2225  m_laser_params.has_read_config,
2226  "Configuration parameters aren't loaded yet");
2227  if (m_laser_params.visualize_laser_scans)
2228  {
2229  this->initLaserScansVisualization();
2230  }
2231  if (m_lc_params.visualize_map_partitions)
2232  {
2233  this->initMapPartitionsVisualization();
2234  }
2235 
2236  if (m_visualize_curr_node_covariance)
2237  {
2238  this->initCurrCovarianceVisualization();
2239  }
2240 
2241  this->m_time_logger.leave("Visuals");
2242  MRPT_END;
2243 }
2244 template <class GRAPH_T>
2246 {
2247  MRPT_START;
2248  parent_t::updateVisuals();
2249  // MRPT_LOG_DEBUG_STREAM("Updating visuals");
2250  this->m_time_logger.enter("Visuals");
2251 
2252  if (m_laser_params.visualize_laser_scans)
2253  {
2254  this->updateLaserScansVisualization();
2255  }
2256  if (m_lc_params.visualize_map_partitions)
2257  {
2258  this->updateMapPartitionsVisualization();
2259  }
2260  if (m_visualize_curr_node_covariance)
2261  {
2262  this->updateCurrCovarianceVisualization();
2263  }
2264 
2265  this->m_time_logger.leave("Visuals");
2266  MRPT_END;
2267 }
2268 
2269 template <class GRAPH_T>
2271 {
2272  MRPT_START;
2273  using namespace std;
2274  using namespace mrpt::opengl;
2275 
2276  // text message for covariance ellipsis
2277  this->m_win_manager->assignTextMessageParameters(
2278  /* offset_y* = */ &m_offset_y_curr_node_covariance,
2279  /* text_index* = */ &m_text_index_curr_node_covariance);
2280 
2281  std::string title("Position uncertainty");
2282  this->m_win_manager->addTextMessage(
2283  5, -m_offset_y_curr_node_covariance, title,
2284  mrpt::img::TColorf(m_curr_node_covariance_color),
2285  /* unique_index = */ m_text_index_curr_node_covariance);
2286 
2287  // covariance ellipsis
2288  CEllipsoid::Ptr cov_ellipsis_obj = mrpt::make_aligned_shared<CEllipsoid>();
2289  cov_ellipsis_obj->setName("cov_ellipsis_obj");
2290  cov_ellipsis_obj->setColor_u8(m_curr_node_covariance_color);
2291  cov_ellipsis_obj->setLocation(0, 0, 0);
2292  // cov_ellipsis_obj->setQuantiles(2.0);
2293 
2294  mrpt::opengl::COpenGLScene::Ptr scene = this->m_win->get3DSceneAndLock();
2295  scene->insert(cov_ellipsis_obj);
2296  this->m_win->unlockAccess3DScene();
2297  this->m_win->forceRepaint();
2298 
2299  MRPT_END;
2300 }
2301 
2302 template <class GRAPH_T>
2304 {
2305  MRPT_START;
2306  using namespace std;
2307  using namespace mrpt::math;
2308  using namespace mrpt::opengl;
2309  using namespace mrpt::gui;
2310 
2311  // get the optimal path to the current node
2312  mrpt::graphs::TNodeID curr_node = this->m_graph->nodeCount() - 1;
2313  path_t* path = queryOptimalPath(curr_node);
2314  if (!path) return;
2315 
2316  CMatrixDouble33 mat;
2317  path->curr_pose_pdf.getCovariance(mat);
2318  pose_t curr_position = this->m_graph->nodes.at(curr_node);
2319 
2321  "In updateCurrCovarianceVisualization\n"
2322  "Covariance matrix:\n"
2323  << mat << "\n"
2324  "determinant : "
2325  << mat.det());
2326 
2327  mrpt::opengl::COpenGLScene::Ptr scene = this->m_win->get3DSceneAndLock();
2328  CRenderizable::Ptr obj = scene->getByName("cov_ellipsis_obj");
2329  CEllipsoid::Ptr cov_ellipsis_obj =
2330  std::dynamic_pointer_cast<CEllipsoid>(obj);
2331 
2332  // set the pose and corresponding covariance matrix of the ellipsis
2333  cov_ellipsis_obj->setLocation(curr_position.x(), curr_position.y(), 0);
2334  // pose_t loc = path->curr_pose_pdf.getMeanVal();
2335  // cov_ellipsis_obj->setLocation(loc.x(), loc.y(), 0);
2336  cov_ellipsis_obj->setCovMatrix(mat, 2);
2337 
2338  this->m_win->unlockAccess3DScene();
2339  this->m_win->forceRepaint();
2340 
2341  MRPT_END;
2342 }
2343 
2344 template <class GRAPH_T>
2346  std::string viz_flag, int sleep_time /* = 500 milliseconds */)
2347 {
2348  MRPT_START;
2349 
2350  this->logFmt(
2352  "Cannot toggle visibility of specified object.\n "
2353  "Make sure that the corresponding visualization flag ( %s "
2354  ") is set to true in the .ini file.\n",
2355  viz_flag.c_str());
2356  std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time));
2357 
2358  MRPT_END;
2359 }
2360 
2361 template <class GRAPH_T>
2363 {
2364  MRPT_START;
2365  parent_t::loadParams(source_fname);
2366 
2367  m_partitioner.options.loadFromConfigFileName(
2368  source_fname, "EdgeRegistrationDeciderParameters");
2369  m_laser_params.loadFromConfigFileName(
2370  source_fname, "EdgeRegistrationDeciderParameters");
2371  m_lc_params.loadFromConfigFileName(
2372  source_fname, "EdgeRegistrationDeciderParameters");
2373 
2374  mrpt::config::CConfigFile source(source_fname);
2375 
2376  m_consec_icp_constraint_factor = source.read_double(
2377  "EdgeRegistrationDeciderParameters", "consec_icp_constraint_factor",
2378  0.90, false);
2379  m_lc_icp_constraint_factor = source.read_double(
2380  "EdgeRegistrationDeciderParameters", "lc_icp_constraint_factor", 0.70,
2381  false);
2382 
2383  // set the logging level if given by the user
2384  int min_verbosity_level = source.read_int(
2385  "EdgeRegistrationDeciderParameters", "class_verbosity", 1, false);
2386 
2387  this->setMinLoggingLevel(mrpt::system::VerbosityLevel(min_verbosity_level));
2388  MRPT_END;
2389 }
2390 template <class GRAPH_T>
2392 {
2393  MRPT_START;
2394  using namespace std;
2395 
2396  cout << "------------------[Pair-wise Consistency of ICP Edges - "
2397  "Registration Procedure Summary]------------------"
2398  << endl;
2399 
2400  parent_t::printParams();
2401  m_partitioner.options.dumpToConsole();
2402  m_laser_params.dumpToConsole();
2403  m_lc_params.dumpToConsole();
2404 
2405  cout << "Scan-matching ICP Constraint factor: "
2406  << m_consec_icp_constraint_factor << endl;
2407  cout << "Loop-closure ICP Constraint factor: "
2408  << m_lc_icp_constraint_factor << endl;
2409 
2410  MRPT_LOG_DEBUG_STREAM("Printed the relevant parameters");
2411  MRPT_END;
2412 }
2413 
2414 template <class GRAPH_T>
2416  std::string* report_str) const
2417 {
2418  MRPT_START;
2419 
2420  // Report on graph
2421  std::stringstream class_props_ss;
2422  class_props_ss << "Pair-wise Consistency of ICP Edges - Registration "
2423  "Procedure Summary: "
2424  << std::endl;
2425  class_props_ss << this->header_sep << std::endl;
2426 
2427  // time and output logging
2428  const std::string time_res = this->m_time_logger.getStatsAsText();
2429  const std::string output_res = this->getLogAsString();
2430 
2431  // merge the individual reports
2432  report_str->clear();
2433  parent_t::getDescriptiveReport(report_str);
2434 
2435  *report_str += class_props_ss.str();
2436  *report_str += this->report_sep;
2437 
2438  *report_str += time_res;
2439  *report_str += this->report_sep;
2440 
2441  *report_str += output_res;
2442  *report_str += this->report_sep;
2443 
2444  MRPT_END;
2445 } // end of getDescriptiveReport
2446 
2447 template <class GRAPH_T>
2449  partitions_t& partitions_out) const
2450 {
2451  partitions_out = this->getCurrentPartitions();
2452 }
2453 
2454 template <class GRAPH_T>
2455 const std::vector<std::vector<uint32_t>>&
2457 {
2458  return m_curr_partitions;
2459 }
2460 
2461 template <class GRAPH_T>
2463  bool full_update /* = false */, bool is_first_time_node_reg /* = false */)
2464 {
2465  MRPT_START;
2466  using namespace mrpt::math;
2467  using namespace std;
2468  this->m_time_logger.enter("updateMapPartitions");
2469 
2470  // Initialize the nodeIDs => LaserScans map
2471  nodes_to_scans2D_t nodes_to_scans;
2472  if (full_update)
2473  {
2474  MRPT_LOG_INFO(
2475  "updateMapPartitions: Full partitioning of map was issued");
2476  // clear the existing partitions and recompute the partitioned map for
2477  // all the nodes
2478  m_partitioner.clear();
2479  nodes_to_scans = this->m_nodes_to_laser_scans2D;
2480  }
2481  else
2482  {
2483  // if registering measurement for root node as well...
2484  if (is_first_time_node_reg)
2485  {
2486  nodes_to_scans.insert(
2487  make_pair(
2488  this->m_graph->root,
2489  this->m_nodes_to_laser_scans2D.at(this->m_graph->root)));
2490  }
2491 
2492  // just use the last node-laser scan pair
2493  nodes_to_scans.insert(
2494  make_pair(
2495  this->m_graph->nodeCount() - 1,
2496  this->m_nodes_to_laser_scans2D.at(
2497  this->m_graph->nodeCount() - 1)));
2498  }
2499 
2500  // TODO - Should always exist.
2501  // for each one of the above nodes - add its position and correspoding
2502  // laserScan to the partitioner object
2503  for (auto it = nodes_to_scans.begin(); it != nodes_to_scans.end(); ++it)
2504  {
2505  if (!it->second)
2506  { // if laserScan invalid go to next...
2508  "nodeID \"" << it->first << "\" has invalid laserScan");
2509  continue;
2510  }
2511 
2512  // find pose of node, if it exists...
2513  // TODO - investigate this case. Why should this be happening?
2514  const auto& search = this->m_graph->nodes.find(it->first);
2515  if (search == this->m_graph->nodes.end())
2516  {
2517  MRPT_LOG_WARN_STREAM("Couldn't find pose for nodeID " << it->first);
2518  continue;
2519  }
2520 
2521  // pose
2522  const auto curr_constraint = constraint_t(search->second);
2523  const auto pose3d(mrpt::poses::CPose3DPDF::createFrom2D(curr_constraint));
2524 
2525  // laser scan
2527  sf.insert(it->second);
2528 
2529  m_partitioner.addMapFrame(sf, *pose3d);
2530  }
2531 
2532  // update the last partitions list
2533  size_t curr_size = m_curr_partitions.size();
2534  m_last_partitions.resize(curr_size);
2535  for (size_t i = 0; i < curr_size; i++)
2536  {
2537  m_last_partitions[i] = m_curr_partitions[i];
2538  }
2539  // update current partitions list
2540  m_partitioner.updatePartitions(m_curr_partitions);
2541 
2542  MRPT_LOG_DEBUG_STREAM("Updated map partitions successfully.");
2543  this->m_time_logger.leave("updateMapPartitions");
2544  MRPT_END;
2545 } // end of updateMapPartitions
2546 
2547 // TLaserParams
2548 // //////////////////////////////////
2549 
2550 template <class GRAPH_T>
2552  : laser_scans_color(0, 20, 255),
2553  keystroke_laser_scans("l"),
2554  has_read_config(false)
2555 {
2557  200); // use the last X mahalanobis distance values
2558  goodness_threshold_win.resizeWindow(200); // use the last X ICP values
2559 }
2560 
2561 template <class GRAPH_T>
2563 {
2564 }
2565 
2566 template <class GRAPH_T>
2568  std::ostream& out) const
2569 {
2570  MRPT_START;
2571 
2572  out << "Use scan-matching constraints = "
2573  << (use_scan_matching ? "TRUE" : "FALSE") << std::endl;
2574  out << "Num. of previous nodes to check ICP against = "
2575  << prev_nodes_for_ICP << std::endl;
2576  out << "Visualize laser scans = "
2577  << (visualize_laser_scans ? "TRUE" : "FALSE") << std::endl;
2578 
2579  MRPT_END;
2580 }
2581 template <class GRAPH_T>
2583  const mrpt::config::CConfigFileBase& source, const std::string& section)
2584 {
2585  MRPT_START;
2586 
2587  use_scan_matching =
2588  source.read_bool(section, "use_scan_matching", true, false);
2589  prev_nodes_for_ICP = source.read_int( // how many nodes to check ICP against
2590  section,
2591  "prev_nodes_for_ICP",
2592  10, false);
2593  visualize_laser_scans = source.read_bool(
2594  "VisualizationParameters", "visualize_laser_scans", true, false);
2595 
2596  has_read_config = true;
2597  MRPT_END;
2598 }
2599 // TLoopClosureParams
2600 // //////////////////////////////////
2601 
2602 template <class GRAPH_T>
2604  : keystroke_map_partitions("b"),
2605  balloon_elevation(3),
2606  balloon_radius(0.5),
2607  balloon_std_color(153, 0, 153),
2608  balloon_curr_color(62, 0, 80),
2609  connecting_lines_color(balloon_std_color),
2610  has_read_config(false)
2611 {
2612 }
2613 
2614 template <class GRAPH_T>
2616 {
2617 }
2618 
2619 template <class GRAPH_T>
2621  std::ostream& out) const
2622 {
2623  MRPT_START;
2624  using namespace std;
2625 
2626  stringstream ss;
2627  ss << "Min. node difference for loop closure = "
2628  << LC_min_nodeid_diff << endl;
2629  ss << "Remote NodeIDs to consider the potential loop closure = "
2630  << LC_min_remote_nodes << endl;
2631  ss << "Min EigenValues ratio for accepting a hypotheses set = "
2632  << LC_eigenvalues_ratio_thresh << endl;
2633  ss << "Check only current node's partition for loop closures = "
2634  << (LC_check_curr_partition_only ? "TRUE" : "FALSE") << endl;
2635  ss << "New registered nodes required for full partitioning = "
2636  << full_partition_per_nodes << endl;
2637  ss << "Visualize map partitions = "
2638  << (visualize_map_partitions ? "TRUE" : "FALSE") << endl;
2639 
2640  out << mrpt::format("%s", ss.str().c_str());
2641 
2642  MRPT_END;
2643 }
2644 template <class GRAPH_T>
2646  const mrpt::config::CConfigFileBase& source, const std::string& section)
2647 {
2648  MRPT_START;
2649  LC_min_nodeid_diff = source.read_int(
2650  "GeneralConfiguration", "LC_min_nodeid_diff", 30, false);
2651  LC_min_remote_nodes =
2652  source.read_int(section, "LC_min_remote_nodes", 3, false);
2653  LC_eigenvalues_ratio_thresh =
2654  source.read_double(section, "LC_eigenvalues_ratio_thresh", 2, false);
2655  LC_check_curr_partition_only =
2656  source.read_bool(section, "LC_check_curr_partition_only", true, false);
2657  full_partition_per_nodes =
2658  source.read_int(section, "full_partition_per_nodes", 50, false);
2659  visualize_map_partitions = source.read_bool(
2660  "VisualizationParameters", "visualize_map_partitions", true, false);
2661 
2662  has_read_config = true;
2663  MRPT_END;
2664 }
2665 } // end of namespaces
2666 
2667 #endif /* end of include guard: CLOOPCLOSERERD_IMPL_H */
2668 
2669 
mrpt::obs::CObservation2DRangeScan::Ptr scan
Definition: TNodeProps.h:21
void toggleMapPartitionsVisualization()
Toggle the map partitions visualization objects.
const partitions_t & getCurrentPartitions() const
GRAPH_T::global_pose_t pose
Definition: TNodeProps.h:20
Scalar * iterator
Definition: eigen_plugins.h:26
double generatePWConsistencyElement(const mrpt::graphs::TNodeID &a1, const mrpt::graphs::TNodeID &a2, const mrpt::graphs::TNodeID &b1, const mrpt::graphs::TNodeID &b2, const hypotsp_t &hypots, const paths_t *opt_paths=NULL)
Return the pair-wise consistency between the observations of the given nodes.
void insert(const CObservation::Ptr &obs)
Inserts a new observation to the list: The pointer to the objects is copied, thus DO NOT delete the p...
Holds the data of an information path.
#define MRPT_START
Definition: exceptions.h:262
void loadParams(const std::string &source_fname)
#define MRPT_LOG_DEBUG(_STRING)
Use: MRPT_LOG_DEBUG("message");
VerbosityLevel
Enumeration of available verbosity levels.
const_iterator find(const KEY &key) const
Definition: ts_hash_map.h:217
A set of object, which are referenced to the coordinates framework established in this object...
Definition: CSetOfObjects.h:26
#define THROW_EXCEPTION(msg)
Definition: exceptions.h:41
void initMapPartitionsVisualization()
Initialize the visualization of the map partition objects.
typename GRAPH_T::constraint_t::type_value pose_t
type of underlying poses (2D/3D).
typename GRAPH_T::global_pose_t global_pose_t
void dumpToTextStream(std::ostream &out) const
This method should clearly display all the contents of the structure in textual form, sending it to a std::ostream.
void loadFromConfigFile(const mrpt::config::CConfigFileBase &source, const std::string &section)
This method load the options from a ".ini"-like file or memory-stored string list.
void resizeWindow(size_t new_size)
Resize the window.
double DEG2RAD(const double x)
Degrees to radians.
void getMinUncertaintyPath(const mrpt::graphs::TNodeID from, const mrpt::graphs::TNodeID to, path_t *path) const
Given two nodeIDs compute and return the path connecting them.
virtual bool updateState(mrpt::obs::CActionCollection::Ptr action, mrpt::obs::CSensoryFrame::Ptr observations, mrpt::obs::CObservation::Ptr observation)
This class allows loading and storing values and vectors of different types from ".ini" files easily.
void execDijkstraProjection(mrpt::graphs::TNodeID starting_node=0, mrpt::graphs::TNodeID ending_node=INVALID_NODEID)
compute the minimum uncertainty of each node position with regards to the graph root.
static CPose3DPDF * createFrom2D(const CPosePDF &o)
This is a static transformation method from 2D poses to 3D PDFs, preserving the representation type (...
Definition: CPose3DPDF.cpp:34
void getDescriptiveReport(std::string *report_str) const
Column vector, like Eigen::MatrixX*, but automatically initialized to zeros since construction...
Definition: eigen_frwds.h:44
void splitPartitionToGroups(std::vector< uint32_t > &partition, std::vector< uint32_t > *groupA, std::vector< uint32_t > *groupB, int max_nodes_in_group=5)
Split an existing partition to Groups.
STL namespace.
TSlidingWindow mahal_distance_ICP_odom_win
Keep track of the mahalanobis distance between the initial pose difference and the suggested new edge...
static hypot_t * findHypotByID(const hypotsp_t &vec_hypots, const size_t &id, bool throw_exc=true)
Given a vector of THypothesis objects, find the one that has the given ID.
GLuint src
Definition: glext.h:7278
void loadFromConfigFile(const mrpt::config::CConfigFileBase &source, const std::string &section)
This method load the options from a ".ini"-like file or memory-stored string list.
GLsizei GLsizei GLuint * obj
Definition: glext.h:4070
void computeCentroidOfNodesVector(const std::vector< uint32_t > &nodes_list, std::pair< double, double > *centroid_coords) const
Compute the Centroid of a group of a vector of node positions.
Struct for passing additional parameters to the getICPEdge call.
#define MRPT_LOG_WARN_STREAM(__CONTENTS)
void registerHypothesis(const hypot_t &h)
Wrapper around the registerNewEdge method which accepts a THypothesis object instead.
const mrpt::graphs::TNodeID & getDestination() const
Return the Destination node of this path.
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:4178
void evaluatePartitionsForLC(const partitions_t &partitions)
Evaluate the given partitions for loop closures.
static const path_t * findPathByEnds(const paths_t &vec_paths, const mrpt::graphs::TNodeID &src, const mrpt::graphs::TNodeID &dst, bool throw_exc=true)
Given a vector of TUncertaintyPath objects, find the one that has the given source and destination no...
float goodness
A goodness measure for the alignment, it is a [0,1] range indicator of percentage of correspondences...
Definition: CICP.h:197
SLAM methods related to graphs of pose constraints.
This class allows loading and storing values and vectors of different types from a configuration text...
This base provides a set of functions for maths stuff.
3D segment, consisting of two points.
GLuint dst
Definition: glext.h:7135
bool mahalanobisDistanceOdometryToICPEdge(const mrpt::graphs::TNodeID &from, const mrpt::graphs::TNodeID &to, const constraint_t &rel_edge)
brief Compare the suggested ICP edge against the initial node difference.
#define MRPT_LOG_DEBUG_FMT(_FMT_STRING,...)
Use: MRPT_LOG_DEBUG_FMT("i=%u", i);
constraint_t curr_pose_pdf
Current path position + corresponding covariance.
typename GRAPH_T::constraint_t constraint_t
Handy typedefs.
Eigen::Matrix< dataType, 4, 4 > inverse(Eigen::Matrix< dataType, 4, 4 > &pose)
Definition: Miscellaneous.h:80
This namespace contains representation of robot actions and observations.
Declares a class for storing a "sensory frame", a set of "observations" taken by the robot approximat...
Definition: CSensoryFrame.h:52
This object renders a 2D laser scan by means of three elements: the points, the line along end-points...
std::map< std::string, int > m_edge_types_to_nums
Keep track of the registered edge types.
#define MRPT_LOG_DEBUG_STREAM(__CONTENTS)
Use: MRPT_LOG_DEBUG_STREAM("Var=" << value << " foo=" << foo_var);
GLsizei const GLchar ** string
Definition: glext.h:4101
bool fillNodePropsFromGroupParams(const mrpt::graphs::TNodeID &nodeID, const std::map< mrpt::graphs::TNodeID, node_props_t > &group_params, node_props_t *node_props)
Fill the TNodeProps instance using the parameters from the map.
std::vector< std::vector< uint32_t > > partitions_t
Typedef for referring to a list of partitions.
bool computeDominantEigenVector(const mrpt::math::CMatrixDouble &consist_matrix, mrpt::math::dynamic_vector< double > *eigvec, bool use_power_method=false)
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
MAT::Scalar mahalanobisDistance2(const VECTORLIKE1 &X, const VECTORLIKE2 &MU, const MAT &COV)
Computes the squared mahalanobis distance of a vector X given the mean MU and the covariance inverse ...
Definition: data_utils.h:34
void setWindowManagerPtr(mrpt::graphslam::CWindowManager *win_manager)
void addToPath(const mrpt::graphs::TNodeID &node, const constraint_t &edge)
add a new link in the current path.
void evalPWConsistenciesMatrix(const mrpt::math::CMatrixDouble &consist_matrix, const hypotsp_t &hypots_pool, hypotsp_t *valid_hypots)
Evalute the consistencies matrix, fill the valid hypotheses.
#define ASSERTDEBMSG_(f, __ERROR_MSG)
Definition: exceptions.h:208
typename parent_t::nodes_to_scans2D_t nodes_to_scans2D_t
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
void addToPaths(std::set< path_t *> *pool_of_paths, const path_t &curr_path, const std::set< mrpt::graphs::TNodeID > &neibors) const
Append the paths starting from the current node.
static hypot_t * findHypotByEnds(const hypotsp_t &vec_hypots, const mrpt::graphs::TNodeID &from, const mrpt::graphs::TNodeID &to, bool throw_exc=true)
Given a vector of THypothesis objects, find the one that has the given start and end nodes...
std::map< mrpt::graphs::TNodeID, node_props_t > group_t
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:86
virtual bool getICPEdge(const mrpt::graphs::TNodeID &from, const mrpt::graphs::TNodeID &to, constraint_t *rel_edge, mrpt::slam::CICP::TReturnInfo *icp_info=NULL, const TGetICPEdgeAdParams *ad_params=NULL)
Get the ICP Edge between the provided nodes.
#define ASSERTDEB_(f)
Defines an assertion mechanism - only when compiled in debug.
Definition: exceptions.h:205
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:16
A solid or wire-frame sphere.
Definition: CSphere.h:29
void checkPartitionsForLC(partitions_t *partitions_for_LC)
Check the registered so far partitions for potential loop closures.
#define MRPT_END
Definition: exceptions.h:266
CMatrixFixedNumeric< double, 3, 3 > CMatrixDouble33
Definition: eigen_frwds.h:57
A RGB color - floats in the range [0,1].
Definition: TColor.h:77
void dumpToTextStream(std::ostream &out) const
This method should clearly display all the contents of the structure in textual form, sending it to a std::ostream.
void registerNewEdge(const mrpt::graphs::TNodeID &from, const mrpt::graphs::TNodeID &to, const constraint_t &rel_edge)
Struct for passing additional parameters to the generateHypotsPool call.
The ICP algorithm return information.
Definition: CICP.h:190
virtual void fetchNodeIDsForScanMatching(const mrpt::graphs::TNodeID &curr_nodeID, std::set< mrpt::graphs::TNodeID > *nodes_set)
Fetch a list of nodes with regards prior to the given nodeID for which to try and add scan matching e...
The namespace for 3D scene representation and rendering.
Definition: CGlCanvasBase.h:15
GLsizei GLsizei GLchar * source
Definition: glext.h:4082
void toggleLaserScansVisualization()
togle the LaserScans visualization on and off
void updateMapPartitions(bool full_update=false, bool is_first_time_node_reg=false)
Split the currently registered graph nodes into partitions.
uint64_t TNodeID
A generic numeric type for unique IDs of nodes or entities.
Definition: TNodeID.h:16
Edge Registration Decider scheme specialized in Loop Closing.
Classes for creating GUI windows for 2D and 3D visualization.
Definition: about_box.h:14
#define INVALID_NODEID
Definition: TNodeID.h:19
T absDiff(const T &lhs, const T &rhs)
Absolute difference between two numbers.
mrpt::graphslam::TUncertaintyPath< GRAPH_T > * popMinUncertaintyPath(std::set< path_t *> *pool_of_paths) const
Find the minimum uncertainty path from te given pool of TUncertaintyPath instances.
GLsizei const GLfloat * value
Definition: glext.h:4117
void updateMapPartitionsVisualization()
Update the map partitions visualization.
GLuint res
Definition: glext.h:7268
A 2D ellipse or 3D ellipsoid, depending on the size of the m_cov matrix (2x2 or 3x3).
Definition: CEllipsoid.h:45
typename GRAPH_T::edges_map_t::const_iterator edges_citerator
void notifyOfWindowEvents(const std::map< std::string, bool > &events_occurred)
std::vector< mrpt::graphs::TNodeID > nodes_traversed
Nodes that the Path comprises of.
An edge hypothesis between two nodeIDs.
Definition: THypothesis.h:33
Lightweight 3D point.
void assertIsBetweenNodeIDs(const mrpt::graphs::TNodeID &from, const mrpt::graphs::TNodeID &to) const
Assert that the current path is between the given nodeIDs.
A set of independent lines (or segments), one line with its own start and end positions (X...
Definition: CSetOfLines.h:31
void dumpVisibilityErrorMsg(std::string viz_flag, int sleep_time=500)
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
Definition: exceptions.h:43
#define MRPT_LOG_ERROR_STREAM(__CONTENTS)
void generateHypotsPool(const std::vector< uint32_t > &groupA, const std::vector< uint32_t > &groupB, hypotsp_t *generated_hypots, const TGenerateHypotsPoolAdParams *ad_params=NULL)
Generate the hypothesis pool for all the inter-group constraints between two groups of nodes...
GLfloat GLfloat p
Definition: glext.h:6305
GLenum const GLfloat * params
Definition: glext.h:3534
void getEdgesStats(std::map< std::string, int > *edge_types_to_num) const
const Scalar * const_iterator
Definition: eigen_plugins.h:27
Internal auxiliary classes.
Definition: levmarq_impl.h:17
std::string getSTLContainerAsString(const T &t)
Return a STL container in std::string form.
typename mrpt::graphs::detail::THypothesis< GRAPH_T > hypot_t
Class acts as a container for storing pointers to mrpt::gui::CDisplayWindow3D, mrpt::graphslam::CWind...
bool approximatelyEqual(T1 a, T1 b, T2 epsilon)
Compare 2 floats and determine whether they are equal.
virtual void addScanMatchingEdges(const mrpt::graphs::TNodeID &curr_nodeID)
Addd ICP constraints from X previous nodeIDs up to the given nodeID.
bool getPropsOfNodeID(const mrpt::graphs::TNodeID &nodeID, global_pose_t *pose, mrpt::obs::CObservation2DRangeScan::Ptr &scan, const node_props_t *node_props=NULL) const
Fill the pose and LaserScan for the given nodeID.
void generatePWConsistenciesMatrix(const std::vector< uint32_t > &groupA, const std::vector< uint32_t > &groupB, const hypotsp_t &hypots_pool, mrpt::math::CMatrixDouble *consist_matrix, const paths_t *groupA_opt_paths=NULL, const paths_t *groupB_opt_paths=NULL)
Compute the pair-wise consistencies Matrix.
#define MRPT_LOG_INFO(_STRING)
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.
Definition: common.h:186
TSlidingWindow goodness_threshold_win
Keep track of ICP Goodness values for ICP between nearby nodes and adapt the Goodness threshold based...



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 7d5e6d718 Fri Aug 24 01:51:28 2018 +0200 at lun nov 2 08:35:50 CET 2020