Main MRPT website > C++ reference
MRPT logo
CNetworkOfPoses_impl.h
Go to the documentation of this file.
00001 /* +---------------------------------------------------------------------------+
00002    |          The Mobile Robot Programming Toolkit (MRPT) C++ library          |
00003    |                                                                           |
00004    |                       http://www.mrpt.org/                                |
00005    |                                                                           |
00006    |   Copyright (C) 2005-2011  University of Malaga                           |
00007    |                                                                           |
00008    |    This software was written by the Machine Perception and Intelligent    |
00009    |      Robotics Lab, University of Malaga (Spain).                          |
00010    |    Contact: Jose-Luis Blanco  <jlblanco@ctima.uma.es>                     |
00011    |                                                                           |
00012    |  This file is part of the MRPT project.                                   |
00013    |                                                                           |
00014    |     MRPT is free software: you can redistribute it and/or modify          |
00015    |     it under the terms of the GNU General Public License as published by  |
00016    |     the Free Software Foundation, either version 3 of the License, or     |
00017    |     (at your option) any later version.                                   |
00018    |                                                                           |
00019    |   MRPT is distributed in the hope that it will be useful,                 |
00020    |     but WITHOUT ANY WARRANTY; without even the implied warranty of        |
00021    |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
00022    |     GNU General Public License for more details.                          |
00023    |                                                                           |
00024    |     You should have received a copy of the GNU General Public License     |
00025    |     along with MRPT.  If not, see <http://www.gnu.org/licenses/>.         |
00026    |                                                                           |
00027    +---------------------------------------------------------------------------+ */
00028 #ifndef CONSTRAINED_POSE_NETWORK_IMPL_H
00029 #define CONSTRAINED_POSE_NETWORK_IMPL_H
00030 
00031 #include <mrpt/graphs/dijkstra.h>
00032 #include <mrpt/utils/CTextFileLinesParser.h>
00033 
00034 
00035 namespace mrpt
00036 {
00037         namespace graphs
00038         {
00039                 namespace detail
00040                 {
00041                         using namespace std;
00042                         using namespace mrpt;
00043                         using namespace mrpt::utils;
00044                         using namespace mrpt::poses;
00045                         using namespace mrpt::graphs;
00046 
00047                         template <class POSE_PDF> struct TPosePDFHelper
00048                         {
00049                                 static inline void copyFrom2D(POSE_PDF &p, const CPosePDFGaussianInf &pdf ) { p.copyFrom( pdf ); }
00050                                 static inline void copyFrom3D(POSE_PDF &p, const CPose3DPDFGaussianInf &pdf ) { p.copyFrom( pdf ); }
00051                         };
00052                         template <> struct TPosePDFHelper<CPose2D>
00053                         {
00054                                 static inline void copyFrom2D(CPose2D &p, const CPosePDFGaussianInf &pdf ) { p = pdf.mean; }
00055                                 static inline void copyFrom3D(CPose2D &p, const CPose3DPDFGaussianInf &pdf ) { p = CPose2D(pdf.mean); }
00056                         };
00057                         template <> struct TPosePDFHelper<CPose3D>
00058                         {
00059                                 static inline void copyFrom2D(CPose3D &p, const CPosePDFGaussianInf &pdf ) { p = pdf.mean; }
00060                                 static inline void copyFrom3D(CPose3D &p, const CPose3DPDFGaussianInf &pdf ) { p = pdf.mean; }
00061                         };
00062 
00063                         /// a helper struct with static template functions \sa CNetworkOfPoses
00064                         template <class graph_t>
00065                         struct graph_ops
00066                         {
00067                                 static void write_VERTEX_line(const TNodeID id, const CPose2D &p, std::ofstream &f)
00068                                 {
00069                                         //  VERTEX2 id x y phi
00070                                         f << "VERTEX2 " << id << format(" %.04f %.04f %.04f\n",p.x(),p.y(),p.phi() );
00071                                 }
00072                                 static void write_VERTEX_line(const TNodeID id, const CPose3D &p, std::ofstream &f)
00073                                 {
00074                                         //  VERTEX3 id x y z roll pitch yaw
00075                                         // **CAUTION** In the TORO graph format angles are in the RPY order vs. MRPT's YPR.
00076                                         f << "VERTEX3 " << id << format(" %.04f %.04f %.04f %.04f %.04f %.04f\n",p.x(),p.y(),p.z(),p.roll(),p.pitch(),p.yaw() );
00077                                 }
00078 
00079 
00080                                 static void write_EDGE_line( const TPairNodeIDs &edgeIDs,const CPosePDFGaussianInf & edge, std::ofstream &f)
00081                                 {
00082                                         //  EDGE2 from_id to_id Ax Ay Aphi inf_xx inf_xy inf_yy inf_pp inf_xp inf_yp
00083                                         // **CAUTION** TORO docs say "from_id" "to_id" in the opposite order, but it seems from the data that this is the correct expected format.
00084                                         f << "EDGE2 " << edgeIDs.first << " " << edgeIDs.second << " " <<
00085                                                 //format(" %.06f %.06f %.06f %e %e %e %e %e %e\n",
00086                                                         edge.mean.x()<<" "<<edge.mean.y()<<" "<<edge.mean.phi()<<" "<<
00087                                                         edge.cov_inv(0,0)<<" "<<edge.cov_inv(0,1)<<" "<<edge.cov_inv(1,1)<<" "<<
00088                                                         edge.cov_inv(2,2)<<" "<<edge.cov_inv(0,2)<<" "<<edge.cov_inv(1,2) << endl;
00089                                 }
00090                                 static void write_EDGE_line( const TPairNodeIDs &edgeIDs,const CPose3DPDFGaussianInf & edge, std::ofstream &f)
00091                                 {
00092                                         //  EDGE3 from_id to_id Ax Ay Az Aroll Apitch Ayaw inf_11 inf_12 .. inf_16 inf_22 .. inf_66
00093                                         // **CAUTION** In the TORO graph format angles are in the RPY order vs. MRPT's YPR.
00094                                         // **CAUTION** TORO docs say "from_id" "to_id" in the opposite order, but it seems from the data that this is the correct expected format.
00095                                         f << "EDGE3 " << edgeIDs.first << " " << edgeIDs.second << " " <<
00096                                                 //format(" %.06f %.06f %.06f %.06f %.06f %.06f %e %e %e %e %e %e %e %e %e %e %e %e %e %e %e %e %e %e %e %e %e\n",
00097                                                         edge.mean.x()<<" "<<edge.mean.y()<<" "<<edge.mean.z()<<" "<<
00098                                                         edge.mean.roll()<<" "<<edge.mean.pitch()<<" "<<edge.mean.yaw()<<" "<<
00099                                                         edge.cov_inv(0,0)<<" "<<edge.cov_inv(0,1)<<" "<<edge.cov_inv(0,2)<<" "<<edge.cov_inv(0,5)<<" "<<edge.cov_inv(0,4)<<" "<<edge.cov_inv(0,3)<<" "<<
00100                                                         edge.cov_inv(1,1)<<" "<<edge.cov_inv(1,2)<<" "<<edge.cov_inv(1,5)<<" "<<edge.cov_inv(1,4)<<" "<<edge.cov_inv(1,3)<<" "<<
00101                                                         edge.cov_inv(2,2)<<" "<<edge.cov_inv(2,5)<<" "<<edge.cov_inv(2,4)<<" "<<edge.cov_inv(2,3)<<" "<<
00102                                                         edge.cov_inv(5,5)<<" "<<edge.cov_inv(5,4)<<" "<<edge.cov_inv(5,3)<<" "<<
00103                                                         edge.cov_inv(4,4)<<" "<<edge.cov_inv(4,3)<<" "<<
00104                                                         edge.cov_inv(3,3) << endl;
00105                                 }
00106                                 static void write_EDGE_line( const TPairNodeIDs &edgeIDs,const CPosePDFGaussian & edge, std::ofstream &f)
00107                                 {
00108                                         CPosePDFGaussianInf p;
00109                                         p.copyFrom(edge);
00110                                         write_EDGE_line(edgeIDs,p,f);
00111                                 }
00112                                 static void write_EDGE_line( const TPairNodeIDs &edgeIDs,const CPose3DPDFGaussian & edge, std::ofstream &f)
00113                                 {
00114                                         CPose3DPDFGaussianInf p;
00115                                         p.copyFrom(edge);
00116                                         write_EDGE_line(edgeIDs,p,f);
00117                                 }
00118                                 static void write_EDGE_line( const TPairNodeIDs &edgeIDs,const CPose2D & edge, std::ofstream &f)
00119                                 {
00120                                         CPosePDFGaussianInf p;
00121                                         p.mean = edge;
00122                                         p.cov_inv.unit(3,1.0);
00123                                         write_EDGE_line(edgeIDs,p,f);
00124                                 }
00125                                 static void write_EDGE_line( const TPairNodeIDs &edgeIDs,const CPose3D & edge, std::ofstream &f)
00126                                 {
00127                                         CPose3DPDFGaussianInf p;
00128                                         p.mean = edge;
00129                                         p.cov_inv.unit(6,1.0);
00130                                         write_EDGE_line(edgeIDs,p,f);
00131                                 }
00132 
00133 
00134                                 // =================================================================
00135                                 //                     save_graph_of_poses_from_text_file
00136                                 // =================================================================
00137                                 static void save_graph_of_poses_from_text_file(const graph_t *g, const std::string &fil)
00138                                 {
00139                                         typedef typename graph_t::constraint_t CPOSE;
00140 
00141                                         std::ofstream  f;
00142                                         f.open(fil.c_str());
00143                                         if (!f.is_open())
00144                                                 THROW_EXCEPTION_CUSTOM_MSG1("Error opening file '%s' for writing",fil.c_str());
00145 
00146                                         // 1st: Nodes
00147                                         for (typename graph_t::global_poses_t::const_iterator itNod = g->nodes.begin();itNod!=g->nodes.end();++itNod)
00148                                                 write_VERTEX_line(itNod->first, itNod->second, f);
00149 
00150                                         // 2nd: Edges:
00151                                         for (typename graph_t::const_iterator it=g->begin();it!=g->end();++it)
00152                                                 if (it->first.first!=it->first.second)  // Ignore self-edges, typically from importing files with EQUIV's
00153                                                         write_EDGE_line( it->first, it->second, f);
00154 
00155                                 } // end save_graph
00156 
00157 
00158                                 // =================================================================
00159                                 //                     load_graph_of_poses_from_text_file
00160                                 // =================================================================
00161                                 static void load_graph_of_poses_from_text_file(graph_t *g, const std::string &fil)
00162                                 {
00163                                         typedef typename graph_t::constraint_t CPOSE;
00164 
00165                                         set<string>  alreadyWarnedUnknowns; // for unknown line types, show a warning to cerr just once.
00166 
00167                                         // First, empty the graph:
00168                                         g->clear();
00169 
00170                                         // Determine if it's a 2D or 3D graph, just to raise an error if loading a 3D graph in a 2D one, since
00171                                         //  it would be an unintentional loss of information:
00172                                         const bool graph_is_3D = CPOSE::is_3D();
00173 
00174                                         CTextFileLinesParser   filParser(fil);  // raises an exception on error
00175 
00176                                         // -------------------------------------------
00177                                         // 1st PASS: Read EQUIV entries only
00178                                         //  since processing them AFTER loading the data
00179                                         //  is much much slower.
00180                                         // -------------------------------------------
00181                                         map<TNodeID,TNodeID> lstEquivs; // List of EQUIV entries: NODEID -> NEWNODEID. NEWNODEID will be always the lowest ID number.
00182 
00183                                         // Read & process lines each at once until EOF:
00184                                         istringstream s;
00185                                         while (filParser.getNextLine(s))
00186                                         {
00187                                                 const unsigned int lineNum = filParser.getCurrentLineNumber();
00188                                                 const string lin = s.str();
00189 
00190                                                 string key;
00191                                                 if ( !(s >> key) || key.empty() )
00192                                                         THROW_EXCEPTION(format("Line %u: Can't read string for entry type in: '%s'", lineNum, lin.c_str() ) );
00193 
00194                                                 if ( strCmpI(key,"EQUIV") )
00195                                                 {
00196                                                         // Process these ones at the end, for now store in a list:
00197                                                         TNodeID  id1,id2;
00198                                                         if (!(s>> id1 >> id2))
00199                                                                 THROW_EXCEPTION(format("Line %u: Can't read id1 & id2 in EQUIV line: '%s'", lineNum, lin.c_str() ) );
00200                                                         lstEquivs[std::max(id1,id2)] = std::min(id1,id2);
00201                                                 }
00202                                         } // end 1st pass
00203 
00204                                         // -------------------------------------------
00205                                         // 2nd PASS: Read all other entries
00206                                         // -------------------------------------------
00207                                         filParser.rewind();
00208 
00209                                         // Read & process lines each at once until EOF:
00210                                         while (filParser.getNextLine(s))
00211                                         {
00212                                                 const unsigned int lineNum = filParser.getCurrentLineNumber();
00213                                                 const string lin = s.str();
00214 
00215                                                 // Recognized strings:
00216                                                 //  VERTEX2 id x y phi
00217                                                 //  EDGE2 from_id to_id Ax Ay Aphi inf_xx inf_xy inf_yy inf_pp inf_xp inf_yp
00218                                                 //  VERTEX3 id x y z roll pitch yaw
00219                                                 //  EDGE3 from_id to_id Ax Ay Az Aroll Apitch Ayaw inf_11 inf_12 .. inf_16 inf_22 .. inf_66
00220                                                 //  EQUIV id1 id2
00221                                                 string key;
00222                                                 if ( !(s >> key) || key.empty() )
00223                                                         THROW_EXCEPTION(format("Line %u: Can't read string for entry type in: '%s'", lineNum, lin.c_str() ) );
00224 
00225                                                 if ( strCmpI(key,"VERTEX2") )
00226                                                 {
00227                                                         TNodeID  id;
00228                                                         TPose2D  p2D;
00229                                                         if (!(s>> id >> p2D.x >> p2D.y >> p2D.phi))
00230                                                                 THROW_EXCEPTION(format("Line %u: Error parsing VERTEX2 line: '%s'", lineNum, lin.c_str() ) );
00231 
00232                                                         // Make sure the node is new:
00233                                                         if (g->nodes.find(id)!=g->nodes.end())
00234                                                                 THROW_EXCEPTION(format("Line %u: Error, duplicated verted ID %u in line: '%s'", lineNum, static_cast<unsigned int>(id), lin.c_str() ) );
00235 
00236                                                         // EQUIV? Replace ID by new one.
00237                                                         {
00238                                                                 const map<TNodeID,TNodeID>::const_iterator itEq = lstEquivs.find(id);
00239                                                                 if (itEq!=lstEquivs.end()) id = itEq->second;
00240                                                         }
00241 
00242                                                         // Add to map: ID -> absolute pose:
00243                                                         if (g->nodes.find(id)==g->nodes.end())
00244                                                         {
00245                                                                 typename CNetworkOfPoses<CPOSE>::constraint_t::type_value & newNode = g->nodes[id];
00246                                                                 newNode = CPose2D(p2D); // Auto converted to CPose3D if needed
00247                                                         }
00248                                                 }
00249                                                 else if ( strCmpI(key,"VERTEX3") )
00250                                                 {
00251                                                         if (!graph_is_3D)
00252                                                                 THROW_EXCEPTION(format("Line %u: Try to load VERTEX3 into a 2D graph: '%s'", lineNum, lin.c_str() ) );
00253 
00254                                                         //  VERTEX3 id x y z roll pitch yaw
00255                                                         TNodeID  id;
00256                                                         TPose3D  p3D;
00257                                                         // **CAUTION** In the TORO graph format angles are in the RPY order vs. MRPT's YPR.
00258                                                         if (!(s>> id >> p3D.x >> p3D.y >> p3D.z >> p3D.roll >> p3D.pitch >> p3D.yaw ))
00259                                                                 THROW_EXCEPTION(format("Line %u: Error parsing VERTEX3 line: '%s'", lineNum, lin.c_str() ) );
00260 
00261                                                         // Make sure the node is new:
00262                                                         if (g->nodes.find(id)!=g->nodes.end())
00263                                                                 THROW_EXCEPTION(format("Line %u: Error, duplicated verted ID %u in line: '%s'", lineNum, static_cast<unsigned int>(id), lin.c_str() ) );
00264 
00265                                                         // EQUIV? Replace ID by new one.
00266                                                         {
00267                                                                 const map<TNodeID,TNodeID>::const_iterator itEq = lstEquivs.find(id);
00268                                                                 if (itEq!=lstEquivs.end()) id = itEq->second;
00269                                                         }
00270 
00271                                                         // Add to map: ID -> absolute pose:
00272                                                         if (g->nodes.find(id)==g->nodes.end())
00273                                                         {
00274                                                                 g->nodes[id] = typename CNetworkOfPoses<CPOSE>::constraint_t::type_value( CPose3D(p3D) ); // Auto converted to CPose2D if needed
00275                                                         }
00276                                                 }
00277                                                 else if ( strCmpI(key,"EDGE2") )
00278                                                 {
00279                                                         //  EDGE2 from_id to_id Ax Ay Aphi inf_xx inf_xy inf_yy inf_pp inf_xp inf_yp
00280                                                         //                                   s00   s01     s11    s22    s02    s12
00281                                                         //  Read values are:
00282                                                         //    [ s00 s01 s02 ]
00283                                                         //    [  -  s11 s12 ]
00284                                                         //    [  -   -  s22 ]
00285                                                         //
00286                                                         TNodeID  to_id, from_id;
00287                                                         if (!(s>> from_id >> to_id ))
00288                                                                 THROW_EXCEPTION(format("Line %u: Error parsing EDGE2 line: '%s'", lineNum, lin.c_str() ) );
00289 
00290                                                         // EQUIV? Replace ID by new one.
00291                                                         {
00292                                                                 const map<TNodeID,TNodeID>::const_iterator itEq = lstEquivs.find(to_id);
00293                                                                 if (itEq!=lstEquivs.end()) to_id = itEq->second;
00294                                                         }
00295                                                         {
00296                                                                 const map<TNodeID,TNodeID>::const_iterator itEq = lstEquivs.find(from_id);
00297                                                                 if (itEq!=lstEquivs.end()) from_id = itEq->second;
00298                                                         }
00299 
00300                                                         if (from_id!=to_id)     // Don't load self-edges! (probably come from an EQUIV)
00301                                                         {
00302                                                                 TPose2D  Ap_mean;
00303                                                                 CMatrixDouble33 Ap_cov_inv;
00304                                                                 if (!(s>>
00305                                                                                 Ap_mean.x >> Ap_mean.y >> Ap_mean.phi >>
00306                                                                                 Ap_cov_inv(0,0) >> Ap_cov_inv(0,1) >> Ap_cov_inv(1,1) >>
00307                                                                                 Ap_cov_inv(2,2) >> Ap_cov_inv(0,2) >> Ap_cov_inv(1,2) ))
00308                                                                         THROW_EXCEPTION(format("Line %u: Error parsing EDGE2 line: '%s'", lineNum, lin.c_str() ) );
00309 
00310                                                                 // Complete low triangular part of inf matrix:
00311                                                                 Ap_cov_inv(1,0) = Ap_cov_inv(0,1);
00312                                                                 Ap_cov_inv(2,0) = Ap_cov_inv(0,2);
00313                                                                 Ap_cov_inv(2,1) = Ap_cov_inv(1,2);
00314 
00315                                                                 // Convert to 2D cov, 3D cov or 3D inv_cov as needed:
00316                                                                 typename CNetworkOfPoses<CPOSE>::edge_t  newEdge;
00317                                                                 TPosePDFHelper<CPOSE>::copyFrom2D(newEdge, CPosePDFGaussianInf( CPose2D(Ap_mean), Ap_cov_inv ) );
00318                                                                 g->insertEdge(from_id, to_id, newEdge);
00319                                                         }
00320                                                 }
00321                                                 else if ( strCmpI(key,"EDGE3") )
00322                                                 {
00323                                                         if (!graph_is_3D)
00324                                                                 THROW_EXCEPTION(format("Line %u: Try to load EDGE3 into a 2D graph: '%s'", lineNum, lin.c_str() ) );
00325 
00326                                                         //  EDGE3 from_id to_id Ax Ay Az Aroll Apitch Ayaw inf_11 inf_12 .. inf_16 inf_22 .. inf_66
00327                                                         TNodeID  to_id, from_id;
00328                                                         if (!(s>> from_id >> to_id ))
00329                                                                 THROW_EXCEPTION(format("Line %u: Error parsing EDGE3 line: '%s'", lineNum, lin.c_str() ) );
00330 
00331                                                         // EQUIV? Replace ID by new one.
00332                                                         {
00333                                                                 const map<TNodeID,TNodeID>::const_iterator itEq = lstEquivs.find(to_id);
00334                                                                 if (itEq!=lstEquivs.end()) to_id = itEq->second;
00335                                                         }
00336                                                         {
00337                                                                 const map<TNodeID,TNodeID>::const_iterator itEq = lstEquivs.find(from_id);
00338                                                                 if (itEq!=lstEquivs.end()) from_id = itEq->second;
00339                                                         }
00340 
00341                                                         if (from_id!=to_id)     // Don't load self-edges! (probably come from an EQUIV)
00342                                                         {
00343                                                                 TPose3D  Ap_mean;
00344                                                                 CMatrixDouble66 Ap_cov_inv;
00345                                                                 // **CAUTION** In the TORO graph format angles are in the RPY order vs. MRPT's YPR.
00346                                                                 if (!(s>> Ap_mean.x >> Ap_mean.y >> Ap_mean.z >> Ap_mean.roll >> Ap_mean.pitch >> Ap_mean.yaw ))
00347                                                                         THROW_EXCEPTION(format("Line %u: Error parsing EDGE3 line: '%s'", lineNum, lin.c_str() ) );
00348 
00349                                                                 // **CAUTION** Indices are shuffled to the change YAW(3) <-> ROLL(5) in the order of the data.
00350                                                                 if (!(s>>
00351                                                                                 Ap_cov_inv(0,0) >> Ap_cov_inv(0,1) >> Ap_cov_inv(0,2) >> Ap_cov_inv(0,5) >> Ap_cov_inv(0,4) >> Ap_cov_inv(0,3) >>
00352                                                                                 Ap_cov_inv(1,1) >> Ap_cov_inv(1,2) >> Ap_cov_inv(1,5) >> Ap_cov_inv(1,4) >> Ap_cov_inv(1,3) >>
00353                                                                                 Ap_cov_inv(2,2) >> Ap_cov_inv(2,5) >> Ap_cov_inv(2,4) >> Ap_cov_inv(2,3) >>
00354                                                                                 Ap_cov_inv(5,5) >> Ap_cov_inv(5,4) >> Ap_cov_inv(5,3) >>
00355                                                                                 Ap_cov_inv(4,4) >> Ap_cov_inv(4,3) >>
00356                                                                                 Ap_cov_inv(3,3) ))
00357                                                                 {
00358                                                                         // Cov may be omitted in the file:
00359                                                                         Ap_cov_inv.unit(6,1.0);
00360 
00361                                                                         if (alreadyWarnedUnknowns.find("MISSING_3D")==alreadyWarnedUnknowns.end())
00362                                                                         {
00363                                                                                 alreadyWarnedUnknowns.insert("MISSING_3D");
00364                                                                                 cerr << "[CNetworkOfPoses::loadFromTextFile] " << fil << ":" << lineNum << ": Warning: Information matrix missing, assuming unity.\n";
00365                                                                         }
00366                                                                 }
00367                                                                 else
00368                                                                 {
00369                                                                         // Complete low triangular part of inf matrix:
00370                                                                         for (size_t r=1;r<6;r++)
00371                                                                                 for (size_t c=0;c<r;c++)
00372                                                                                         Ap_cov_inv(r,c) = Ap_cov_inv(c,r);
00373                                                                 }
00374 
00375                                                                 // Convert as needed:
00376                                                                 typename CNetworkOfPoses<CPOSE>::edge_t  newEdge;
00377                                                                 TPosePDFHelper<CPOSE>::copyFrom3D(newEdge, CPose3DPDFGaussianInf( CPose3D(Ap_mean), Ap_cov_inv ) );
00378                                                                 g->insertEdge(from_id, to_id, newEdge);
00379                                                         }
00380                                                 }
00381                                                 else if ( strCmpI(key,"EQUIV") )
00382                                                 {
00383                                                         // Already read in the 1st pass.
00384                                                 }
00385                                                 else
00386                                                 {       // Unknown entry: Warn the user just once:
00387                                                         if (alreadyWarnedUnknowns.find(key)==alreadyWarnedUnknowns.end())
00388                                                         {
00389                                                                 alreadyWarnedUnknowns.insert(key);
00390                                                                 cerr << "[CNetworkOfPoses::loadFromTextFile] " << fil << ":" << lineNum << ": Warning: unknown entry type: " << key << endl;
00391                                                         }
00392                                                 }
00393                                         } // end while
00394 
00395                                 } // end load_graph
00396 
00397 
00398                                 // --------------------------------------------------------------------------------
00399                                 //               Implements: collapseDuplicatedEdges
00400                                 //
00401                                 // Look for duplicated edges (even in opposite directions) between all pairs of nodes and fuse them.
00402                                 //  Upon return, only one edge remains between each pair of nodes with the mean
00403                                 //   & covariance (or information matrix) corresponding to the Bayesian fusion of all the Gaussians.
00404                                 // --------------------------------------------------------------------------------
00405                                 static size_t graph_of_poses_collapse_dup_edges(graph_t *g)
00406                                 {
00407                                         MRPT_START
00408                                         typedef typename graph_t::edges_map_t::iterator TEdgeIterator;
00409 
00410                                         // Data structure: (id1,id2) -> all edges between them
00411                                         //  (with id1 < id2)
00412                                         typedef map<pair<TNodeID,TNodeID>, vector<TEdgeIterator> > TListAllEdges; // For god's sake... when will ALL compilers support auto!! :'-(
00413                                         TListAllEdges lstAllEdges;
00414 
00415                                         // Clasify all edges to identify duplicated ones:
00416                                         for (TEdgeIterator itEd=g->edges.begin();itEd!=g->edges.end();++itEd)
00417                                         {
00418                                                 // Build a pair <id1,id2> with id1 < id2:
00419                                                 const pair<TNodeID,TNodeID> arc_id = make_pair( std::min(itEd->first.first,itEd->first.second),std::max(itEd->first.first,itEd->first.second) );
00420                                                 // get (or create the first time) the list of edges between them:
00421                                                 vector<TEdgeIterator> &lstEdges = lstAllEdges[arc_id];
00422                                                 // And add this one:
00423                                                 lstEdges.push_back(itEd);
00424                                         }
00425 
00426                                         // Now, remove all but the first edge:
00427                                         size_t  nRemoved = 0;
00428                                         for (typename TListAllEdges::const_iterator it=lstAllEdges.begin();it!=lstAllEdges.end();++it)
00429                                         {
00430                                                 const size_t N = it->second.size();
00431                                                 for (size_t i=1;i<N;i++)  // i=0 is NOT removed
00432                                                         g->edges.erase( it->second[i] );
00433 
00434                                                 if (N>=2) nRemoved+=N-1;
00435                                         }
00436 
00437                                         return nRemoved;
00438                                         MRPT_END
00439                                 } // end of graph_of_poses_collapse_dup_edges
00440 
00441                                 // --------------------------------------------------------------------------------
00442                                 //               Implements: dijkstra_nodes_estimate
00443                                 //
00444                                 //      Compute a simple estimation of the global coordinates of each node just from the information in all edges, sorted in a Dijkstra tree based on the current "root" node.
00445                                 //      Note that "global" coordinates are with respect to the node with the ID specified in \a root.
00446                                 // --------------------------------------------------------------------------------
00447                                 static void graph_of_poses_dijkstra_init(graph_t *g)
00448                                 {
00449                                         MRPT_START
00450 
00451                                         // Do Dijkstra shortest path from "root" to all other nodes:
00452                                         typedef CDijkstra<graph_t,typename graph_t::maps_implementation_t> dijkstra_t;
00453                                         typedef typename graph_t::constraint_t  constraint_t;
00454 
00455                                         dijkstra_t dijkstra(*g, g->root);
00456 
00457                                         // Get the tree representation of the graph and traverse it
00458                                         //  from its root toward the leafs:
00459                                         typename dijkstra_t::tree_graph_t  treeView;
00460                                         dijkstra.getTreeGraph(treeView);
00461 
00462                                         // This visitor class performs the real job of
00463                                         struct VisitorComputePoses : public dijkstra_t::tree_graph_t::Visitor
00464                                         {
00465                                                 graph_t * m_g; // The original graph
00466 
00467                                                 VisitorComputePoses(graph_t *g) : m_g(g) { }
00468                                                 virtual void OnVisitNode( const TNodeID parent_id, const typename dijkstra_t::tree_graph_t::Visitor::tree_t::TEdgeInfo &edge_to_child, const size_t depth_level )
00469                                                 {
00470                                                         const TNodeID  child_id = edge_to_child.id;
00471 
00472                                                         // Compute the pose of "child_id" as parent_pose (+) edge_delta_pose,
00473                                                         //  taking into account that that edge may be in reverse order and then have to invert the delta_pose:
00474                                                         if ( (!edge_to_child.reverse && !m_g->edges_store_inverse_poses) ||
00475                                                                  ( edge_to_child.reverse &&  m_g->edges_store_inverse_poses)
00476                                                                 )
00477                                                         {       // pose_child = p_parent (+) p_delta
00478                                                                 m_g->nodes[child_id].composeFrom( m_g->nodes[parent_id],  edge_to_child.data->getPoseMean() );
00479                                                         }
00480                                                         else
00481                                                         {       // pose_child = p_parent (+) [(-)p_delta]
00482                                                                 m_g->nodes[child_id].composeFrom( m_g->nodes[parent_id], - edge_to_child.data->getPoseMean() );
00483                                                         }
00484                                                 }
00485                                         };
00486 
00487                                         // Remove all global poses but for the root node, which is the origin:
00488                                         g->nodes.clear();
00489                                         g->nodes[g->root] = typename constraint_t::type_value();  // Typ: CPose2D() or CPose3D()
00490 
00491                                         // Run the visit thru all nodes in the tree:
00492                                         VisitorComputePoses  myVisitor(g);
00493                                         treeView.visitBreadthFirst(treeView.root, myVisitor);
00494 
00495                                         MRPT_END
00496                                 }
00497 
00498 
00499                                 // Auxiliary funcs:
00500                                 template <class VEC> static inline double auxMaha2Dist(VEC &err,const CPosePDFGaussianInf &p) {
00501                                         math::wrapToPiInPlace(err[2]);
00502                                         return mrpt::math::multiply_HCHt_scalar(err,p.cov_inv); // err^t*cov_inv*err
00503                                 }
00504                                 template <class VEC> static inline double auxMaha2Dist(VEC &err,const CPose3DPDFGaussianInf &p) {
00505                                         math::wrapToPiInPlace(err[3]);
00506                                         math::wrapToPiInPlace(err[4]);
00507                                         math::wrapToPiInPlace(err[5]);
00508                                         return mrpt::math::multiply_HCHt_scalar(err,p.cov_inv); // err^t*cov_inv*err
00509                                 }
00510                                 template <class VEC> static inline double auxMaha2Dist(VEC &err,const CPosePDFGaussian &p) {
00511                                         math::wrapToPiInPlace(err[2]);
00512                                         CMatrixDouble33  COV_INV(UNINITIALIZED_MATRIX);
00513                                         p.cov.inv(COV_INV);
00514                                         return mrpt::math::multiply_HCHt_scalar(err,COV_INV); // err^t*cov_inv*err
00515                                 }
00516                                 template <class VEC> static inline double auxMaha2Dist(VEC &err,const CPose3DPDFGaussian &p) {
00517                                         math::wrapToPiInPlace(err[3]);
00518                                         math::wrapToPiInPlace(err[4]);
00519                                         math::wrapToPiInPlace(err[5]);
00520                                         CMatrixDouble66 COV_INV(UNINITIALIZED_MATRIX);
00521                                         p.cov.inv(COV_INV);
00522                                         return mrpt::math::multiply_HCHt_scalar(err,COV_INV); // err^t*cov_inv*err
00523                                 }
00524                                 // These two are for simulating maha2 distances for non-PDF types: fallback to squared-norm:
00525                                 template <class VEC> static inline double auxMaha2Dist(VEC &err,const CPose2D &p) {
00526                                         math::wrapToPiInPlace(err[2]);
00527                                         return square(err[0])+square(err[1])+square(err[2]);
00528                                 }
00529                                 template <class VEC> static inline double auxMaha2Dist(VEC &err,const CPose3D &p) {
00530                                         math::wrapToPiInPlace(err[3]);
00531                                         math::wrapToPiInPlace(err[4]);
00532                                         math::wrapToPiInPlace(err[5]);
00533                                         return square(err[0])+square(err[1])+square(err[2])+square(err[3])+square(err[4])+square(err[5]);
00534                                 }
00535 
00536 
00537                                 static inline double auxEuclid2Dist(const CPose2D &p1,const CPose2D &p2) {
00538                                         return
00539                                                 square(p1.x()-p2.x())+
00540                                                 square(p1.y()-p2.y())+
00541                                                 square( mrpt::math::wrapToPi(p1.phi()-p2.phi() ) );
00542                                 }
00543                                 static inline double auxEuclid2Dist(const CPose3D &p1,const CPose3D &p2) {
00544                                         return
00545                                                 square(p1.x()-p2.x())+
00546                                                 square(p1.y()-p2.y())+
00547                                                 square(p1.z()-p2.z())+
00548                                                 square( mrpt::math::wrapToPi(p1.yaw()-p2.yaw() ) )+
00549                                                 square( mrpt::math::wrapToPi(p1.pitch()-p2.pitch() ) )+
00550                                                 square( mrpt::math::wrapToPi(p1.roll()-p2.roll() ) );
00551                                 }
00552 
00553                                 // --------------------------------------------------------------------------------
00554                                 //               Implements: detail::graph_edge_sqerror
00555                                 //
00556                                 //      Compute the square error of a single edge, in comparison to the nodes global poses.
00557                                 // --------------------------------------------------------------------------------
00558                                 static double graph_edge_sqerror(
00559                                         const graph_t *g,
00560                                         const typename mrpt::graphs::CDirectedGraph<typename graph_t::constraint_t>::edges_map_t::const_iterator &itEdge,
00561                                         bool ignoreCovariances )
00562                                 {
00563                                         MRPT_START
00564 
00565                                         // Get node IDs:
00566                                         const TNodeID from_id = itEdge->first.first;
00567                                         const TNodeID to_id   = itEdge->first.second;
00568 
00569                                         // And their global poses as stored in "nodes"
00570                                         typename graph_t::global_poses_t::const_iterator itPoseFrom = g->nodes.find(from_id);
00571                                         typename graph_t::global_poses_t::const_iterator itPoseTo   = g->nodes.find(to_id);
00572                                         ASSERTMSG_(itPoseFrom!=g->nodes.end(), format("Node %u doesn't have a global pose in 'nodes'.", static_cast<unsigned int>(from_id)))
00573                                         ASSERTMSG_(itPoseTo!=g->nodes.end(), format("Node %u doesn't have a global pose in 'nodes'.", static_cast<unsigned int>(to_id)))
00574 
00575                                         // The global poses:
00576                                         typedef typename graph_t::constraint_t constraint_t;
00577 
00578                                         const typename constraint_t::type_value &from_mean = itPoseFrom->second;
00579                                         const typename constraint_t::type_value &to_mean   = itPoseTo->second;
00580 
00581                                         // The delta_pose as stored in the edge:
00582                                         const constraint_t &edge_delta_pose = itEdge->second;
00583                                         const typename constraint_t::type_value &edge_delta_pose_mean = edge_delta_pose.getPoseMean();
00584 
00585                                         if (ignoreCovariances)
00586                                         {       // Square Euclidean distance: Just use the mean values, ignore covs.
00587                                                 // from_plus_delta = from_mean (+) edge_delta_pose_mean
00588                                                 typename constraint_t::type_value from_plus_delta(UNINITIALIZED_POSE);
00589                                                 from_plus_delta.composeFrom(from_mean, edge_delta_pose_mean);
00590 
00591                                                 // (auxMaha2Dist will also take into account the 2PI wrapping)
00592                                                 return auxEuclid2Dist(from_plus_delta,to_mean);
00593                                         }
00594                                         else
00595                                         {
00596                                                 // Square Mahalanobis distance
00597                                                 // from_plus_delta = from_mean (+) edge_delta_pose (as a Gaussian)
00598                                                 constraint_t from_plus_delta = edge_delta_pose;
00599                                                 from_plus_delta.changeCoordinatesReference(from_mean);
00600 
00601                                                 // "from_plus_delta" is now a 3D or 6D Gaussian, to be compared to "to_mean":
00602                                                 //  We want to compute the squared Mahalanobis distance:
00603                                                 //       err^t * INV_COV * err
00604                                                 //
00605                                                 CArrayDouble<constraint_t::type_value::static_size> err;
00606                                                 for (size_t i=0;i<constraint_t::type_value::static_size;i++)
00607                                                         err[i] = from_plus_delta.getPoseMean()[i] - to_mean[i];
00608 
00609                                                 // (auxMaha2Dist will also take into account the 2PI wrapping)
00610                                                 return auxMaha2Dist(err,from_plus_delta);
00611                                         }
00612                                         MRPT_END
00613                                 }
00614 
00615                         }; // end of graph_ops<graph_t>
00616 
00617                 }// end NS
00618         }// end NS
00619 } // end NS
00620 
00621 #endif



Page generated by Doxygen 1.7.5 for MRPT 0.9.5 SVN: at Thu Oct 13 21:25:36 UTC 2011