9 #ifndef CONSTRAINED_POSE_NETWORK_H 10 #define CONSTRAINED_POSE_NETWORK_H 38 #include <type_traits> 48 template <
class GRAPH_T>
54 class MAPS_IMPLEMENTATION,
class NODE_ANNOTATIONS,
class EDGE_ANNOTATIONS>
59 class MAPS_IMPLEMENTATION,
class NODE_ANNOTATIONS,
class EDGE_ANNOTATIONS>
117 class MAPS_IMPLEMENTATION =
132 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>;
152 return literal(
"mrpt::graphs::CNetworkOfPoses<") +
165 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS,
171 return literal(
"global_pose_t<") +
180 template <
typename ARG1>
184 template <
typename ARG1,
typename ARG2>
202 static_cast<const constraint_no_pdf_t>(*
this) ==
203 static_cast<const constraint_no_pdf_t>(other) &&
204 static_cast<const NODE_ANNOTATIONS>(*
this) ==
205 static_cast<const NODE_ANNOTATIONS>(other));
209 return (!(*
this == other));
213 std::ostream& o,
const self_t& global_pose)
215 o << global_pose.asString() <<
"| " 216 << global_pose.retAnnotsAsString();
228 using global_poses_t =
typename MAPS_IMPLEMENTATION::template map<
298 const std::string& fileName,
bool collapse_dup_edges =
true)
331 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>;
333 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>;
335 bool is_multirobot =
false;
336 std::unique_ptr<visualizer_t> viz;
337 is_multirobot = (std::is_base_of<
342 viz.reset(
new visualizer_multirobot_t(*
this));
346 viz.reset(
new visualizer_t(*
this));
348 viz->getAs3DObject(
object, viz_params);
396 this, it, ignoreCovariances);
418 const std::set<TNodeID>& node_IDs,
self_t* sub_graph,
420 const bool& auto_expand_set =
true)
const 423 using namespace mrpt;
432 "\nInvalid pointer to a CNetworkOfPoses instance is given. " 437 TNodeID root_node = root_node_in;
441 node_IDs.find(root_node) != node_IDs.end(),
442 "\nRoot_node does not exist in the given node_IDs set. " 448 node_IDs.size() >= 2,
450 "Very few nodes [%lu] for which to extract a subgraph. " 452 static_cast<unsigned long>(node_IDs.size())));
456 bool is_fully_connected_graph =
true;
457 std::set<TNodeID> node_IDs_real;
458 if (*node_IDs.rbegin() - *node_IDs.begin() + 1 == node_IDs.size())
460 node_IDs_real = node_IDs;
464 is_fully_connected_graph =
false;
468 for (
TNodeID curr_node_ID = *node_IDs.begin();
469 curr_node_ID != *node_IDs.rbegin(); ++curr_node_ID)
471 node_IDs_real.insert(curr_node_ID);
476 node_IDs_real = node_IDs;
482 node_IDs_real.begin();
483 node_IDs_it != node_IDs_real.end(); ++node_IDs_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())
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;
608 sub_graph->
nodes.begin();
609 n_it != sub_graph->
nodes.end(); ++n_it)
611 bool is_there =
false;
615 uncon_it = unconnected_nodeIDs.begin();
616 uncon_it != unconnected_nodeIDs.end(); ++uncon_it)
618 if (n_it->first == *uncon_it)
627 mainland.insert(n_it->first);
631 bool is_single_island =
632 (island_highest - island_lowest + 1 ==
633 unconnected_nodeIDs.size());
635 if (is_single_island)
649 const std::set<TNodeID>& island = unconnected_nodeIDs;
651 sub_graph, island, mainland);
662 std::vector<std::set<TNodeID>> vec_of_islands;
663 std::set<TNodeID> curr_island;
664 TNodeID prev_nodeID = *unconnected_nodeIDs.begin();
668 ++unconnected_nodeIDs.begin();
669 *it < sub_graph->
root &&
670 it != unconnected_nodeIDs.end();
673 if (!(
absDiff(*it, prev_nodeID) == 1))
675 vec_of_islands.push_back(curr_island);
678 curr_island.insert(*it);
683 vec_of_islands.push_back(curr_island);
691 sub_graph, vec_of_islands.back(), mainland);
722 const bool hypots_from_other_to_self =
true,
723 std::map<TNodeID, TNodeID>* old_to_new_nodeID_mappings_out = NULL)
734 const self_t& graph_from = (hypots_from_other_to_self ? other : *
this);
735 const self_t& graph_to = (hypots_from_other_to_self ? *this : other);
743 for (hypots_cit_t h_cit = common_hypots.begin();
744 h_cit != common_hypots.end(); ++h_cit)
747 graph_from.
nodes.find(h_cit->from) != graph_from.
nodes.end(),
748 format(
"NodeID %lu is not found in (from) graph", h_cit->from));
750 graph_to.
nodes.find(h_cit->to) != graph_to.
nodes.end(),
751 format(
"NodeID %lu is not found in (to) graph", h_cit->to));
756 for (nodes_cit_t n_cit = this->nodes.begin();
757 n_cit != this->nodes.end(); ++n_cit)
759 if (n_cit->first > max_nodeID)
761 max_nodeID = n_cit->first;
764 TNodeID renum_start = max_nodeID + 1;
765 size_t renum_counter = 0;
770 std::map<TNodeID, TNodeID>* old_to_new_nodeID_mappings;
776 std::map<TNodeID, TNodeID> mappings_tmp;
779 if (old_to_new_nodeID_mappings_out)
781 old_to_new_nodeID_mappings = old_to_new_nodeID_mappings_out;
785 old_to_new_nodeID_mappings = &mappings_tmp;
787 old_to_new_nodeID_mappings->clear();
792 for (nodes_cit_t n_cit = other.
nodes.begin();
793 n_cit != other.
nodes.end(); ++n_cit)
795 TNodeID new_nodeID = renum_start + renum_counter++;
796 old_to_new_nodeID_mappings->insert(
797 make_pair(n_cit->first, new_nodeID));
798 this->nodes.insert(make_pair(new_nodeID, n_cit->second));
806 for (hypots_cit_t h_cit = common_hypots.begin();
807 h_cit != common_hypots.end(); ++h_cit)
810 if (hypots_from_other_to_self)
812 from = old_to_new_nodeID_mappings->at(h_cit->from);
818 to = old_to_new_nodeID_mappings->at(h_cit->to);
829 g_cit != other.
end(); ++g_cit)
832 old_to_new_nodeID_mappings->at(g_cit->first.first);
834 old_to_new_nodeID_mappings->at(g_cit->first.second);
835 this->
insertEdge(new_from, new_to, g_cit->second);
857 self_t* sub_graph,
const std::set<TNodeID>& groupA,
858 const std::set<TNodeID>& groupB)
864 "\nInvalid pointer to a CNetworkOfPoses instance is given. " 866 ASSERTMSG_(!groupA.empty(),
"\ngroupA is empty.");
867 ASSERTMSG_(!groupB.empty(),
"\ngroupB is empty.");
871 *groupA.rend() < *groupB.rbegin() ||
872 *groupA.rbegin() > *groupB.rend(),
873 "Groups A, B contain overlapping nodeIDs");
877 const std::set<TNodeID>& low_nodeIDs =
878 *groupA.rbegin() < *groupB.rbegin() ? groupA : groupB;
879 const std::set<TNodeID>& high_nodeIDs =
880 *groupA.rbegin() > *groupB.rbegin() ? groupA : groupB;
883 const TNodeID& from_nodeID = *low_nodeIDs.rbegin();
884 const TNodeID& to_nodeID = *high_nodeIDs.begin();
897 bool ignoreCovariances =
true)
const 900 this, itEdge, ignoreCovariances);
913 bool ignoreCovariances =
true)
const 920 "Request for edge %u->%u that doesn't exist in graph.",
921 static_cast<unsigned int>(from_id),
922 static_cast<unsigned int>(to_id)));
953 graph,
"Invalid pointer to the graph instance was provided.");
957 const typename BASE::edge_t& virt_edge(p_to - p_from);
965 class CPOSE,
class MAPS_IMPLEMENTATION,
class NODE_ANNOTATIONS,
966 class EDGE_ANNOTATIONS>
970 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>&
obj)
973 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>;
980 class CPOSE,
class MAPS_IMPLEMENTATION,
class NODE_ANNOTATIONS,
981 class EDGE_ANNOTATIONS>
985 CPOSE, MAPS_IMPLEMENTATION, NODE_ANNOTATIONS, EDGE_ANNOTATIONS>&
obj)
988 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...
void dijkstra_nodes_estimate()
Spanning tree computation of a simple estimation of the global coordinates of each node just from the...
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...
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...
static void graph_of_poses_dijkstra_init(graph_t *g)
Base class for C*Visualizer classes.
A directed graph of pose constraints, with edges being the relative poses between pairs of nodes iden...
#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.
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::utils::map_as_vector<> (dense, fastest representation)
Virtual base class for "archives": classes abstracting I/O streams.
void mergeGraph(const self_t &other, const typename std::vector< detail::THypothesis< self_t >> &common_hypots, const bool hypots_from_other_to_self=true, std::map< TNodeID, TNodeID > *old_to_new_nodeID_mappings_out=NULL)
Integrate given graph into own graph using the list of provided common THypotheses.
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 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...
GLsizei const GLfloat * value
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...
const Scalar * const_iterator
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.