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);
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);
The Dijkstra algorithm for finding the shortest path between a given source node in a (weighted) dire...
A directed graph with the argument of the template specifying the type of the annotations in the edge...
A directed graph of pose constraints, with edges being the relative poses between pairs of nodes iden...
global_poses_t nodes
The nodes (vertices) of the graph, with their estimated "global" (with respect to root) position,...
A class for parsing text files, returning each non-empty and non-comment line, along its line number.
size_t getCurrentLineNumber() const
Return the line number of the last line returned with getNextLine.
void rewind()
Reset the read pointer to the beginning of the file.
bool getNextLine(std::string &out_str)
Reads from the file and return the next (non-comment) line, as a std::string.
CArrayNumeric is an array for numeric types supporting several mathematical operations (actually,...
A class used to store a 2D pose, including the 2D coordinate point and a heading (phi) angle.
const double & phi() const
Get the phi angle of the 2D pose (in radians)
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
double pitch() const
Get the PITCH angle (in radians)
double roll() const
Get the ROLL angle (in radians)
double yaw() const
Get the YAW angle (in radians)
Declares a class that represents a Probability Density function (PDF) of a 3D pose .
Declares a class that represents a Probability Density function (PDF) of a 3D pose as a Gaussian des...
CPose3D mean
The mean value.
mrpt::math::CMatrixDouble66 cov_inv
The inverse of the 6x6 covariance matrix.
A class used to store a 3D pose as a translation (x,y,z) and a quaternion (qr,qx,qy,...
double x() const
Common members of all points & poses classes.
Declares a class that represents a Probability Density function (PDF) of a 2D pose .
A Probability Density function (PDF) of a 2D pose as a Gaussian with a mean and the inverse of the c...
mrpt::math::CMatrixDouble33 cov_inv
The inverse of the 3x3 covariance matrix (the "information" matrix)
CPose2D mean
The mean value.
Virtual base class for "archives": classes abstracting I/O streams.
#define MRPT_UNUSED_PARAM(a)
Determines whether this is an X86 or AMD64 platform.
const Scalar * const_iterator
#define ASSERT_EQUAL_(__A, __B)
Assert comparing two values, reporting their actual values upon failure.
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
#define THROW_EXCEPTION(msg)
#define ASSERTMSG_(f, __ERROR_MSG)
Defines an assertion mechanism.
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
GLdouble GLdouble GLdouble r
GLenum GLsizei GLenum format
GLsizei const GLchar ** string
void wrapToPiInPlace(T &a)
Modifies the given angle to translate it into the ]-pi,pi] range.
T wrapToPi(T a)
Modifies the given angle to translate it into the ]-pi,pi] range.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
bool strCmpI(const std::string &s1, const std::string &s2)
Return true if the two strings are equal (case insensitive)
This file implements matrix/vector text and binary serialization.
Internal functions for MRPT.
Abstract graph and tree data structures, plus generic graph algorithms.
std::pair< TNodeID, TNodeID > TPairNodeIDs
A pair of node IDs.
uint64_t TNodeID
A generic numeric type for unique IDs of nodes or entities.
This base provides a set of functions for maths stuff.
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)
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
T square(const T x)
Inline function for the square of a number.
This file implements miscelaneous matrix and matrix/vector operations, and internal functions in mrpt...
unsigned __int32 uint32_t
Abstract class from which NodeAnnotations related classes can be implemented.
bool setAnnots(const self_t &other)
Set the properties of the current TNodeAnnotations object.
static void copyFrom3D(CPose2D &p, const CPose3DPDFGaussianInf &pdf)
static void copyFrom2D(CPose2D &p, const CPosePDFGaussianInf &pdf)
static void copyFrom3D(CPose3D &p, const CPose3DPDFGaussianInf &pdf)
static void copyFrom2D(CPose3D &p, const CPosePDFGaussianInf &pdf)
static void copyFrom2D(POSE_PDF &p, const CPosePDFGaussianInf &pdf)
static void copyFrom3D(POSE_PDF &p, const CPose3DPDFGaussianInf &pdf)
a helper struct with static template functions
static void write_VERTEX_line(const TNodeID id, const mrpt::poses::CPose3D &p, std::ostream &f)
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const CPosePDFGaussian &edge, std::ostream &f)
static void write_VERTEX_line(const TNodeID id, const mrpt::poses::CPose2D &p, std::ostream &f)
static void graph_of_poses_dijkstra_init(graph_t *g)
static void load_graph_of_poses_from_text_stream(graph_t *g, std::istream &f, const std::string &fil=std::string("(none)"))
static double auxMaha2Dist(VEC &err, const CPosePDFGaussianInf &p)
static double auxEuclid2Dist(const mrpt::poses::CPose2D &p1, const mrpt::poses::CPose2D &p2)
static size_t graph_of_poses_collapse_dup_edges(graph_t *g)
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const CPosePDFGaussianInf &edge, std::ostream &f)
static double auxMaha2Dist(VEC &err, const CPose3DPDFGaussian &p)
static double auxMaha2Dist(VEC &err, const CPose3DPDFGaussianInf &p)
static double auxMaha2Dist(VEC &err, const CPosePDFGaussian &p)
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const CPose3DPDFGaussian &edge, std::ostream &f)
static void save_graph_of_poses_to_ostream(const graph_t *g, std::ostream &f)
static void load_graph_of_poses_from_text_file(graph_t *g, const std::string &fil)
static void read_graph_of_poses_from_binary_file(graph_t *g, mrpt::serialization::CArchive &in)
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const mrpt::poses::CPose2D &edge, std::ostream &f)
static double auxEuclid2Dist(const mrpt::poses::CPose3D &p1, const mrpt::poses::CPose3D &p2)
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const CPose3DPDFGaussianInf &edge, std::ostream &f)
static void save_graph_of_poses_to_binary_file(const graph_t *g, mrpt::serialization::CArchive &out)
static double auxMaha2Dist(VEC &err, const mrpt::poses::CPose3D &p)
static void write_EDGE_line(const TPairNodeIDs &edgeIDs, const mrpt::poses::CPose3D &edge, std::ostream &f)
static double auxMaha2Dist(VEC &err, const mrpt::poses::CPose2D &p)
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)
static void save_graph_of_poses_to_text_file(const graph_t *g, const std::string &fil)
double phi
Orientation (rads)
Lightweight 3D pose (three spatial coordinates, plus three angular coordinates).
double roll
Roll coordinate (rotation angle over X coordinate).
double pitch
Pitch coordinate (rotation angle over Y axis).
double yaw
Yaw coordinate (rotation angle over Z axis).
Lightweight 3D pose (three spatial coordinates, plus a quaternion ).
double x
Translation in x,y,z.
double qr
Unit quaternion part, qr,qx,qy,qz.