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



Page generated by Doxygen 1.7.4 for MRPT 0.9.5 SVN:2717 at Sun Oct 16 16:08:03 PDT 2011 Hosted on:
SourceForge.net Logo