9 #ifndef CONSTRAINED_POSE_NETWORK_IMPL_H 10 #define CONSTRAINED_POSE_NETWORK_IMPL_H 41 template <
class POSE_PDF>
79 template <
class graph_t>
86 f <<
"VERTEX2 " <<
id <<
" " <<
p.x() <<
" " <<
p.y() <<
" " <<
p.phi();
94 f <<
"VERTEX3 " <<
id <<
" " <<
p.x() <<
" " <<
p.y() <<
" " <<
p.z()
95 <<
" " <<
p.roll() <<
" " <<
p.pitch() <<
" " <<
p.yaw();
106 f <<
"EDGE2 " << edgeIDs.first <<
" " << edgeIDs.second <<
" " 122 f <<
"EDGE3 " << edgeIDs.first <<
" " << edgeIDs.second <<
" " 143 write_EDGE_line(edgeIDs,
p, f);
151 write_EDGE_line(edgeIDs,
p, f);
159 p.cov_inv.unit(3, 1.0);
160 write_EDGE_line(edgeIDs,
p, f);
168 p.cov_inv.unit(6, 1.0);
169 write_EDGE_line(edgeIDs,
p, f);
182 "Error opening file '%s' for writing", fil.c_str());
187 itNod !=
g->nodes.end(); ++itNod)
189 write_VERTEX_line(itNod->first, itNod->second, f);
192 f <<
" | " << itNod->second.retAnnotsAsString() << endl;
198 if (it->first.first != it->first.second)
202 write_EDGE_line(it->first, it->second, f);
219 out <<
g->nodes <<
g->edges <<
g->root;
231 in >> sStoredClassName;
236 in >> stored_version;
239 switch (stored_version)
242 in >>
g->nodes >>
g->edges >>
g->root;
258 typedef typename graph_t::constraint_t CPOSE;
260 set<string> alreadyWarnedUnknowns;
269 const bool graph_is_3D = CPOSE::is_3D();
278 map<TNodeID, TNodeID> lstEquivs;
287 const string lin =
s.str();
290 if (!(
s >> key) || key.empty())
293 "Line %u: Can't read string for entry type in: '%s'",
294 lineNum, lin.c_str()));
300 if (!(
s >> id1 >> id2))
303 "Line %u: Can't read id1 & id2 in EQUIV line: '%s'",
304 lineNum, lin.c_str()));
305 lstEquivs[std::max(id1, id2)] =
std::min(id1, id2);
318 const string lin =
s.str();
334 if (!(
s >> key) || key.empty())
337 "Line %u: Can't read string for entry type in: '%s'",
338 lineNum, lin.c_str()));
345 if (!(
s >>
id >> p2D.
x >> p2D.
y >> p2D.
phi))
348 "Line %u: Error parsing VERTEX2 line: '%s'",
349 lineNum, lin.c_str()));
352 if (
g->nodes.find(
id) !=
g->nodes.end())
355 "Line %u: Error, duplicated verted ID %u in line: " 357 lineNum, static_cast<unsigned int>(
id),
364 if (itEq != lstEquivs.end())
id = itEq->second;
368 if (
g->nodes.find(
id) ==
g->nodes.end())
371 CPOSE>::constraint_t::type_value pose_t;
378 else if (
strCmpI(key,
"VERTEX3"))
383 "Line %u: Try to load VERTEX3 into a 2D graph: " 385 lineNum, lin.c_str()));
392 if (!(
s >>
id >> p3D.
x >> p3D.
y >> p3D.
z >> p3D.
roll >>
396 "Line %u: Error parsing VERTEX3 line: '%s'",
397 lineNum, lin.c_str()));
400 if (
g->nodes.find(
id) !=
g->nodes.end())
403 "Line %u: Error, duplicated verted ID %u in line: " 405 lineNum, static_cast<unsigned int>(
id),
412 if (itEq != lstEquivs.end())
id = itEq->second;
416 if (
g->nodes.find(
id) ==
g->nodes.end())
424 else if (
strCmpI(key,
"VERTEX_SE3:QUAT"))
429 "Line %u: Try to load VERTEX_SE3:QUAT into a 2D " 431 lineNum, lin.c_str()));
436 if (!(
s >>
id >> p3D.
x >> p3D.
y >> p3D.
z >> p3D.
qx >> p3D.
qy >>
440 "Line %u: Error parsing VERTEX_SE3:QUAT line: '%s'",
441 lineNum, lin.c_str()));
444 if (
g->nodes.find(
id) !=
g->nodes.end())
447 "Line %u: Error, duplicated verted ID %u in line: " 449 lineNum, static_cast<unsigned int>(
id),
456 if (itEq != lstEquivs.end())
id = itEq->second;
460 if (
g->nodes.find(
id) ==
g->nodes.end())
482 if (!(
s >> from_id >> to_id))
485 "Line %u: Error parsing EDGE2 line: '%s'", lineNum,
491 lstEquivs.find(to_id);
492 if (itEq != lstEquivs.end()) to_id = itEq->second;
496 lstEquivs.find(from_id);
497 if (itEq != lstEquivs.end()) from_id = itEq->second;
500 if (from_id != to_id)
505 if (!(
s >> Ap_mean.
x >> Ap_mean.
y >> Ap_mean.
phi >>
506 Ap_cov_inv(0, 0) >> Ap_cov_inv(0, 1) >>
507 Ap_cov_inv(1, 1) >> Ap_cov_inv(2, 2) >>
508 Ap_cov_inv(0, 2) >> Ap_cov_inv(1, 2)))
511 "Line %u: Error parsing EDGE2 line: '%s'",
512 lineNum, lin.c_str()));
515 Ap_cov_inv(1, 0) = Ap_cov_inv(0, 1);
516 Ap_cov_inv(2, 0) = Ap_cov_inv(0, 2);
517 Ap_cov_inv(2, 1) = Ap_cov_inv(1, 2);
524 g->insertEdge(from_id, to_id, newEdge);
527 else if (
strCmpI(key,
"EDGE3"))
532 "Line %u: Try to load EDGE3 into a 2D graph: '%s'",
533 lineNum, lin.c_str()));
538 if (!(
s >> from_id >> to_id))
541 "Line %u: Error parsing EDGE3 line: '%s'", lineNum,
547 lstEquivs.find(to_id);
548 if (itEq != lstEquivs.end()) to_id = itEq->second;
552 lstEquivs.find(from_id);
553 if (itEq != lstEquivs.end()) from_id = itEq->second;
556 if (from_id != to_id)
563 if (!(
s >> Ap_mean.
x >> Ap_mean.
y >> Ap_mean.
z >>
567 "Line %u: Error parsing EDGE3 line: '%s'",
568 lineNum, lin.c_str()));
572 if (!(
s >> Ap_cov_inv(0, 0) >> Ap_cov_inv(0, 1) >>
573 Ap_cov_inv(0, 2) >> Ap_cov_inv(0, 5) >>
574 Ap_cov_inv(0, 4) >> Ap_cov_inv(0, 3) >>
575 Ap_cov_inv(1, 1) >> Ap_cov_inv(1, 2) >>
576 Ap_cov_inv(1, 5) >> Ap_cov_inv(1, 4) >>
577 Ap_cov_inv(1, 3) >> Ap_cov_inv(2, 2) >>
578 Ap_cov_inv(2, 5) >> Ap_cov_inv(2, 4) >>
579 Ap_cov_inv(2, 3) >> Ap_cov_inv(5, 5) >>
580 Ap_cov_inv(5, 4) >> Ap_cov_inv(5, 3) >>
581 Ap_cov_inv(4, 4) >> Ap_cov_inv(4, 3) >>
585 Ap_cov_inv.unit(6, 1.0);
587 if (alreadyWarnedUnknowns.find(
"MISSING_3D") ==
588 alreadyWarnedUnknowns.end())
590 alreadyWarnedUnknowns.insert(
"MISSING_3D");
591 cerr <<
"[CNetworkOfPoses::loadFromTextFile] " 592 << fil <<
":" << lineNum
593 <<
": Warning: Information matrix missing, " 600 for (
size_t r = 1;
r < 6;
r++)
601 for (
size_t c = 0;
c <
r;
c++)
602 Ap_cov_inv(
r,
c) = Ap_cov_inv(
c,
r);
610 g->insertEdge(from_id, to_id, newEdge);
613 else if (
strCmpI(key,
"EDGE_SE3:QUAT"))
618 "Line %u: Try to load EDGE3 into a 2D graph: '%s'",
619 lineNum, lin.c_str()));
626 if (!(
s >> from_id >> to_id))
629 "Line %u: Error parsing EDGE_SE3:QUAT line: '%s'",
630 lineNum, lin.c_str()));
635 lstEquivs.find(to_id);
636 if (itEq != lstEquivs.end()) to_id = itEq->second;
640 lstEquivs.find(from_id);
641 if (itEq != lstEquivs.end()) from_id = itEq->second;
644 if (from_id != to_id)
649 if (!(
s >> Ap_mean.
x >> Ap_mean.
y >> Ap_mean.
z >>
650 Ap_mean.
qx >> Ap_mean.
qy >> Ap_mean.
qz >> Ap_mean.
qr))
653 "Line %u: Error parsing EDGE_SE3:QUAT line: " 655 lineNum, lin.c_str()));
659 if (!(
s >> Ap_cov_inv(0, 0) >> Ap_cov_inv(0, 1) >>
660 Ap_cov_inv(0, 2) >> Ap_cov_inv(0, 5) >>
661 Ap_cov_inv(0, 4) >> Ap_cov_inv(0, 3) >>
662 Ap_cov_inv(1, 1) >> Ap_cov_inv(1, 2) >>
663 Ap_cov_inv(1, 5) >> Ap_cov_inv(1, 4) >>
664 Ap_cov_inv(1, 3) >> Ap_cov_inv(2, 2) >>
665 Ap_cov_inv(2, 5) >> Ap_cov_inv(2, 4) >>
666 Ap_cov_inv(2, 3) >> Ap_cov_inv(5, 5) >>
667 Ap_cov_inv(5, 4) >> Ap_cov_inv(5, 3) >>
668 Ap_cov_inv(4, 4) >> Ap_cov_inv(4, 3) >>
672 Ap_cov_inv.unit(6, 1.0);
674 if (alreadyWarnedUnknowns.find(
"MISSING_3D") ==
675 alreadyWarnedUnknowns.end())
677 alreadyWarnedUnknowns.insert(
"MISSING_3D");
678 cerr <<
"[CNetworkOfPoses::loadFromTextFile] " 679 << fil <<
":" << lineNum
680 <<
": Warning: Information matrix missing, " 687 for (
size_t r = 1;
r < 6;
r++)
688 for (
size_t c = 0;
c <
r;
c++)
689 Ap_cov_inv(
r,
c) = Ap_cov_inv(
c,
r);
698 g->insertEdge(from_id, to_id, newEdge);
701 else if (
strCmpI(key,
"EQUIV"))
707 if (alreadyWarnedUnknowns.find(key) ==
708 alreadyWarnedUnknowns.end())
710 alreadyWarnedUnknowns.insert(key);
711 cerr <<
"[CNetworkOfPoses::loadFromTextFile] " << fil <<
":" 712 << lineNum <<
": Warning: unknown entry type: " << key
737 typedef map<pair<TNodeID, TNodeID>, vector<TEdgeIterator>>
740 TListAllEdges lstAllEdges;
743 for (TEdgeIterator itEd =
g->edges.begin(); itEd !=
g->edges.end();
747 const pair<TNodeID, TNodeID> arc_id = make_pair(
748 std::min(itEd->first.first, itEd->first.second),
749 std::max(itEd->first.first, itEd->first.second));
751 vector<TEdgeIterator>& lstEdges = lstAllEdges[arc_id];
753 lstEdges.push_back(itEd);
759 it != lstAllEdges.end(); ++it)
761 const size_t N = it->second.size();
762 for (
size_t i = 1; i < N; i++)
763 g->edges.erase(it->second[i]);
765 if (N >= 2) nRemoved += N - 1;
789 typedef typename graph_t::constraint_t constraint_t;
792 dijkstra_t dijkstra(*
g,
g->root);
796 typename dijkstra_t::tree_graph_t treeView;
797 dijkstra.getTreeGraph(treeView);
800 struct VisitorComputePoses :
public dijkstra_t::tree_graph_t::Visitor
804 VisitorComputePoses(graph_t*
g) : m_g(
g) {}
805 virtual void OnVisitNode(
807 const typename dijkstra_t::tree_graph_t::Visitor::tree_t::
808 TEdgeInfo& edge_to_child,
809 const size_t depth_level)
override 812 const TNodeID child_id = edge_to_child.id;
818 if ((!edge_to_child.reverse &&
819 !m_g->edges_store_inverse_poses) ||
820 (edge_to_child.reverse && m_g->edges_store_inverse_poses))
822 m_g->nodes[child_id].composeFrom(
823 m_g->nodes[parent_id],
824 edge_to_child.data->getPoseMean());
828 m_g->nodes[child_id].composeFrom(
829 m_g->nodes[parent_id],
830 -edge_to_child.data->getPoseMean());
840 bool empty_node_annots =
g->nodes.begin()->second.is_node_annots_empty;
841 map<const TNodeID, TNodeAnnotations*> nodeID_to_annots;
842 if (!empty_node_annots)
846 poses_cit !=
g->nodes.end(); ++poses_cit)
848 nodeID_to_annots.insert(
850 poses_cit->first, poses_cit->second.getCopyOfAnnots()));
856 typename constraint_t::type_value();
859 VisitorComputePoses myVisitor(
g);
860 treeView.visitBreadthFirst(treeView.root, myVisitor);
863 if (!empty_node_annots)
867 poses_cit !=
g->nodes.end(); ++poses_cit)
870 nodeID_to_annots.at(poses_cit->first);
871 bool res = poses_cit->second.setAnnots(*node_annots);
880 "Setting annotations for nodeID \"%lu\" was " 882 static_cast<unsigned long>(poses_cit->first)));
971 bool ignoreCovariances)
976 const TNodeID from_id = itEdge->first.first;
977 const TNodeID to_id = itEdge->first.second;
981 g->nodes.find(from_id);
983 g->nodes.find(to_id);
985 itPoseFrom !=
g->nodes.end(),
987 "Node %u doesn't have a global pose in 'nodes'.",
988 static_cast<unsigned int>(from_id)))
990 itPoseTo !=
g->nodes.end(),
992 "Node %u doesn't have a global pose in 'nodes'.",
993 static_cast<unsigned int>(to_id)))
996 typedef typename graph_t::constraint_t constraint_t;
998 const typename constraint_t::type_value& from_mean = itPoseFrom->second;
999 const typename constraint_t::type_value& to_mean = itPoseTo->second;
1002 const constraint_t& edge_delta_pose = itEdge->second;
1003 const typename constraint_t::type_value& edge_delta_pose_mean =
1004 edge_delta_pose.getPoseMean();
1006 if (ignoreCovariances)
1009 typename constraint_t::type_value from_plus_delta(
1011 from_plus_delta.composeFrom(from_mean, edge_delta_pose_mean);
1014 return auxEuclid2Dist(from_plus_delta, to_mean);
1020 constraint_t from_plus_delta = edge_delta_pose;
1021 from_plus_delta.changeCoordinatesReference(from_mean);
1030 err[i] = from_plus_delta.getPoseMean()[i] - to_mean[i];
1033 return auxMaha2Dist(err, from_plus_delta);
#define ASSERT_EQUAL_(__A, __B)
A directed graph with the argument of the template specifying the type of the annotations in the edge...
static double auxMaha2Dist(VEC &err, const CPosePDFGaussian &p)
double x() const
Common members of all points & poses classes.
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
std::pair< TNodeID, TNodeID > TPairNodeIDs
A pair of node IDs.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
A template to obtain the type of its argument as a string at compile time.
Abstract class from which NodeAnnotations related classes can be implemented.
bool getNextLine(std::string &out_str)
Reads from the file and return the next (non-comment) line, as a std::string.
double roll
Roll coordinate (rotation angle over X coordinate).
static double auxMaha2Dist(VEC &err, const mrpt::poses::CPose2D &p)
#define THROW_EXCEPTION(msg)
Abstract graph and tree data structures, plus generic graph algorithms.
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
mrpt::math::CMatrixDouble66 cov_inv
The inverse of the 6x6 covariance matrix.
double pitch() const
Get the PITCH angle (in radians)
double yaw() const
Get the YAW angle (in radians)
This file implements miscelaneous matrix and matrix/vector operations, and internal functions in mrpt...
MAT_C::Scalar multiply_HCHt_scalar(const VECTOR_H &H, const MAT_C &C)
r (a scalar) = H * C * H^t (with a vector H and a symmetric matrix C)
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const CPose3DPDFGaussianInf &edge, std::ofstream &f)
const Scalar * const_iterator
double yaw
Yaw coordinate (rotation angle over Z axis).
static double auxMaha2Dist(VEC &err, const CPosePDFGaussianInf &p)
static void read_graph_of_poses_from_binary_file(graph_t *g, mrpt::utils::CStream &in)
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const CPose3DPDFGaussian &edge, std::ofstream &f)
static double auxEuclid2Dist(const mrpt::poses::CPose2D &p1, const mrpt::poses::CPose2D &p2)
static double auxEuclid2Dist(const mrpt::poses::CPose3D &p1, const mrpt::poses::CPose3D &p2)
static void graph_of_poses_dijkstra_init(graph_t *g)
T square(const T x)
Inline function for the square of a number.
A directed graph of pose constraints, with edges being the relative poses between pairs of nodes iden...
void rewind()
Reset the read pointer to the beginning of the file.
static void copyFrom2D(CPose2D &p, const CPosePDFGaussianInf &pdf)
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const CPosePDFGaussian &edge, std::ofstream &f)
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
void wrapToPiInPlace(T &a)
Modifies the given angle to translate it into the ]-pi,pi] range.
This base provides a set of functions for maths stuff.
static void save_graph_of_poses_to_binary_file(const graph_t *g, mrpt::utils::CStream &out)
Declares a class that represents a Probability Density function (PDF) of a 2D pose ...
uint64_t TNodeID
The type for node IDs in graphs of different types.
#define MRPT_UNUSED_PARAM(a)
Can be used to avoid "not used parameters" warnings from the compiler.
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const mrpt::poses::CPose3D &edge, std::ofstream &f)
static void copyFrom2D(POSE_PDF &p, const CPosePDFGaussianInf &pdf)
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
static void copyFrom2D(CPose3D &p, const CPosePDFGaussianInf &pdf)
double x
Translation in x,y,z.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
static double auxMaha2Dist(VEC &err, const CPose3DPDFGaussian &p)
CPose3D mean
The mean value.
A class used to store a 3D pose as a translation (x,y,z) and a quaternion (qr,qx,qy,qz).
A class for parsing text files, returning each non-empty and non-comment line, along its line number...
GLsizei const GLchar ** string
T wrapToPi(T a)
Modifies the given angle to translate it into the ]-pi,pi] range.
double qr
Unit quaternion part, qr,qx,qy,qz.
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
double roll() const
Get the ROLL angle (in radians)
double pitch
Pitch coordinate (rotation angle over Y axis).
Lightweight 3D pose (three spatial coordinates, plus a quaternion ).
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...
GLdouble GLdouble GLdouble r
CPose2D mean
The mean value.
A class used to store a 2D pose, including the 2D coordinate point and a heading (phi) angle...
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
This file implements matrix/vector text and binary serialization.
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)
const double & phi() const
Get the phi angle of the 2D pose (in radians)
static void copyFrom3D(CPose3D &p, const CPose3DPDFGaussianInf &pdf)
Lightweight 3D pose (three spatial coordinates, plus three angular coordinates).
Declares a class that represents a Probability Density function (PDF) of a 3D pose as a Gaussian des...
A partial specialization of CArrayNumeric for double numbers.
Declares a class that represents a Probability Density function (PDF) of a 3D pose ...
size_t getCurrentLineNumber() const
Return the line number of the last line returned with getNextLine.
static void load_graph_of_poses_from_text_file(graph_t *g, const std::string &fil)
global_poses_t nodes
The nodes (vertices) of the graph, with their estimated "global" (with respect to root) position...
static double auxMaha2Dist(VEC &err, const CPose3DPDFGaussianInf &p)
The Dijkstra algorithm for finding the shortest path between a given source node in a (weighted) dire...
static void copyFrom3D(CPose2D &p, const CPose3DPDFGaussianInf &pdf)
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const mrpt::poses::CPose2D &edge, std::ofstream &f)
static void copyFrom3D(POSE_PDF &p, const CPose3DPDFGaussianInf &pdf)
bool strCmpI(const std::string &s1, const std::string &s2)
Return true if the two strings are equal (case insensitive)
unsigned __int32 uint32_t
static void write_VERTEX_line(const TNodeID id, const mrpt::poses::CPose2D &p, std::ofstream &f)
#define ASSERTMSG_(f, __ERROR_MSG)
double phi
Orientation (rads)
mrpt::math::CMatrixDouble33 cov_inv
The inverse of the 3x3 covariance matrix (the "information" matrix)
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const CPosePDFGaussianInf &edge, std::ofstream &f)
static void write_VERTEX_line(const TNodeID id, const mrpt::poses::CPose3D &p, std::ofstream &f)
static double auxMaha2Dist(VEC &err, const mrpt::poses::CPose3D &p)