38 #include <type_traits> 47 template <
class GRAPH_T>
53 class MAPS_IMPLEMENTATION,
class NODE_ANNOTATIONS,
class EDGE_ANNOTATIONS>
58 class MAPS_IMPLEMENTATION,
class NODE_ANNOTATIONS,
class EDGE_ANNOTATIONS>
116 class MAPS_IMPLEMENTATION =
131 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>;
151 return literal(
"mrpt::graphs::CNetworkOfPoses<") +
164 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS,
170 return literal(
"global_pose_t<") +
179 template <
typename ARG1>
183 template <
typename ARG1,
typename ARG2>
201 static_cast<const constraint_no_pdf_t>(*
this) ==
202 static_cast<const constraint_no_pdf_t>(other) &&
203 static_cast<const NODE_ANNOTATIONS>(*
this) ==
204 static_cast<const NODE_ANNOTATIONS>(other));
208 return (!(*
this == other));
212 std::ostream& o,
const self_t& global_pose)
214 o << global_pose.asString() <<
"| " 215 << global_pose.retAnnotsAsString();
227 using global_poses_t =
typename MAPS_IMPLEMENTATION::template map<
297 const std::string& fileName,
bool collapse_dup_edges =
true)
330 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>;
332 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>;
334 bool is_multirobot =
false;
335 std::unique_ptr<visualizer_t> viz;
341 viz.reset(
new visualizer_multirobot_t(*
this));
345 viz.reset(
new visualizer_t(*
this));
347 viz->getAs3DObject(
object, viz_params);
363 std::optional<std::reference_wrapper<std::map<TNodeID, size_t>>>
364 topological_distances = std::nullopt)
367 this, topological_distances ? &topological_distances.value().get()
398 this, it, ignoreCovariances);
420 const std::set<TNodeID>& node_IDs,
self_t* sub_graph,
422 const bool& auto_expand_set =
true)
const 425 using namespace mrpt;
434 "\nInvalid pointer to a CNetworkOfPoses instance is given. " 439 TNodeID root_node = root_node_in;
443 node_IDs.find(root_node) != node_IDs.end(),
444 "\nRoot_node does not exist in the given node_IDs set. " 450 node_IDs.size() >= 2,
452 "Very few nodes [%lu] for which to extract a subgraph. " 454 static_cast<unsigned long>(node_IDs.size())));
458 bool is_fully_connected_graph =
true;
459 std::set<TNodeID> node_IDs_real;
460 if (*node_IDs.rbegin() - *node_IDs.begin() + 1 == node_IDs.size())
462 node_IDs_real = node_IDs;
466 is_fully_connected_graph =
false;
470 for (
TNodeID curr_node_ID = *node_IDs.begin();
471 curr_node_ID != *node_IDs.rbegin(); ++curr_node_ID)
473 node_IDs_real.insert(curr_node_ID);
478 node_IDs_real = node_IDs;
483 for (
unsigned long node_IDs_it : node_IDs_real)
486 typename global_poses_t::const_iterator own_it;
487 for (own_it =
nodes.begin(); own_it !=
nodes.end(); ++own_it)
489 if (node_IDs_it == own_it->first)
495 own_it !=
nodes.end(),
497 "NodeID [%lu] can't be found in the initial graph.",
498 static_cast<unsigned long>(node_IDs_it)));
501 sub_graph->
nodes.insert(make_pair(node_IDs_it, curr_node));
510 root_node = sub_graph->
nodes.begin()->first;
512 sub_graph->
root = root_node;
519 const TNodeID& from = e.first.first;
520 const TNodeID& to = e.first.second;
521 const typename BASE::edge_t& curr_edge = e.second;
524 if (sub_graph->
nodes.find(from) != sub_graph->
nodes.end() &&
525 sub_graph->
nodes.find(to) != sub_graph->
nodes.end())
531 if (!auto_expand_set && !is_fully_connected_graph)
538 std::set<TNodeID> root_neighbors;
541 if (root_neighbors.empty())
544 typename global_poses_t::iterator root_it =
547 if ((*root_it == *sub_graph->
nodes.rbegin()))
552 sub_graph, next_to_root, sub_graph->
root);
560 sub_graph, sub_graph->
root, next_to_root);
567 bool dijkstra_runs_successfully =
false;
571 while (!dijkstra_runs_successfully)
575 dijkstra_t dijkstra(*sub_graph, sub_graph->
root);
576 dijkstra_runs_successfully =
true;
580 dijkstra_runs_successfully =
false;
582 set<TNodeID> unconnected_nodeIDs;
595 const TNodeID& island_highest =
596 *unconnected_nodeIDs.rbegin();
597 const TNodeID& island_lowest = *unconnected_nodeIDs.begin();
605 std::set<TNodeID> mainland;
607 for (
typename global_poses_t::const_iterator n_it =
608 sub_graph->
nodes.begin();
609 n_it != sub_graph->
nodes.end(); ++n_it)
611 bool is_there =
false;
614 for (
unsigned long unconnected_nodeID :
617 if (n_it->first == unconnected_nodeID)
626 mainland.insert(n_it->first);
630 bool is_single_island =
631 (island_highest - island_lowest + 1 ==
632 unconnected_nodeIDs.size());
634 if (is_single_island)
648 const std::set<TNodeID>& island = unconnected_nodeIDs;
650 sub_graph, island, mainland);
661 std::vector<std::set<TNodeID>> vec_of_islands;
662 std::set<TNodeID> curr_island;
663 TNodeID prev_nodeID = *unconnected_nodeIDs.begin();
666 for (
auto it = ++unconnected_nodeIDs.begin();
667 *it < sub_graph->
root &&
668 it != unconnected_nodeIDs.end();
671 if (!(
absDiff(*it, prev_nodeID) == 1))
673 vec_of_islands.push_back(curr_island);
676 curr_island.insert(*it);
681 vec_of_islands.push_back(curr_island);
689 sub_graph, vec_of_islands.back(), mainland);
720 const bool hypots_from_other_to_self =
true,
721 std::map<TNodeID, TNodeID>* old_to_new_nodeID_mappings_out =
nullptr)
730 using nodes_cit_t =
typename global_poses_t::const_iterator;
732 const self_t& graph_from = (hypots_from_other_to_self ? other : *
this);
733 const self_t& graph_to = (hypots_from_other_to_self ? *this : other);
741 for (hypots_cit_t h_cit = common_hypots.begin();
742 h_cit != common_hypots.end(); ++h_cit)
745 graph_from.
nodes.find(h_cit->from) != graph_from.
nodes.end(),
746 format(
"NodeID %lu is not found in (from) graph", h_cit->from));
748 graph_to.
nodes.find(h_cit->to) != graph_to.
nodes.end(),
749 format(
"NodeID %lu is not found in (to) graph", h_cit->to));
754 for (nodes_cit_t n_cit = this->nodes.begin();
755 n_cit != this->nodes.end(); ++n_cit)
757 if (n_cit->first > max_nodeID)
759 max_nodeID = n_cit->first;
762 TNodeID renum_start = max_nodeID + 1;
763 size_t renum_counter = 0;
768 std::map<TNodeID, TNodeID>* old_to_new_nodeID_mappings;
774 std::map<TNodeID, TNodeID> mappings_tmp;
777 if (old_to_new_nodeID_mappings_out)
779 old_to_new_nodeID_mappings = old_to_new_nodeID_mappings_out;
783 old_to_new_nodeID_mappings = &mappings_tmp;
785 old_to_new_nodeID_mappings->clear();
790 for (nodes_cit_t n_cit = other.
nodes.begin();
791 n_cit != other.
nodes.end(); ++n_cit)
793 TNodeID new_nodeID = renum_start + renum_counter++;
794 old_to_new_nodeID_mappings->insert(
795 make_pair(n_cit->first, new_nodeID));
796 this->nodes.insert(make_pair(new_nodeID, n_cit->second));
804 for (hypots_cit_t h_cit = common_hypots.begin();
805 h_cit != common_hypots.end(); ++h_cit)
808 if (hypots_from_other_to_self)
810 from = old_to_new_nodeID_mappings->at(h_cit->from);
816 to = old_to_new_nodeID_mappings->at(h_cit->to);
827 g_cit != other.
end(); ++g_cit)
830 old_to_new_nodeID_mappings->at(g_cit->first.first);
832 old_to_new_nodeID_mappings->at(g_cit->first.second);
833 this->
insertEdge(new_from, new_to, g_cit->second);
855 self_t* sub_graph,
const std::set<TNodeID>& groupA,
856 const std::set<TNodeID>& groupB)
862 "\nInvalid pointer to a CNetworkOfPoses instance is given. " 864 ASSERTMSG_(!groupA.empty(),
"\ngroupA is empty.");
865 ASSERTMSG_(!groupB.empty(),
"\ngroupB is empty.");
869 *groupA.rend() < *groupB.rbegin() ||
870 *groupA.rbegin() > *groupB.rend(),
871 "Groups A, B contain overlapping nodeIDs");
875 const std::set<TNodeID>& low_nodeIDs =
876 *groupA.rbegin() < *groupB.rbegin() ? groupA : groupB;
877 const std::set<TNodeID>& high_nodeIDs =
878 *groupA.rbegin() > *groupB.rbegin() ? groupA : groupB;
881 const TNodeID& from_nodeID = *low_nodeIDs.rbegin();
882 const TNodeID& to_nodeID = *high_nodeIDs.begin();
895 bool ignoreCovariances =
true)
const 898 this, itEdge, ignoreCovariances);
911 bool ignoreCovariances =
true)
const 918 "Request for edge %u->%u that doesn't exist in graph.",
919 static_cast<unsigned int>(from_id),
920 static_cast<unsigned int>(to_id)));
951 graph,
"Invalid pointer to the graph instance was provided.");
955 const typename BASE::edge_t& virt_edge(p_to - p_from);
963 class CPOSE,
class MAPS_IMPLEMENTATION,
class NODE_ANNOTATIONS,
964 class EDGE_ANNOTATIONS>
968 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>&
obj)
971 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>;
978 class CPOSE,
class MAPS_IMPLEMENTATION,
class NODE_ANNOTATIONS,
979 class EDGE_ANNOTATIONS>
983 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>&
obj)
986 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>;
static constexpr auto getClassName()
A directed graph with the argument of the template specifying the type of the annotations in the edge...
static void save_graph_of_poses_to_binary_file(const graph_t *g, mrpt::serialization::CArchive &out)
mrpt::serialization::CArchive & operator>>(mrpt::serialization::CArchive &in, CNetworkOfPoses< CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS > &obj)
Binary serialization (read) operator "stream >> graph".
double getGlobalSquareError(bool ignoreCovariances=true) const
Evaluates the graph total square error (ignoreCovariances=true) or chi2 (ignoreCovariances=false) fro...
typename MAPS_IMPLEMENTATION::template map< mrpt::graphs::TNodeID, CPOSE > global_poses_pdf_t
A map from pose IDs to their global coordinate estimates, with uncertainty.
global_pose_t(const global_pose_t &other)
Copy constructor - delegate copying to the NODE_ANNOTATIONS struct.
void clear()
Empty all edges, nodes and set root to ID 0.
mrpt::graphs::TNodeID root
The ID of the node that is the origin of coordinates, used as reference by all coordinates in nodes...
void dijkstra_nodes_estimate(std::optional< std::reference_wrapper< std::map< TNodeID, size_t >>> topological_distances=std::nullopt)
Spanning tree computation of a simple estimation of the global coordinates of each node just from the...
size_t collapseDuplicatedEdges()
Look for duplicated edges (even in opposite directions) between all pairs of nodes and fuse them...
edges_map_t edges
The public member with the directed edges in the graph.
EDGE_ANNOTATIONS edge_annotations_t
The extra annotations in edges, apart from a constraint_t.
void saveToTextFile(const std::string &fileName) const
Saves to a text file in the format used by TORO, HoG-man, G2O.
friend std::ostream & operator<<(std::ostream &o, const self_t &global_pose)
Abstract graph and tree data structures, plus generic graph algorithms.
static constexpr auto getClassName()
void getNeighborsOf(const TNodeID nodeID, std::set< TNodeID > &neighborIDs) const
Return the list of all neighbors of "nodeID", by creating a list of their node IDs.
void loadFromTextFile(const std::string &fileName, bool collapse_dup_edges=true)
Loads from a text file in the format used by TORO & HoG-man (more on the format here) Recognized line...
CPOSE constraint_t
The type of PDF poses in the contraints (edges) (=CPOSE template argument)
double chi2() const
Returns the total chi-squared error of the graph.
void getUnconnectedNodeIDs(std::set< mrpt::graphs::TNodeID > *set_nodeIDs) const
Fill set with the nodeIDs Dijkstra algorithm could not reach starting from the root node...
static void read_graph_of_poses_from_binary_file(graph_t *g, mrpt::serialization::CArchive &in)
GLsizei GLsizei GLuint * obj
double getEdgeSquareError(const typename BASE::edges_map_t::const_iterator &itEdge, bool ignoreCovariances=true) const
Computes the square error of one pose constraints (edge) with respect to the global poses in nodes If...
void clearEdges()
Erase all edges.
double getEdgeSquareError(const mrpt::graphs::TNodeID from_id, const mrpt::graphs::TNodeID to_id, bool ignoreCovariances=true) const
Computes the square error of one pose constraints (edge) with respect to the global poses in nodes If...
Base class for C*Visualizer classes.
A directed graph of pose constraints, with edges being the relative poses between pairs of nodes iden...
#define ASSERT_(f)
Defines an assertion mechanism.
Internal functions for MRPT.
static void save_graph_of_poses_to_ostream(const graph_t *g, std::ostream &f)
This base provides a set of functions for maths stuff.
typename CPOSE::type_value constraint_no_pdf_t
The type of edges or their means if they are PDFs (that is, a simple "edge" value) ...
global_pose_t(const ARG1 &a1)
The type of each global pose in nodes: an extension of the constraint_no_pdf_t pose with any optional...
void insertEdge(TNodeID from_nodeID, TNodeID to_nodeID, const edge_t &edge_value)
Insert an edge (from -> to) with the given edge value.
void getAs3DObject(mrpt::opengl::CSetOfObjects::Ptr object, const mrpt::system::TParametersDouble &viz_params) const
Return 3D Visual Representation of the edges and nodes in the network of poses.
typename MAPS_IMPLEMENTATION::template map< mrpt::graphs::TNodeID, global_pose_t > global_poses_t
A map from pose IDs to their global coordinate estimates, without uncertainty (the "most-likely value...
#define ASSERTMSG_(f, __ERROR_MSG)
Defines an assertion mechanism.
void mergeGraph(const self_t &other, const typename std::vector< detail::THypothesis< self_t >> &common_hypots, const bool hypots_from_other_to_self=true, std::map< TNodeID, TNodeID > *old_to_new_nodeID_mappings_out=nullptr)
Integrate given graph into own graph using the list of provided common THypotheses.
bool operator!=(const global_pose_t &other) const
static void connectGraphPartitions(self_t *sub_graph, const std::set< TNodeID > &groupA, const std::set< TNodeID > &groupB)
Add an edge between the last node of the group with the lower nodeIDs and the first node of the highe...
void writeAsText(std::ostream &o) const
Writes as text in the format used by TORO, HoG-man, G2O.
GLsizei const GLchar ** string
static void load_graph_of_poses_from_text_stream(graph_t *g, std::istream &f, const std::string &fil=std::string("(none)"))
size_t nodeCount() const
Return number of nodes in the list nodes of global coordinates (may be different that all nodes appea...
void extractSubGraph(const std::set< TNodeID > &node_IDs, self_t *sub_graph, const TNodeID root_node_in=INVALID_NODEID, const bool &auto_expand_set=true) const
Find the edges between the nodes in the node_IDs set and fill given graph pointer accordingly...
Traits for using a std::map<> (sparse representation)
global_pose_t()
Potential class constructors.
static size_t graph_of_poses_collapse_dup_edges(graph_t *g)
static void save_graph_of_poses_to_text_file(const graph_t *g, const std::string &fil)
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
A Probability Density function (PDF) of a 2D pose as a Gaussian with a mean and the inverse of the c...
Traits for using a mrpt::containers::map_as_vector<> (dense, fastest representation) ...
Virtual base class for "archives": classes abstracting I/O streams.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
static double graph_edge_sqerror(const graph_t *g, const typename mrpt::graphs::CDirectedGraph< typename graph_t::constraint_t >::edges_map_t::const_iterator &itEdge, bool ignoreCovariances)
a helper struct with static template functions
Declares a class that represents a Probability Density function (PDF) of a 3D pose as a Gaussian des...
void readAsText(std::istream &i)
Reads as text in the format used by TORO, HoG-man, G2O.
typename edges_map_t::const_iterator const_iterator
uint64_t TNodeID
A generic numeric type for unique IDs of nodes or entities.
static void graph_of_poses_dijkstra_init(graph_t *g, std::map< TNodeID, size_t > *topological_distances=nullptr)
static void load_graph_of_poses_from_text_file(graph_t *g, const std::string &fil)
MAPS_IMPLEMENTATION maps_implementation_t
The type of map's implementation (=MAPS_IMPLEMENTATION template argument)
global_poses_t nodes
The nodes (vertices) of the graph, with their estimated "global" (with respect to root) position...
global_pose_t(const ARG1 &a1, const ARG2 &a2)
The Dijkstra algorithm for finding the shortest path between a given source node in a (weighted) dire...
T absDiff(const T &lhs, const T &rhs)
Absolute difference between two numbers.
bool edges_store_inverse_poses
False (default) if an edge i->j stores the normal relative pose of j as seen from i: True if an edge...
bool operator==(const global_pose_t &other) const
An edge hypothesis between two nodeIDs.
Struct to be used as the NODE_ANNOTATIONS template argument in CNetworkOfPoses class instances for us...
Struct to be used as the NODE_ANNOTATIONS template argument in CNetworkOfPoses class instances for us...
Wrapper class that provides visualization of a network of poses that have been registered by many gra...
Custom exception class that passes information in case an unconnected graph is passed to a Dijkstra i...
NODE_ANNOTATIONS node_annotations_t
The extra annotations in nodes, apart from a constraint_no_pdf_t.
typename CNetworkOfPoses< CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS >::global_pose_t self_t
#define MRPT_DECLARE_TTYPENAME(_TYPE)
static void addVirtualEdge(self_t *graph, const TNodeID &from, const TNodeID &to)
Add a virtual edge between two nodes in the given graph.