9 #ifndef CONSTRAINED_POSE_NETWORK_IMPL_H 10 #define CONSTRAINED_POSE_NETWORK_IMPL_H 36 template <
class POSE_PDF>
74 template <
class graph_t>
81 f <<
"VERTEX_SE2 " <<
id <<
" " <<
p.x() <<
" " <<
p.y() <<
" " 90 f <<
"VERTEX3 " <<
id <<
" " <<
p.x() <<
" " <<
p.y() <<
" " <<
p.z()
91 <<
" " <<
p.roll() <<
" " <<
p.pitch() <<
" " <<
p.yaw();
100 f <<
"EDGE_SE2 " << edgeIDs.first <<
" " << edgeIDs.second <<
" " 116 f <<
"EDGE3 " << edgeIDs.first <<
" " << edgeIDs.second <<
" " 137 write_EDGE_line(edgeIDs,
p, f);
145 write_EDGE_line(edgeIDs,
p, f);
153 p.cov_inv.unit(3, 1.0);
154 write_EDGE_line(edgeIDs,
p, f);
162 p.cov_inv.unit(6, 1.0);
163 write_EDGE_line(edgeIDs,
p, f);
167 const graph_t*
g, std::ostream& f)
170 for (
const auto&
n :
g->nodes)
172 write_VERTEX_line(
n.first,
n.second, f);
174 const auto sAnnot =
n.second.retAnnotsAsString();
175 if (!sAnnot.empty()) f <<
" | " << sAnnot;
178 if (
n.first ==
g->root) f <<
"FIX " <<
n.first << endl;
182 for (
const auto& e : *
g)
183 if (e.first.first != e.first.second)
184 write_EDGE_line(e.first, e.second, f);
198 "Error opening file '%s' for writing", fil.c_str());
199 save_graph_of_poses_to_ostream(
g, f);
216 out <<
g->nodes <<
g->edges <<
g->root;
229 in >> sStoredClassName;
234 in >> stored_version;
237 switch (stored_version)
240 in >>
g->nodes >>
g->edges >>
g->root;
251 graph_t*
g, std::istream& f,
257 using CPOSE =
typename graph_t::constraint_t;
259 set<string> alreadyWarnedUnknowns;
268 const bool graph_is_3D = CPOSE::is_3D();
277 map<TNodeID, TNodeID> lstEquivs;
286 const string lin =
s.str();
289 if (!(
s >> key) || key.empty())
291 "Line %u: Can't read string for entry type in: '%s'",
292 lineNum, lin.c_str()));
298 if (!(
s >> id1 >> id2))
300 "Line %u: Can't read id1 & id2 in EQUIV line: '%s'",
301 lineNum, lin.c_str()));
302 lstEquivs[std::max(id1, id2)] =
std::min(id1, id2);
315 const string lin =
s.str();
331 if (!(
s >> key) || key.empty())
333 "Line %u: Can't read string for entry type in: '%s'",
334 lineNum, lin.c_str()));
341 if (!(
s >>
id >> p2D.
x >> p2D.
y >> p2D.
phi))
343 "Line %u: Error parsing VERTEX2 line: '%s'", lineNum,
347 if (
g->nodes.find(
id) !=
g->nodes.end())
349 "Line %u: Error, duplicated verted ID %u in line: " 351 lineNum, static_cast<unsigned int>(
id), lin.c_str()));
357 if (itEq != lstEquivs.end())
id = itEq->second;
361 if (
g->nodes.find(
id) ==
g->nodes.end())
364 CPOSE>::constraint_t::type_value;
370 else if (
strCmpI(key,
"VERTEX3"))
374 "Line %u: Try to load VERTEX3 into a 2D graph: " 376 lineNum, lin.c_str()));
383 if (!(
s >>
id >> p3D.
x >> p3D.
y >> p3D.
z >> p3D.
roll >>
386 "Line %u: Error parsing VERTEX3 line: '%s'", lineNum,
390 if (
g->nodes.find(
id) !=
g->nodes.end())
392 "Line %u: Error, duplicated verted ID %u in line: " 394 lineNum, static_cast<unsigned int>(
id), lin.c_str()));
400 if (itEq != lstEquivs.end())
id = itEq->second;
404 if (
g->nodes.find(
id) ==
g->nodes.end())
411 else if (
strCmpI(key,
"VERTEX_SE3:QUAT"))
415 "Line %u: Try to load VERTEX_SE3:QUAT into a 2D " 417 lineNum, lin.c_str()));
422 if (!(
s >>
id >> p3D.
x >> p3D.
y >> p3D.
z >> p3D.
qx >> p3D.
qy >>
425 "Line %u: Error parsing VERTEX_SE3:QUAT line: '%s'",
426 lineNum, lin.c_str()));
429 if (
g->nodes.find(
id) !=
g->nodes.end())
431 "Line %u: Error, duplicated verted ID %u in line: " 433 lineNum, static_cast<unsigned int>(
id), lin.c_str()));
439 if (itEq != lstEquivs.end())
id = itEq->second;
443 if (
g->nodes.find(
id) ==
g->nodes.end())
462 if (!(
s >> from_id >> to_id))
464 "Line %u: Error parsing EDGE2 line: '%s'", lineNum,
470 lstEquivs.find(to_id);
471 if (itEq != lstEquivs.end()) to_id = itEq->second;
475 lstEquivs.find(from_id);
476 if (itEq != lstEquivs.end()) from_id = itEq->second;
479 if (from_id != to_id)
484 if (!(
s >> Ap_mean.
x >> Ap_mean.
y >> Ap_mean.
phi >>
485 Ap_cov_inv(0, 0) >> Ap_cov_inv(0, 1) >>
486 Ap_cov_inv(0, 2) >> Ap_cov_inv(1, 1) >>
487 Ap_cov_inv(1, 2) >> Ap_cov_inv(2, 2)))
489 "Line %u: Error parsing EDGE2 line: '%s'", lineNum,
493 Ap_cov_inv(1, 0) = Ap_cov_inv(0, 1);
494 Ap_cov_inv(2, 0) = Ap_cov_inv(0, 2);
495 Ap_cov_inv(2, 1) = Ap_cov_inv(1, 2);
502 g->insertEdge(from_id, to_id, newEdge);
505 else if (
strCmpI(key,
"EDGE3"))
509 "Line %u: Try to load EDGE3 into a 2D graph: '%s'",
510 lineNum, lin.c_str()));
515 if (!(
s >> from_id >> to_id))
517 "Line %u: Error parsing EDGE3 line: '%s'", lineNum,
523 lstEquivs.find(to_id);
524 if (itEq != lstEquivs.end()) to_id = itEq->second;
528 lstEquivs.find(from_id);
529 if (itEq != lstEquivs.end()) from_id = itEq->second;
532 if (from_id != to_id)
539 if (!(
s >> Ap_mean.
x >> Ap_mean.
y >> Ap_mean.
z >>
542 "Line %u: Error parsing EDGE3 line: '%s'", lineNum,
547 if (!(
s >> Ap_cov_inv(0, 0) >> Ap_cov_inv(0, 1) >>
548 Ap_cov_inv(0, 2) >> Ap_cov_inv(0, 5) >>
549 Ap_cov_inv(0, 4) >> Ap_cov_inv(0, 3) >>
550 Ap_cov_inv(1, 1) >> Ap_cov_inv(1, 2) >>
551 Ap_cov_inv(1, 5) >> Ap_cov_inv(1, 4) >>
552 Ap_cov_inv(1, 3) >> Ap_cov_inv(2, 2) >>
553 Ap_cov_inv(2, 5) >> Ap_cov_inv(2, 4) >>
554 Ap_cov_inv(2, 3) >> Ap_cov_inv(5, 5) >>
555 Ap_cov_inv(5, 4) >> Ap_cov_inv(5, 3) >>
556 Ap_cov_inv(4, 4) >> Ap_cov_inv(4, 3) >>
560 Ap_cov_inv.unit(6, 1.0);
562 if (alreadyWarnedUnknowns.find(
"MISSING_3D") ==
563 alreadyWarnedUnknowns.end())
565 alreadyWarnedUnknowns.insert(
"MISSING_3D");
566 cerr <<
"[CNetworkOfPoses::loadFromTextFile] " 567 << fil <<
":" << lineNum
568 <<
": Warning: Information matrix missing, " 575 for (
size_t r = 1;
r < 6;
r++)
576 for (
size_t c = 0;
c <
r;
c++)
577 Ap_cov_inv(
r,
c) = Ap_cov_inv(
c,
r);
585 g->insertEdge(from_id, to_id, newEdge);
588 else if (
strCmpI(key,
"EDGE_SE3:QUAT"))
592 "Line %u: Try to load EDGE3 into a 2D graph: '%s'",
593 lineNum, lin.c_str()));
600 if (!(
s >> from_id >> to_id))
602 "Line %u: Error parsing EDGE_SE3:QUAT line: '%s'",
603 lineNum, lin.c_str()));
608 lstEquivs.find(to_id);
609 if (itEq != lstEquivs.end()) to_id = itEq->second;
613 lstEquivs.find(from_id);
614 if (itEq != lstEquivs.end()) from_id = itEq->second;
617 if (from_id != to_id)
622 if (!(
s >> Ap_mean.
x >> Ap_mean.
y >> Ap_mean.
z >>
623 Ap_mean.
qx >> Ap_mean.
qy >> Ap_mean.
qz >> Ap_mean.
qr))
625 "Line %u: Error parsing EDGE_SE3:QUAT line: " 627 lineNum, lin.c_str()));
631 if (!(
s >> Ap_cov_inv(0, 0) >> Ap_cov_inv(0, 1) >>
632 Ap_cov_inv(0, 2) >> Ap_cov_inv(0, 5) >>
633 Ap_cov_inv(0, 4) >> Ap_cov_inv(0, 3) >>
634 Ap_cov_inv(1, 1) >> Ap_cov_inv(1, 2) >>
635 Ap_cov_inv(1, 5) >> Ap_cov_inv(1, 4) >>
636 Ap_cov_inv(1, 3) >> Ap_cov_inv(2, 2) >>
637 Ap_cov_inv(2, 5) >> Ap_cov_inv(2, 4) >>
638 Ap_cov_inv(2, 3) >> Ap_cov_inv(5, 5) >>
639 Ap_cov_inv(5, 4) >> Ap_cov_inv(5, 3) >>
640 Ap_cov_inv(4, 4) >> Ap_cov_inv(4, 3) >>
644 Ap_cov_inv.unit(6, 1.0);
646 if (alreadyWarnedUnknowns.find(
"MISSING_3D") ==
647 alreadyWarnedUnknowns.end())
649 alreadyWarnedUnknowns.insert(
"MISSING_3D");
650 cerr <<
"[CNetworkOfPoses::loadFromTextFile] " 651 << fil <<
":" << lineNum
652 <<
": Warning: Information matrix missing, " 659 for (
size_t r = 1;
r < 6;
r++)
660 for (
size_t c = 0;
c <
r;
c++)
661 Ap_cov_inv(
r,
c) = Ap_cov_inv(
c,
r);
670 g->insertEdge(from_id, to_id, newEdge);
673 else if (
strCmpI(key,
"EQUIV"))
682 "Line %u: Can't read id in FIX line: '%s'",
683 lineNum, lin.c_str()));
688 if (alreadyWarnedUnknowns.find(key) ==
689 alreadyWarnedUnknowns.end())
691 alreadyWarnedUnknowns.insert(key);
692 cerr <<
"[CNetworkOfPoses::loadFromTextFile] " << fil <<
":" 693 << lineNum <<
": Warning: unknown entry type: " << key
704 std::ifstream f(fil);
707 "Error opening file '%s' for reading", fil.c_str());
708 load_graph_of_poses_from_text_stream(
g, f, fil);
728 using TListAllEdges =
729 map<pair<TNodeID, TNodeID>,
730 vector<TEdgeIterator>>;
733 TListAllEdges lstAllEdges;
736 for (TEdgeIterator itEd =
g->edges.begin(); itEd !=
g->edges.end();
740 const pair<TNodeID, TNodeID> arc_id = make_pair(
741 std::min(itEd->first.first, itEd->first.second),
742 std::max(itEd->first.first, itEd->first.second));
744 vector<TEdgeIterator>& lstEdges = lstAllEdges[arc_id];
746 lstEdges.push_back(itEd);
752 it != lstAllEdges.end(); ++it)
754 const size_t N = it->second.size();
755 for (
size_t i = 1; i < N; i++)
756 g->edges.erase(it->second[i]);
758 if (N >= 2) nRemoved += N - 1;
782 using constraint_t =
typename graph_t::constraint_t;
785 dijkstra_t dijkstra(*
g,
g->root);
789 typename dijkstra_t::tree_graph_t treeView;
790 dijkstra.getTreeGraph(treeView);
793 struct VisitorComputePoses :
public dijkstra_t::tree_graph_t::Visitor
797 VisitorComputePoses(graph_t*
g) : m_g(
g) {}
798 virtual void OnVisitNode(
800 const typename dijkstra_t::tree_graph_t::Visitor::tree_t::
801 TEdgeInfo& edge_to_child,
802 const size_t depth_level)
override 805 const TNodeID child_id = edge_to_child.id;
811 if ((!edge_to_child.reverse &&
812 !m_g->edges_store_inverse_poses) ||
813 (edge_to_child.reverse && m_g->edges_store_inverse_poses))
815 m_g->nodes[child_id].composeFrom(
816 m_g->nodes[parent_id],
817 edge_to_child.data->getPoseMean());
821 m_g->nodes[child_id].composeFrom(
822 m_g->nodes[parent_id],
823 -edge_to_child.data->getPoseMean());
833 bool empty_node_annots =
g->nodes.begin()->second.is_node_annots_empty;
834 map<const TNodeID, TNodeAnnotations*> nodeID_to_annots;
835 if (!empty_node_annots)
839 poses_cit !=
g->nodes.end(); ++poses_cit)
841 nodeID_to_annots.insert(make_pair(
842 poses_cit->first, poses_cit->second.getCopyOfAnnots()));
848 typename constraint_t::type_value();
851 VisitorComputePoses myVisitor(
g);
852 treeView.visitBreadthFirst(treeView.root, myVisitor);
855 if (!empty_node_annots)
859 poses_cit !=
g->nodes.end(); ++poses_cit)
862 nodeID_to_annots.at(poses_cit->first);
863 bool res = poses_cit->second.setAnnots(*node_annots);
872 "Setting annotations for nodeID \"%lu\" was " 874 static_cast<unsigned long>(poses_cit->first)));
963 bool ignoreCovariances)
968 const TNodeID from_id = itEdge->first.first;
969 const TNodeID to_id = itEdge->first.second;
973 g->nodes.find(from_id);
975 g->nodes.find(to_id);
977 itPoseFrom !=
g->nodes.end(),
979 "Node %u doesn't have a global pose in 'nodes'.",
980 static_cast<unsigned int>(from_id)));
982 itPoseTo !=
g->nodes.end(),
984 "Node %u doesn't have a global pose in 'nodes'.",
985 static_cast<unsigned int>(to_id)));
988 using constraint_t =
typename graph_t::constraint_t;
990 const typename constraint_t::type_value& from_mean = itPoseFrom->second;
991 const typename constraint_t::type_value& to_mean = itPoseTo->second;
994 const constraint_t& edge_delta_pose = itEdge->second;
995 const typename constraint_t::type_value& edge_delta_pose_mean =
996 edge_delta_pose.getPoseMean();
998 if (ignoreCovariances)
1001 typename constraint_t::type_value from_plus_delta(
1003 from_plus_delta.composeFrom(from_mean, edge_delta_pose_mean);
1006 return auxEuclid2Dist(from_plus_delta, to_mean);
1012 constraint_t from_plus_delta = edge_delta_pose;
1013 from_plus_delta.changeCoordinatesReference(from_mean);
1022 err[i] = from_plus_delta.getPoseMean()[i] - to_mean[i];
1025 return auxMaha2Dist(err, from_plus_delta);
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.
static void save_graph_of_poses_to_binary_file(const graph_t *g, mrpt::serialization::CArchive &out)
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const CPosePDFGaussianInf &edge, std::ostream &f)
#define THROW_EXCEPTION(msg)
Abstract class from which NodeAnnotations related classes can be implemented.
double roll
Roll coordinate (rotation angle over X coordinate).
static double auxMaha2Dist(VEC &err, const mrpt::poses::CPose2D &p)
Abstract graph and tree data structures, plus generic graph algorithms.
mrpt::math::CMatrixDouble66 cov_inv
The inverse of the 6x6 covariance matrix.
CArrayNumeric is an array for numeric types supporting several mathematical operations (actually...
A class for parsing text files, returning each non-empty and non-comment line, along its line number...
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)
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::serialization::CArchive &in)
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)
A directed graph of pose constraints, with edges being the relative poses between pairs of nodes iden...
static void copyFrom2D(CPose2D &p, const CPosePDFGaussianInf &pdf)
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const CPose3DPDFGaussian &edge, std::ostream &f)
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
T square(const T x)
Inline function for the square of a number.
void rewind()
Reset the read pointer to the beginning of the file.
size_t getCurrentLineNumber() const
Return the line number of the last line returned with getNextLine.
void wrapToPiInPlace(T &a)
Modifies the given angle to translate it into the ]-pi,pi] range.
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.
Declares a class that represents a Probability Density function (PDF) of a 2D pose ...
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const CPosePDFGaussian &edge, std::ostream &f)
#define ASSERT_EQUAL_(__A, __B)
Assert comparing two values, reporting their actual values upon failure.
static void copyFrom2D(POSE_PDF &p, const CPosePDFGaussianInf &pdf)
static void copyFrom2D(CPose3D &p, const CPosePDFGaussianInf &pdf)
double x
Translation in x,y,z.
static double auxMaha2Dist(VEC &err, const CPose3DPDFGaussian &p)
#define ASSERTMSG_(f, __ERROR_MSG)
Defines an assertion mechanism.
bool getNextLine(std::string &out_str)
Reads from the file and return the next (non-comment) line, as a std::string.
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).
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)
static void load_graph_of_poses_from_text_stream(graph_t *g, std::istream &f, const std::string &fil=std::string("(none)"))
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...
Virtual base class for "archives": classes abstracting I/O streams.
GLdouble GLdouble GLdouble r
CPose2D mean
The mean value.
static void write_VERTEX_line(const TNodeID id, const mrpt::poses::CPose2D &p, std::ostream &f)
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).
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
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)
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const mrpt::poses::CPose3D &edge, std::ostream &f)
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...
uint64_t TNodeID
A generic numeric type for unique IDs of nodes or entities.
Declares a class that represents a Probability Density function (PDF) of a 3D pose ...
static void load_graph_of_poses_from_text_file(graph_t *g, const std::string &fil)
std::pair< TNodeID, TNodeID > TPairNodeIDs
A pair of node IDs.
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const mrpt::poses::CPose2D &edge, std::ostream &f)
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 write_EDGE_line(const TPairNodeIDs &edgeIDs, const CPose3DPDFGaussianInf &edge, std::ostream &f)
static void copyFrom3D(CPose2D &p, const CPose3DPDFGaussianInf &pdf)
static void copyFrom3D(POSE_PDF &p, const CPose3DPDFGaussianInf &pdf)
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
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::CPose3D &p, std::ostream &f)
const Scalar * const_iterator
double phi
Orientation (rads)
mrpt::math::CMatrixDouble33 cov_inv
The inverse of the 3x3 covariance matrix (the "information" matrix)
static double auxMaha2Dist(VEC &err, const mrpt::poses::CPose3D &p)
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.