Graph.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions are met:
00007     * Redistributions of source code must retain the above copyright
00008       notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright
00010       notice, this list of conditions and the following disclaimer in the
00011       documentation and/or other materials provided with the distribution.
00012     * Neither the name of the Universite de Sherbrooke nor the
00013       names of its contributors may be used to endorse or promote products
00014       derived from this software without specific prior written permission.
00015 
00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
00020 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 */
00027 #include "rtabmap/core/Graph.h"
00028 
00029 #include <rtabmap/utilite/ULogger.h>
00030 #include <rtabmap/utilite/UStl.h>
00031 #include <rtabmap/utilite/UMath.h>
00032 #include <rtabmap/utilite/UConversion.h>
00033 #include <rtabmap/utilite/UTimer.h>
00034 #include <rtabmap/utilite/UFile.h>
00035 #include <rtabmap/core/GeodeticCoords.h>
00036 #include <rtabmap/core/Memory.h>
00037 #include <rtabmap/core/util3d_filtering.h>
00038 #include <pcl/search/kdtree.h>
00039 #include <pcl/common/eigen.h>
00040 #include <pcl/common/common.h>
00041 #include <set>
00042 #include <queue>
00043 #include <fstream>
00044 
00045 #include <rtabmap/core/OptimizerTORO.h>
00046 #include <rtabmap/core/OptimizerG2O.h>
00047 
00048 namespace rtabmap {
00049 
00050 namespace graph {
00051 
00052 bool exportPoses(
00053                 const std::string & filePath,
00054                 int format, // 0=Raw, 1=RGBD-SLAM, 2=KITTI, 3=TORO, 4=g2o
00055                 const std::map<int, Transform> & poses,
00056                 const std::multimap<int, Link> & constraints, // required for formats 3 and 4
00057                 const std::map<int, double> & stamps, // required for format 1
00058                 bool g2oRobust) // optional for format 4
00059 {
00060         UDEBUG("%s", filePath.c_str());
00061         std::string tmpPath = filePath;
00062         if(format==3) // TORO
00063         {
00064                 if(UFile::getExtension(tmpPath).empty())
00065                 {
00066                         tmpPath+=".graph";
00067                 }
00068                 return OptimizerTORO::saveGraph(tmpPath, poses, constraints);
00069         }
00070         else if(format == 4) // g2o
00071         {
00072                 if(UFile::getExtension(tmpPath).empty())
00073                 {
00074                         tmpPath+=".g2o";
00075                 }
00076 #ifdef WITH_G2O
00077                 return OptimizerG2O::saveGraph(tmpPath, poses, constraints, g2oRobust);
00078 #else
00079                 UERROR("Cannot export in g2o format because RTAB-Map is not built with g2o support!");
00080                 return false;
00081 #endif
00082         }
00083         else
00084         {
00085                 if(UFile::getExtension(tmpPath).empty())
00086                 {
00087                         tmpPath+=".txt";
00088                 }
00089 
00090                 if(format == 1)
00091                 {
00092                         if(stamps.size() != poses.size())
00093                         {
00094                                 UERROR("When exporting poses to format 1 (RGBD-SLAM), stamps and poses maps should have the same size!");
00095                                 return false;
00096                         }
00097                 }
00098 
00099                 FILE* fout = 0;
00100 #ifdef _MSC_VER
00101                 fopen_s(&fout, tmpPath.c_str(), "w");
00102 #else
00103                 fout = fopen(tmpPath.c_str(), "w");
00104 #endif
00105                 if(fout)
00106                 {
00107                         for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
00108                         {
00109                                 if(format == 1) // rgbd-slam format
00110                                 {
00111                                         // put the pose in rgbd-slam world reference
00112                                         Transform t( 0, 0, 1, 0,
00113                                                                  0, -1, 0, 0,
00114                                                                  1, 0, 0, 0);
00115                                         Transform pose = t.inverse() * iter->second;
00116                                         t = Transform( 0, 0, 1, 0,
00117                                                                   -1, 0, 0, 0,
00118                                                                    0,-1, 0, 0);
00119                                         pose = t.inverse() * pose * t;
00120 
00121                                         // Format: stamp x y z qx qy qz qw
00122                                         Eigen::Quaternionf q = pose.getQuaternionf();
00123 
00124                                         UASSERT(uContains(stamps, iter->first));
00125                                         fprintf(fout, "%f %f %f %f %f %f %f %f\n",
00126                                                         stamps.at(iter->first),
00127                                                         pose.x(),
00128                                                         pose.y(),
00129                                                         pose.z(),
00130                                                         q.x(),
00131                                                         q.y(),
00132                                                         q.z(),
00133                                                         q.w());
00134                                 }
00135                                 else // default / KITTI format
00136                                 {
00137                                         Transform pose = iter->second;
00138                                         if(format == 2)
00139                                         {
00140                                                 // for KITTI, we need to remove optical rotation
00141                                                 // z pointing front, x left, y down
00142                                                 Transform t( 0, 0, 1, 0,
00143                                                                         -1, 0, 0, 0,
00144                                                                          0,-1, 0, 0);
00145                                                 pose = t.inverse() * pose * t;
00146                                         }
00147 
00148                                         // Format: r11 r12 r13 tx r21 r22 r23 ty r31 r32 r33 tz
00149                                         const float * p = (const float *)pose.data();
00150 
00151                                         fprintf(fout, "%f", p[0]);
00152                                         for(int i=1; i<pose.size(); i++)
00153                                         {
00154                                                 fprintf(fout, " %f", p[i]);
00155                                         }
00156                                         fprintf(fout, "\n");
00157                                 }
00158                         }
00159                         fclose(fout);
00160                         return true;
00161                 }
00162         }
00163         return false;
00164 }
00165 
00166 bool importPoses(
00167                 const std::string & filePath,
00168                 int format, // 0=Raw, 1=RGBD-SLAM, 2=KITTI, 3=TORO, 4=g2o, 5=NewCollege(t,x,y), 6=Malaga Urban GPS, 7=St Lucia INS, 8=Karlsruhe
00169                 std::map<int, Transform> & poses,
00170                 std::multimap<int, Link> * constraints, // optional for formats 3 and 4
00171                 std::map<int, double> * stamps) // optional for format 1
00172 {
00173         UDEBUG("%s format=%d", filePath.c_str(), format);
00174         if(format==3) // TORO
00175         {
00176                 std::multimap<int, Link> constraintsTmp;
00177                 if(OptimizerTORO::loadGraph(filePath, poses, constraintsTmp))
00178                 {
00179                         if(constraints)
00180                         {
00181                                 *constraints = constraintsTmp;
00182                         }
00183                         return true;
00184                 }
00185                 return false;
00186         }
00187         else if(format == 4) // g2o
00188         {
00189                 std::multimap<int, Link> constraintsTmp;
00190                 UERROR("Cannot import from g2o format because it is not yet supported!");
00191                 return false;
00192         }
00193         else
00194         {
00195                 std::ifstream file;
00196                 file.open(filePath.c_str(), std::ifstream::in);
00197                 if(!file.good())
00198                 {
00199                         return false;
00200                 }
00201                 int id=1;
00202                 GeodeticCoords origin;
00203                 Transform originPose;
00204                 while(file.good())
00205                 {
00206                         std::string str;
00207                         std::getline(file, str);
00208 
00209                         if(str.empty() || str.at(0) == '#' || str.at(0) == '%')
00210                         {
00211                                 continue;
00212                         }
00213 
00214                         if(format == 8) // Karlsruhe format
00215                         {
00216                                 std::vector<std::string> strList = uListToVector(uSplit(str));
00217                                 if(strList.size() ==  10)
00218                                 {
00219                                         // timestamp,lat,lon,alt,x,y,z,roll,pitch,yaw
00220 
00221                                         // stamp is 1252400096825289728, transform to 1252400096.825289728
00222                                         double stamp = uStr2Double(strList[0].insert(10, 1, '.'));
00223                                         double x = uStr2Double(strList[4]);
00224                                         double y = uStr2Double(strList[5]);
00225                                         double z = uStr2Double(strList[6]);
00226                                         double roll = uStr2Double(strList[8]);
00227                                         double pitch = uStr2Double(strList[7]);
00228                                         double yaw = -(uStr2Double(strList[9])-M_PI_2);
00229                                         if(stamps)
00230                                         {
00231                                                 stamps->insert(std::make_pair(id, stamp));
00232                                         }
00233                                         Transform pose = Transform(x,y,z,roll,pitch,yaw);
00234                                         if(poses.size() == 0)
00235                                         {
00236                                                 originPose = pose.inverse();
00237                                         }
00238                                         pose = originPose * pose; // transform in local coordinate where first value is the origin
00239                                         poses.insert(std::make_pair(id, pose));
00240                                 }
00241                                 else
00242                                 {
00243                                         UERROR("Error parsing \"%s\" with Karlsruhe format (should have 10 values)", str.c_str());
00244                                 }
00245                         }
00246                         else if(format == 7) // St Lucia format
00247                         {
00248                                 std::vector<std::string> strList = uListToVector(uSplit(str));
00249                                 if(strList.size() ==  12)
00250                                 {
00251                                         // Data Type
00252                                         //0=Timestamp (seconds)
00253                                         //1=Timestamp (millisec)
00254                                         //2=Latitude (deg)
00255                                         //3=Longitude (deg)
00256                                         //4=Altitude (m)
00257                                         //5=Height AMSL (m)
00258                                         //6=vENU X
00259                                         //7=vENU Y
00260                                         //8=vENU Z
00261                                         //9=Roll (rad)
00262                                         //10=Pitch (rad)
00263                                         //11=Yaw (rad)
00264 
00265                                         // the millisec str needs 0-padding if size < 6
00266                                         std::string millisecStr = strList[1];
00267                                         while(millisecStr.size() < 6)
00268                                         {
00269                                                 millisecStr = "0" + millisecStr;
00270                                         }
00271                                         double stamp = uStr2Double(strList[0] + "." + millisecStr);
00272 
00273                                         // conversion GPS to local coordinate XYZ
00274                                         double longitude = uStr2Double(strList[2]);
00275                                         double latitude = uStr2Double(strList[3]);
00276                                         double altitude = uStr2Double(strList[4]);
00277                                         if(poses.empty())
00278                                         {
00279                                                 origin = GeodeticCoords(longitude, latitude, altitude);
00280                                         }
00281                                         cv::Point3d coordENU = GeodeticCoords(longitude, latitude, altitude).toENU_WGS84(origin);
00282                                         double roll = uStr2Double(strList[10]);
00283                                         double pitch = uStr2Double(strList[9]);
00284                                         double yaw = -(uStr2Double(strList[11])-M_PI_2);
00285                                         if(stamps)
00286                                         {
00287                                                 stamps->insert(std::make_pair(id, stamp));
00288                                         }
00289                                         poses.insert(std::make_pair(id, Transform(coordENU.x,coordENU.y,coordENU.z, roll,pitch,yaw)));
00290                                 }
00291                                 else
00292                                 {
00293                                         UERROR("Error parsing \"%s\" with St Lucia format (should have 12 values, e.g., 101215_153851_Ins0.log)", str.c_str());
00294                                 }
00295                         }
00296                         else if(format == 6) // MALAGA URBAN format
00297                         {
00298                                 std::vector<std::string> strList = uListToVector(uSplit(str));
00299                                 if(strList.size() ==  25)
00300                                 {
00301                                         // 0=Time
00302                                         // Lat Lon Alt fix #sats speed dir
00303                                         // 8=Local_X
00304                                         // 9=Local_Y
00305                                         // 10=Local_Z
00306                                         // rawlog_ID Geocen_X Geocen_Y Geocen_Z GPS_X GPS_Y GPS_Z GPS_VX GPS_VY GPS_VZ Local_VX Local_VY Local_VZ SAT_Time
00307                                         double stamp = uStr2Double(strList[0]);
00308                                         double x = uStr2Double(strList[8]);
00309                                         double y = uStr2Double(strList[9]);
00310                                         double z = uStr2Double(strList[10]);
00311                                         if(stamps)
00312                                         {
00313                                                 stamps->insert(std::make_pair(id, stamp));
00314                                         }
00315                                         float yaw = 0.0f;
00316                                         if(uContains(poses, id-1))
00317                                         {
00318                                                 // set yaw depending on successive poses
00319                                                 Transform & previousPose = poses.at(id-1);
00320                                                 yaw = atan2(y-previousPose.y(),x-previousPose.x());
00321                                                 previousPose = Transform(previousPose.x(), previousPose.y(), yaw);
00322                                         }
00323                                         poses.insert(std::make_pair(id, Transform(x,y,z,0,0,yaw)));
00324                                 }
00325                                 else
00326                                 {
00327                                         UERROR("Error parsing \"%s\" with Malaga Urban format (should have 25 values, *_GPS.txt)", str.c_str());
00328                                 }
00329                         }
00330                         else if(format == 5) // NewCollege format
00331                         {
00332                                 std::vector<std::string> strList = uListToVector(uSplit(str));
00333                                 if(strList.size() ==  3)
00334                                 {
00335                                         if( uIsNumber(uReplaceChar(strList[0], ' ', "")) && 
00336                                                 uIsNumber(uReplaceChar(strList[1], ' ', "")) && 
00337                                                 uIsNumber(uReplaceChar(strList[2], ' ', "")) &&
00338                                                 (strList.size()==3 || uIsNumber(uReplaceChar(strList[3], ' ', ""))))
00339                                         {
00340                                                 double stamp = uStr2Double(uReplaceChar(strList[0], ' ', ""));
00341                                                 double x = uStr2Double(uReplaceChar(strList[1], ' ', ""));
00342                                                 double y = uStr2Double(uReplaceChar(strList[2], ' ', ""));
00343 
00344                                                 if(stamps)
00345                                                 {
00346                                                         stamps->insert(std::make_pair(id, stamp));
00347                                                 }
00348                                                 float yaw = 0.0f; 
00349                                                 if(uContains(poses, id-1))
00350                                                 {
00351                                                         // set yaw depending on successive poses
00352                                                         Transform & previousPose = poses.at(id-1);
00353                                                         yaw = atan2(y-previousPose.y(),x-previousPose.x());
00354                                                         previousPose = Transform(previousPose.x(), previousPose.y(), yaw);
00355                                                 }
00356                                                 Transform pose = Transform(x,y,0,0,0,yaw);
00357                                                 if(poses.size() == 0)
00358                                                 {
00359                                                         originPose = pose.inverse();
00360                                                 }
00361                                                 pose = originPose * pose; // transform in local coordinate where first value is the origin
00362                                                 poses.insert(std::make_pair(id, pose));
00363                                         }
00364                                         else
00365                                         {
00366                                                 UDEBUG("Not valid values detected:  \"%s\"", str.c_str());
00367                                         }
00368                                 }
00369                                 else
00370                                 {
00371                                         UERROR("Error parsing \"%s\" with NewCollege format (should have 3 values: stamp x y)", str.c_str());
00372                                 }
00373                         }
00374                         else if(format == 1) // rgbd-slam format
00375                         {
00376                                 std::list<std::string> strList = uSplit(str);
00377                                 if(strList.size() ==  8)
00378                                 {
00379                                         double stamp = uStr2Double(strList.front());
00380                                         strList.pop_front();
00381                                         str = uJoin(strList, " ");
00382                                         Transform pose = Transform::fromString(str);
00383                                         if(pose.isNull())
00384                                         {
00385                                                 UWARN("Null transform read!? line parsed: \"%s\"", str.c_str());
00386                                         }
00387                                         else
00388                                         {
00389                                                 if(stamps)
00390                                                 {
00391                                                         stamps->insert(std::make_pair(id, stamp));
00392                                                 }
00393                                                 // we need to remove optical rotation
00394                                                 // z pointing front, x left, y down
00395                                                 Transform t( 0, 0, 1, 0,
00396                                                                         -1, 0, 0, 0,
00397                                                                          0,-1, 0, 0);
00398                                                 pose = t * pose * t.inverse();
00399                                                 t = Transform( 0, 0, 1, 0,
00400                                                                            0, -1, 0, 0,
00401                                                                            1, 0, 0, 0);
00402                                                 pose = t*pose;
00403                                                 poses.insert(std::make_pair(id, pose));
00404                                         }
00405                                 }
00406                                 else
00407                                 {
00408                                         UERROR("Error parsing \"%s\" with RGBD-SLAM format (should have 8 values: stamp x y z qw qx qy qz)", str.c_str());
00409                                 }
00410                         }
00411                         else // default / KITTI format
00412                         {
00413                                 Transform pose = Transform::fromString(str);
00414                                 if(format == 2)
00415                                 {
00416                                         // for KITTI, we need to remove optical rotation
00417                                         // z pointing front, x left, y down
00418                                         Transform t( 0, 0, 1, 0,
00419                                                                 -1, 0, 0, 0,
00420                                                                  0,-1, 0, 0);
00421                                         pose = t * pose * t.inverse();
00422                                 }
00423                                 poses.insert(std::make_pair(id, pose));
00424                         }
00425                         ++id;
00426                 }
00427                 file.close();
00428                 return true;
00429         }
00430         return false;
00431 }
00432 
00433 
00435 // Graph utilities
00437 std::multimap<int, Link>::iterator findLink(
00438                 std::multimap<int, Link> & links,
00439                 int from,
00440                 int to,
00441                 bool checkBothWays)
00442 {
00443         std::multimap<int, Link>::iterator iter = links.find(from);
00444         while(iter != links.end() && iter->first == from)
00445         {
00446                 if(iter->second.to() == to)
00447                 {
00448                         return iter;
00449                 }
00450                 ++iter;
00451         }
00452 
00453         if(checkBothWays)
00454         {
00455                 // let's try to -> from
00456                 iter = links.find(to);
00457                 while(iter != links.end() && iter->first == to)
00458                 {
00459                         if(iter->second.to() == from)
00460                         {
00461                                 return iter;
00462                         }
00463                         ++iter;
00464                 }
00465         }
00466         return links.end();
00467 }
00468 
00469 std::multimap<int, int>::iterator findLink(
00470                 std::multimap<int, int> & links,
00471                 int from,
00472                 int to,
00473                 bool checkBothWays)
00474 {
00475         std::multimap<int, int>::iterator iter = links.find(from);
00476         while(iter != links.end() && iter->first == from)
00477         {
00478                 if(iter->second == to)
00479                 {
00480                         return iter;
00481                 }
00482                 ++iter;
00483         }
00484 
00485         if(checkBothWays)
00486         {
00487                 // let's try to -> from
00488                 iter = links.find(to);
00489                 while(iter != links.end() && iter->first == to)
00490                 {
00491                         if(iter->second == from)
00492                         {
00493                                 return iter;
00494                         }
00495                         ++iter;
00496                 }
00497         }
00498         return links.end();
00499 }
00500 std::multimap<int, Link>::const_iterator findLink(
00501                 const std::multimap<int, Link> & links,
00502                 int from,
00503                 int to,
00504                 bool checkBothWays)
00505 {
00506         std::multimap<int, Link>::const_iterator iter = links.find(from);
00507         while(iter != links.end() && iter->first == from)
00508         {
00509                 if(iter->second.to() == to)
00510                 {
00511                         return iter;
00512                 }
00513                 ++iter;
00514         }
00515 
00516         if(checkBothWays)
00517         {
00518                 // let's try to -> from
00519                 iter = links.find(to);
00520                 while(iter != links.end() && iter->first == to)
00521                 {
00522                         if(iter->second.to() == from)
00523                         {
00524                                 return iter;
00525                         }
00526                         ++iter;
00527                 }
00528         }
00529         return links.end();
00530 }
00531 
00532 std::multimap<int, int>::const_iterator findLink(
00533                 const std::multimap<int, int> & links,
00534                 int from,
00535                 int to,
00536                 bool checkBothWays)
00537 {
00538         std::multimap<int, int>::const_iterator iter = links.find(from);
00539         while(iter != links.end() && iter->first == from)
00540         {
00541                 if(iter->second == to)
00542                 {
00543                         return iter;
00544                 }
00545                 ++iter;
00546         }
00547 
00548         if(checkBothWays)
00549         {
00550                 // let's try to -> from
00551                 iter = links.find(to);
00552                 while(iter != links.end() && iter->first == to)
00553                 {
00554                         if(iter->second == from)
00555                         {
00556                                 return iter;
00557                         }
00558                         ++iter;
00559                 }
00560         }
00561         return links.end();
00562 }
00563 
00564 std::multimap<int, Link> filterLinks(
00565                 const std::multimap<int, Link> & links,
00566                 Link::Type filteredType)
00567 {
00568         std::multimap<int, Link> output;
00569         for(std::multimap<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
00570         {
00571                 if(iter->second.type() != filteredType)
00572                 {
00573                         output.insert(*iter);
00574                 }
00575         }
00576         return output;
00577 }
00578 
00579 std::map<int, Link> filterLinks(
00580                 const std::map<int, Link> & links,
00581                 Link::Type filteredType)
00582 {
00583         std::map<int, Link> output;
00584         for(std::map<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
00585         {
00586                 if(iter->second.type() != filteredType)
00587                 {
00588                         output.insert(*iter);
00589                 }
00590         }
00591         return output;
00592 }
00593 
00594 std::map<int, Transform> frustumPosesFiltering(
00595                 const std::map<int, Transform> & poses,
00596                 const Transform & cameraPose,
00597                 float horizontalFOV, // in degrees, xfov = atan((image_width/2)/fx)*2
00598                 float verticalFOV,   // in degrees, yfov = atan((image_height/2)/fy)*2
00599                 float nearClipPlaneDistance,
00600                 float farClipPlaneDistance,
00601                 bool negative)
00602 {
00603         std::map<int, Transform> output;
00604 
00605         if(poses.size())
00606         {
00607                 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
00608                 std::vector<int> ids(poses.size());
00609 
00610                 cloud->resize(poses.size());
00611                 ids.resize(poses.size());
00612                 int oi=0;
00613                 for(std::map<int, rtabmap::Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
00614                 {
00615                         if(!iter->second.isNull())
00616                         {
00617                                 (*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
00618                                 ids[oi++] = iter->first;
00619                         }
00620                 }
00621                 cloud->resize(oi);
00622                 ids.resize(oi);
00623 
00624                 pcl::IndicesPtr indices = util3d::frustumFiltering(
00625                                 cloud,
00626                                 pcl::IndicesPtr(new std::vector<int>),
00627                                 cameraPose,
00628                                 horizontalFOV,
00629                                 verticalFOV,
00630                                 nearClipPlaneDistance,
00631                                 farClipPlaneDistance,
00632                                 negative);
00633 
00634 
00635                 for(unsigned int i=0; i<indices->size(); ++i)
00636                 {
00637                         output.insert(*poses.find(ids[indices->at(i)]));
00638                 }
00639         }
00640         return output;
00641 }
00642 
00643 std::map<int, Transform> radiusPosesFiltering(
00644                 const std::map<int, Transform> & poses,
00645                 float radius,
00646                 float angle,
00647                 bool keepLatest)
00648 {
00649         if(poses.size() > 2 && radius > 0.0f)
00650         {
00651                 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
00652                 cloud->resize(poses.size());
00653                 int i=0;
00654                 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter, ++i)
00655                 {
00656                         (*cloud)[i] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
00657                         UASSERT_MSG(pcl::isFinite((*cloud)[i]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str());
00658                 }
00659 
00660                 // radius filtering
00661                 std::vector<int> names = uKeys(poses);
00662                 std::vector<Transform> transforms = uValues(poses);
00663 
00664                 pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> (false));
00665                 tree->setInputCloud(cloud);
00666                 std::set<int> indicesChecked;
00667                 std::set<int> indicesKept;
00668 
00669                 for(unsigned int i=0; i<cloud->size(); ++i)
00670                 {
00671                         if(indicesChecked.find(i) == indicesChecked.end())
00672                         {
00673                                 std::vector<int> kIndices;
00674                                 std::vector<float> kDistances;
00675                                 tree->radiusSearch(cloud->at(i), radius, kIndices, kDistances);
00676 
00677                                 std::set<int> cloudIndices;
00678                                 const Transform & currentT = transforms.at(i);
00679                                 Eigen::Vector3f vA = currentT.toEigen3f().rotation()*Eigen::Vector3f(1,0,0);
00680                                 for(unsigned int j=0; j<kIndices.size(); ++j)
00681                                 {
00682                                         if(indicesChecked.find(kIndices[j]) == indicesChecked.end())
00683                                         {
00684                                                 if(angle > 0.0f)
00685                                                 {
00686                                                         const Transform & checkT = transforms.at(kIndices[j]);
00687                                                         // same orientation?
00688                                                         Eigen::Vector3f vB = checkT.toEigen3f().rotation()*Eigen::Vector3f(1,0,0);
00689                                                         double a = pcl::getAngle3D(Eigen::Vector4f(vA[0], vA[1], vA[2], 0), Eigen::Vector4f(vB[0], vB[1], vB[2], 0));
00690                                                         if(a <= angle)
00691                                                         {
00692                                                                 cloudIndices.insert(kIndices[j]);
00693                                                         }
00694                                                 }
00695                                                 else
00696                                                 {
00697                                                         cloudIndices.insert(kIndices[j]);
00698                                                 }
00699                                         }
00700                                 }
00701 
00702                                 if(keepLatest)
00703                                 {
00704                                         bool lastAdded = false;
00705                                         for(std::set<int>::reverse_iterator iter = cloudIndices.rbegin(); iter!=cloudIndices.rend(); ++iter)
00706                                         {
00707                                                 if(!lastAdded)
00708                                                 {
00709                                                         indicesKept.insert(*iter);
00710                                                         lastAdded = true;
00711                                                 }
00712                                                 indicesChecked.insert(*iter);
00713                                         }
00714                                 }
00715                                 else
00716                                 {
00717                                         bool firstAdded = false;
00718                                         for(std::set<int>::iterator iter = cloudIndices.begin(); iter!=cloudIndices.end(); ++iter)
00719                                         {
00720                                                 if(!firstAdded)
00721                                                 {
00722                                                         indicesKept.insert(*iter);
00723                                                         firstAdded = true;
00724                                                 }
00725                                                 indicesChecked.insert(*iter);
00726                                         }
00727                                 }
00728                         }
00729                 }
00730 
00731                 //pcl::IndicesPtr indicesOut(new std::vector<int>);
00732                 //indicesOut->insert(indicesOut->end(), indicesKept.begin(), indicesKept.end());
00733                 UINFO("Cloud filtered In = %d, Out = %d", cloud->size(), indicesKept.size());
00734                 //pcl::io::savePCDFile("duplicateIn.pcd", *cloud);
00735                 //pcl::io::savePCDFile("duplicateOut.pcd", *cloud, *indicesOut);
00736 
00737                 std::map<int, Transform> keptPoses;
00738                 for(std::set<int>::iterator iter = indicesKept.begin(); iter!=indicesKept.end(); ++iter)
00739                 {
00740                         keptPoses.insert(std::make_pair(names.at(*iter), transforms.at(*iter)));
00741                 }
00742 
00743                 // make sure the first and last poses are still here
00744                 keptPoses.insert(*poses.begin());
00745                 keptPoses.insert(*poses.rbegin());
00746 
00747                 return keptPoses;
00748         }
00749         else
00750         {
00751                 return poses;
00752         }
00753 }
00754 
00755 std::multimap<int, int> radiusPosesClustering(const std::map<int, Transform> & poses, float radius, float angle)
00756 {
00757         std::multimap<int, int> clusters;
00758         if(poses.size() > 1 && radius > 0.0f)
00759         {
00760                 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
00761                 cloud->resize(poses.size());
00762                 int i=0;
00763                 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter, ++i)
00764                 {
00765                         (*cloud)[i] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
00766                         UASSERT_MSG(pcl::isFinite((*cloud)[i]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str());
00767                 }
00768 
00769                 // radius clustering (nearest neighbors)
00770                 std::vector<int> ids = uKeys(poses);
00771                 std::vector<Transform> transforms = uValues(poses);
00772 
00773                 pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> (false));
00774                 tree->setInputCloud(cloud);
00775 
00776                 for(unsigned int i=0; i<cloud->size(); ++i)
00777                 {
00778                         std::vector<int> kIndices;
00779                         std::vector<float> kDistances;
00780                         tree->radiusSearch(cloud->at(i), radius, kIndices, kDistances);
00781 
00782                         std::set<int> cloudIndices;
00783                         const Transform & currentT = transforms.at(i);
00784                         Eigen::Vector3f vA = currentT.toEigen3f().rotation()*Eigen::Vector3f(1,0,0);
00785                         for(unsigned int j=0; j<kIndices.size(); ++j)
00786                         {
00787                                 if((int)i != kIndices[j])
00788                                 {
00789                                         if(angle > 0.0f)
00790                                         {
00791                                                 const Transform & checkT = transforms.at(kIndices[j]);
00792                                                 // same orientation?
00793                                                 Eigen::Vector3f vB = checkT.toEigen3f().rotation()*Eigen::Vector3f(1,0,0);
00794                                                 double a = pcl::getAngle3D(Eigen::Vector4f(vA[0], vA[1], vA[2], 0), Eigen::Vector4f(vB[0], vB[1], vB[2], 0));
00795                                                 if(a <= angle)
00796                                                 {
00797                                                         clusters.insert(std::make_pair(ids[i], ids[kIndices[j]]));
00798                                                 }
00799                                         }
00800                                         else
00801                                         {
00802                                                 clusters.insert(std::make_pair(ids[i], ids[kIndices[j]]));
00803                                         }
00804                                 }
00805                         }
00806                 }
00807         }
00808         return clusters;
00809 }
00810 
00811 void reduceGraph(
00812                 const std::map<int, Transform> & poses,
00813                 const std::multimap<int, Link> & links,
00814                 std::multimap<int, int> & hyperNodes, //<parent ID, child ID>
00815                 std::multimap<int, Link> & hyperLinks)
00816 {
00817         UINFO("Input: poses=%d links=%d", (int)poses.size(), (int)links.size());
00818         UTimer timer;
00819         std::map<int, int> posesToHyperNodes;
00820         std::map<int, std::multimap<int, Link> > clusterloopClosureLinks;
00821 
00822         {
00823                 std::multimap<int, Link> bidirectionalLoopClosureLinks;
00824                 for(std::multimap<int, Link>::const_iterator jter=links.begin(); jter!=links.end(); ++jter)
00825                 {
00826                         if(jter->second.type() != Link::kNeighbor &&
00827                            jter->second.type() != Link::kNeighborMerged &&
00828                            jter->second.userDataCompressed().empty())
00829                         {
00830                                 if(uContains(poses, jter->second.from()) &&
00831                                    uContains(poses, jter->second.to()))
00832                                 {
00833                                         UASSERT_MSG(graph::findLink(links, jter->second.to(), jter->second.from(), false) == links.end(), "Input links should be unique!");
00834                                         bidirectionalLoopClosureLinks.insert(std::make_pair(jter->second.from(), jter->second));
00835                                         //bidirectionalLoopClosureLinks.insert(std::make_pair(jter->second.to(), jter->second.inverse()));
00836                                 }
00837                         }
00838                 }
00839 
00840                 UINFO("Clustering hyper nodes...");
00841                 // largest ID to smallest ID
00842                 for(std::map<int, Transform>::const_reverse_iterator iter=poses.rbegin(); iter!=poses.rend(); ++iter)
00843                 {
00844                         if(posesToHyperNodes.find(iter->first) == posesToHyperNodes.end())
00845                         {
00846                                 int hyperNodeId = iter->first;
00847                                 std::list<int> loopClosures;
00848                                 std::set<int> loopClosuresAdded;
00849                                 loopClosures.push_back(iter->first);
00850                                 std::multimap<int, Link> clusterLinks;
00851                                 while(loopClosures.size())
00852                                 {
00853                                         int id = loopClosures.front();
00854                                         loopClosures.pop_front();
00855 
00856                                         UASSERT(posesToHyperNodes.find(id) == posesToHyperNodes.end());
00857 
00858                                         posesToHyperNodes.insert(std::make_pair(id, hyperNodeId));
00859                                         hyperNodes.insert(std::make_pair(hyperNodeId, id));
00860 
00861                                         for(std::multimap<int, Link>::const_iterator jter=bidirectionalLoopClosureLinks.find(id); jter!=bidirectionalLoopClosureLinks.end() && jter->first==id; ++jter)
00862                                         {
00863                                                 if(posesToHyperNodes.find(jter->second.to()) == posesToHyperNodes.end() &&
00864                                                    loopClosuresAdded.find(jter->second.to()) == loopClosuresAdded.end())
00865                                                 {
00866                                                         loopClosures.push_back(jter->second.to());
00867                                                         loopClosuresAdded.insert(jter->second.to());
00868                                                         clusterLinks.insert(*jter);
00869                                                         clusterLinks.insert(std::make_pair(jter->second.to(), jter->second.inverse()));
00870                                                         if(jter->second.from() < jter->second.to())
00871                                                         {
00872                                                                 UWARN("Child to Parent link? %d->%d (type=%d)",
00873                                                                                 jter->second.from(),
00874                                                                                 jter->second.to(),
00875                                                                                 jter->second.type());
00876                                                         }
00877                                                 }
00878                                         }
00879                                 }
00880                                 UASSERT(clusterloopClosureLinks.find(hyperNodeId) == clusterloopClosureLinks.end());
00881                                 clusterloopClosureLinks.insert(std::make_pair(hyperNodeId, clusterLinks));
00882                                 UDEBUG("Created hyper node %d with %d children (%f%%)",
00883                                                 hyperNodeId, (int)loopClosuresAdded.size(), float(posesToHyperNodes.size())/float(poses.size())*100.0f);
00884                         }
00885                 }
00886                 UINFO("Clustering hyper nodes... done! (%f s)", timer.ticks());
00887         }
00888 
00889         UINFO("Creating hyper links...");
00890         int i=0;
00891         for(std::multimap<int, Link>::const_reverse_iterator jter=links.rbegin(); jter!=links.rend(); ++jter)
00892         {
00893                 if((jter->second.type() == Link::kNeighbor ||
00894                    jter->second.type() == Link::kNeighborMerged ||
00895                    !jter->second.userDataCompressed().empty()) &&
00896                    uContains(poses, jter->second.from()) &&
00897                    uContains(poses, jter->second.to()))
00898                 {
00899                         UASSERT_MSG(uContains(posesToHyperNodes, jter->second.from()), uFormat("%d->%d (type=%d)", jter->second.from(), jter->second.to(), jter->second.type()).c_str());
00900                         UASSERT_MSG(uContains(posesToHyperNodes, jter->second.to()), uFormat("%d->%d (type=%d)", jter->second.from(), jter->second.to(), jter->second.type()).c_str());
00901                         int hyperNodeIDFrom = posesToHyperNodes.at(jter->second.from());
00902                         int hyperNodeIDTo = posesToHyperNodes.at(jter->second.to());
00903 
00904                         // ignore links inside a hyper node
00905                         if(hyperNodeIDFrom != hyperNodeIDTo)
00906                         {
00907                                 std::multimap<int, Link>::iterator tmpIter = graph::findLink(hyperLinks, hyperNodeIDFrom, hyperNodeIDTo);
00908                                 if(tmpIter!=hyperLinks.end() &&
00909                                         hyperNodeIDFrom == jter->second.from() &&
00910                                         hyperNodeIDTo == jter->second.to() &&
00911                                         tmpIter->second.type() > Link::kNeighbor &&
00912                                         jter->second.type() == Link::kNeighbor)
00913                                 {
00914                                         // neighbor links have priority, so remove the previously added link
00915                                         hyperLinks.erase(tmpIter);
00916                                 }
00917 
00918                                 // only add unique link between two hyper nodes (keeping only the more recent)
00919                                 if(graph::findLink(hyperLinks, hyperNodeIDFrom, hyperNodeIDTo) == hyperLinks.end())
00920                                 {
00921                                         UASSERT(clusterloopClosureLinks.find(hyperNodeIDFrom) != clusterloopClosureLinks.end());
00922                                         UASSERT(clusterloopClosureLinks.find(hyperNodeIDTo) != clusterloopClosureLinks.end());
00923                                         std::multimap<int, Link> tmpLinks = clusterloopClosureLinks.at(hyperNodeIDFrom);
00924                                         tmpLinks.insert(clusterloopClosureLinks.at(hyperNodeIDTo).begin(), clusterloopClosureLinks.at(hyperNodeIDTo).end());
00925                                         tmpLinks.insert(std::make_pair(jter->second.from(), jter->second));
00926 
00927                                         std::list<int> path = computePath(tmpLinks, hyperNodeIDFrom, hyperNodeIDTo, false, true);
00928                                         UASSERT_MSG(path.size()>1,
00929                                                         uFormat("path.size()=%d, hyperNodeIDFrom=%d, hyperNodeIDTo=%d",
00930                                                                         (int)path.size(),
00931                                                                         hyperNodeIDFrom,
00932                                                                         hyperNodeIDTo).c_str());
00933 
00934                                         if(path.size() > 10)
00935                                         {
00936                                                 UWARN("Large path! %d nodes", (int)path.size());
00937                                                 std::stringstream stream;
00938                                                 for(std::list<int>::const_iterator iter=path.begin(); iter!=path.end();++iter)
00939                                                 {
00940                                                         if(iter!=path.begin())
00941                                                         {
00942                                                                 stream << ",";
00943                                                         }
00944 
00945                                                         stream << *iter;
00946                                                 }
00947                                                 UWARN("Path = [%s]", stream.str().c_str());
00948                                         }
00949 
00950                                         // create the hyperlink
00951                                         std::list<int>::iterator iter=path.begin();
00952                                         int from = *iter;
00953                                         ++iter;
00954                                         int to = *iter;
00955                                         std::multimap<int, Link>::const_iterator foundIter = graph::findLink(tmpLinks, from, to, false);
00956                                         UASSERT(foundIter != tmpLinks.end());
00957                                         Link hyperLink = foundIter->second;
00958                                         ++iter;
00959                                         from = to;
00960                                         for(; iter!=path.end(); ++iter)
00961                                         {
00962                                                 to = *iter;
00963                                                 std::multimap<int, Link>::const_iterator foundIter = graph::findLink(tmpLinks, from, to, false);
00964                                                 UASSERT(foundIter != tmpLinks.end());
00965                                                 hyperLink = hyperLink.merge(foundIter->second, jter->second.type());
00966 
00967                                                 from = to;
00968                                         }
00969 
00970                                         UASSERT(hyperLink.from() == hyperNodeIDFrom);
00971                                         UASSERT(hyperLink.to() == hyperNodeIDTo);
00972                                         hyperLinks.insert(std::make_pair(hyperNodeIDFrom, hyperLink));
00973 
00974                                         UDEBUG("Created hyper link %d->%d (%f%%)",
00975                                                         hyperLink.from(), hyperLink.to(), float(i)/float(links.size())*100.0f);
00976                                         if(hyperLink.transform().getNorm() > jter->second.transform().getNorm()+1)
00977                                         {
00978                                                 UWARN("Large hyper link %d->%d (%f m)! original %d->%d (%f m)",
00979                                                                 hyperLink.from(),
00980                                                                 hyperLink.to(),
00981                                                                 hyperLink.transform().getNorm(),
00982                                                                 jter->second.from(),
00983                                                                 jter->second.to(),
00984                                                                 jter->second.transform().getNorm());
00985 
00986                                         }
00987                                 }
00988                         }
00989                 }
00990                 ++i;
00991         }
00992         UINFO("Creating hyper links... done! (%f s)", timer.ticks());
00993 
00994         UINFO("Output: poses=%d links=%d", (int)uUniqueKeys(hyperNodes).size(), (int)links.size());
00995 }
00996 
00997 
00998 class Node
00999 {
01000 public:
01001         Node(int id, int fromId, const rtabmap::Transform & pose) :
01002                 id_(id),
01003                 costSoFar_(0.0f),
01004                 distToEnd_(0.0f),
01005                 fromId_(fromId),
01006                 closed_(false),
01007                 pose_(pose)
01008         {}
01009 
01010         int id() const {return id_;}
01011         int fromId() const {return fromId_;}
01012         bool isClosed() const {return closed_;}
01013         bool isOpened() const {return !closed_;}
01014         float costSoFar() const {return costSoFar_;} // Dijkstra cost
01015         float distToEnd() const {return distToEnd_;} // Breath-first cost
01016         float totalCost() const {return costSoFar_ + distToEnd_;} // A* cost
01017         rtabmap::Transform pose() const {return pose_;}
01018         float distFrom(const rtabmap::Transform & pose) const
01019         {
01020                 return pose_.getDistance(pose); // use sqrt distance
01021         }
01022 
01023         void setClosed(bool closed) {closed_ = closed;}
01024         void setFromId(int fromId) {fromId_ = fromId;}
01025         void setCostSoFar(float costSoFar) {costSoFar_ = costSoFar;}
01026         void setDistToEnd(float distToEnd) {distToEnd_ = distToEnd;}
01027         void setPose(const Transform & pose) {pose_ = pose;}
01028 
01029 private:
01030         int id_;
01031         float costSoFar_;
01032         float distToEnd_;
01033         int fromId_;
01034         bool closed_;
01035         rtabmap::Transform pose_;
01036 };
01037 
01038 typedef std::pair<int, float> Pair; // first is id, second is cost
01039 struct Order
01040 {
01041     bool operator()(Pair const& a, Pair const& b) const
01042     {
01043         return a.second > b.second;
01044     }
01045 };
01046 
01047 // A*
01048 std::list<std::pair<int, Transform> > computePath(
01049                         const std::map<int, rtabmap::Transform> & poses,
01050                         const std::multimap<int, int> & links,
01051                         int from,
01052                         int to,
01053                         bool updateNewCosts)
01054 {
01055         std::list<std::pair<int, Transform> > path;
01056 
01057         int startNode = from;
01058         int endNode = to;
01059         rtabmap::Transform endPose = poses.at(endNode);
01060         std::map<int, Node> nodes;
01061         nodes.insert(std::make_pair(startNode, Node(startNode, 0, poses.at(startNode))));
01062         std::priority_queue<Pair, std::vector<Pair>, Order> pq;
01063         std::multimap<float, int> pqmap;
01064         if(updateNewCosts)
01065         {
01066                 pqmap.insert(std::make_pair(0, startNode));
01067         }
01068         else
01069         {
01070                 pq.push(Pair(startNode, 0));
01071         }
01072 
01073         while((updateNewCosts && pqmap.size()) || (!updateNewCosts && pq.size()))
01074         {
01075                 Node * currentNode;
01076                 if(updateNewCosts)
01077                 {
01078                         currentNode = &nodes.find(pqmap.begin()->second)->second;
01079                         pqmap.erase(pqmap.begin());
01080                 }
01081                 else
01082                 {
01083                         currentNode = &nodes.find(pq.top().first)->second;
01084                         pq.pop();
01085                 }
01086 
01087                 currentNode->setClosed(true);
01088 
01089                 if(currentNode->id() == endNode)
01090                 {
01091                         while(currentNode->id()!=startNode)
01092                         {
01093                                 path.push_front(std::make_pair(currentNode->id(), currentNode->pose()));
01094                                 currentNode = &nodes.find(currentNode->fromId())->second;
01095                         }
01096                         path.push_front(std::make_pair(startNode, poses.at(startNode)));
01097                         break;
01098                 }
01099 
01100                 // lookup neighbors
01101                 for(std::multimap<int, int>::const_iterator iter = links.find(currentNode->id());
01102                         iter!=links.end() && iter->first == currentNode->id();
01103                         ++iter)
01104                 {
01105                         std::map<int, Node>::iterator nodeIter = nodes.find(iter->second);
01106                         if(nodeIter == nodes.end())
01107                         {
01108                                 std::map<int, rtabmap::Transform>::const_iterator poseIter = poses.find(iter->second);
01109                                 if(poseIter == poses.end())
01110                                 {
01111                                         UERROR("Next pose %d (from %d) should be found in poses! Ignoring it!", iter->second, iter->first);
01112                                 }
01113                                 else
01114                                 {
01115                                         Node n(iter->second, currentNode->id(), poseIter->second);
01116                                         n.setCostSoFar(currentNode->costSoFar() + currentNode->distFrom(poseIter->second));
01117                                         n.setDistToEnd(n.distFrom(endPose));
01118 
01119                                         nodes.insert(std::make_pair(iter->second, n));
01120                                         if(updateNewCosts)
01121                                         {
01122                                                 pqmap.insert(std::make_pair(n.totalCost(), n.id()));
01123                                         }
01124                                         else
01125                                         {
01126                                                 pq.push(Pair(n.id(), n.totalCost()));
01127                                         }
01128                                 }
01129                         }
01130                         else if(updateNewCosts && nodeIter->second.isOpened())
01131                         {
01132                                 float newCostSoFar = currentNode->costSoFar() + currentNode->distFrom(nodeIter->second.pose());
01133                                 if(nodeIter->second.costSoFar() > newCostSoFar)
01134                                 {
01135                                         // update the cost in the priority queue
01136                                         for(std::multimap<float, int>::iterator mapIter=pqmap.begin(); mapIter!=pqmap.end(); ++mapIter)
01137                                         {
01138                                                 if(mapIter->second == nodeIter->first)
01139                                                 {
01140                                                         pqmap.erase(mapIter);
01141                                                         nodeIter->second.setCostSoFar(newCostSoFar);
01142                                                         pqmap.insert(std::make_pair(nodeIter->second.totalCost(), nodeIter->first));
01143                                                         break;
01144                                                 }
01145                                         }
01146                                 }
01147                         }
01148                 }
01149         }
01150         return path;
01151 }
01152 
01153 // Dijksta
01154 std::list<int> RTABMAP_EXP computePath(
01155                         const std::multimap<int, Link> & links,
01156                         int from,
01157                         int to,
01158                         bool updateNewCosts,
01159                         bool useSameCostForAllLinks)
01160 {
01161         std::list<int> path;
01162 
01163         int startNode = from;
01164         int endNode = to;
01165         std::map<int, Node> nodes;
01166         nodes.insert(std::make_pair(startNode, Node(startNode, 0, Transform())));
01167         std::priority_queue<Pair, std::vector<Pair>, Order> pq;
01168         std::multimap<float, int> pqmap;
01169         if(updateNewCosts)
01170         {
01171                 pqmap.insert(std::make_pair(0, startNode));
01172         }
01173         else
01174         {
01175                 pq.push(Pair(startNode, 0));
01176         }
01177 
01178         while((updateNewCosts && pqmap.size()) || (!updateNewCosts && pq.size()))
01179         {
01180                 Node * currentNode;
01181                 if(updateNewCosts)
01182                 {
01183                         currentNode = &nodes.find(pqmap.begin()->second)->second;
01184                         pqmap.erase(pqmap.begin());
01185                 }
01186                 else
01187                 {
01188                         currentNode = &nodes.find(pq.top().first)->second;
01189                         pq.pop();
01190                 }
01191 
01192                 currentNode->setClosed(true);
01193 
01194                 if(currentNode->id() == endNode)
01195                 {
01196                         while(currentNode->id()!=startNode)
01197                         {
01198                                 path.push_front(currentNode->id());
01199                                 currentNode = &nodes.find(currentNode->fromId())->second;
01200                         }
01201                         path.push_front(startNode);
01202                         break;
01203                 }
01204 
01205                 // lookup neighbors
01206                 for(std::multimap<int, Link>::const_iterator iter = links.find(currentNode->id());
01207                         iter!=links.end() && iter->first == currentNode->id();
01208                         ++iter)
01209                 {
01210                         std::map<int, Node>::iterator nodeIter = nodes.find(iter->second.to());
01211                         float cost = 1;
01212                         if(!useSameCostForAllLinks)
01213                         {
01214                                 cost = iter->second.transform().getNorm();
01215                         }
01216                         if(nodeIter == nodes.end())
01217                         {
01218                                 Node n(iter->second.to(), currentNode->id(), Transform());
01219 
01220                                 n.setCostSoFar(currentNode->costSoFar() + cost);
01221                                 nodes.insert(std::make_pair(iter->second.to(), n));
01222                                 if(updateNewCosts)
01223                                 {
01224                                         pqmap.insert(std::make_pair(n.totalCost(), n.id()));
01225                                 }
01226                                 else
01227                                 {
01228                                         pq.push(Pair(n.id(), n.totalCost()));
01229                                 }
01230                         }
01231                         else if(!useSameCostForAllLinks && updateNewCosts && nodeIter->second.isOpened())
01232                         {
01233                                 float newCostSoFar = currentNode->costSoFar() + cost;
01234                                 if(nodeIter->second.costSoFar() > newCostSoFar)
01235                                 {
01236                                         // update the cost in the priority queue
01237                                         for(std::multimap<float, int>::iterator mapIter=pqmap.begin(); mapIter!=pqmap.end(); ++mapIter)
01238                                         {
01239                                                 if(mapIter->second == nodeIter->first)
01240                                                 {
01241                                                         pqmap.erase(mapIter);
01242                                                         nodeIter->second.setCostSoFar(newCostSoFar);
01243                                                         pqmap.insert(std::make_pair(nodeIter->second.totalCost(), nodeIter->first));
01244                                                         break;
01245                                                 }
01246                                         }
01247                                 }
01248                         }
01249                 }
01250         }
01251         return path;
01252 }
01253 
01254 
01255 // return path starting from "fromId" (Identity pose for the first node)
01256 std::list<std::pair<int, Transform> > computePath(
01257                 int fromId,
01258                 int toId,
01259                 const Memory * memory,
01260                 bool lookInDatabase,
01261                 bool updateNewCosts,
01262                 float linearVelocity,  // m/sec
01263                 float angularVelocity) // rad/sec
01264 {
01265         UASSERT(memory!=0);
01266         UASSERT(fromId>=0);
01267         UASSERT(toId>=0);
01268         std::list<std::pair<int, Transform> > path;
01269         UDEBUG("fromId=%d, toId=%d, lookInDatabase=%d, updateNewCosts=%d, linearVelocity=%f, angularVelocity=%f",
01270                         fromId,
01271                         toId,
01272                         lookInDatabase?1:0,
01273                         updateNewCosts?1:0,
01274                         linearVelocity,
01275                         angularVelocity);
01276 
01277         std::multimap<int, Link> allLinks;
01278         if(lookInDatabase)
01279         {
01280                 // Faster to load all links in one query
01281                 UTimer t;
01282                 allLinks = memory->getAllLinks(lookInDatabase);
01283                 UINFO("getting all %d links time = %f s", (int)allLinks.size(), t.ticks());
01284         }
01285 
01286         //dijkstra
01287         int startNode = fromId;
01288         int endNode = toId;
01289         std::map<int, Node> nodes;
01290         nodes.insert(std::make_pair(startNode, Node(startNode, 0, Transform::getIdentity())));
01291         std::priority_queue<Pair, std::vector<Pair>, Order> pq;
01292         std::multimap<float, int> pqmap;
01293         if(updateNewCosts)
01294         {
01295                 pqmap.insert(std::make_pair(0, startNode));
01296         }
01297         else
01298         {
01299                 pq.push(Pair(startNode, 0));
01300         }
01301 
01302         while((updateNewCosts && pqmap.size()) || (!updateNewCosts && pq.size()))
01303         {
01304                 Node * currentNode;
01305                 if(updateNewCosts)
01306                 {
01307                         currentNode = &nodes.find(pqmap.begin()->second)->second;
01308                         pqmap.erase(pqmap.begin());
01309                 }
01310                 else
01311                 {
01312                         currentNode = &nodes.find(pq.top().first)->second;
01313                         pq.pop();
01314                 }
01315 
01316                 currentNode->setClosed(true);
01317 
01318                 if(currentNode->id() == endNode)
01319                 {
01320                         while(currentNode->id()!=startNode)
01321                         {
01322                                 path.push_front(std::make_pair(currentNode->id(), currentNode->pose()));
01323                                 currentNode = &nodes.find(currentNode->fromId())->second;
01324                         }
01325                         path.push_front(std::make_pair(startNode, currentNode->pose()));
01326                         break;
01327                 }
01328 
01329                 // lookup neighbors
01330                 std::map<int, Link> links;
01331                 if(allLinks.size() == 0)
01332                 {
01333                         links = memory->getLinks(currentNode->id(), lookInDatabase);
01334                 }
01335                 else
01336                 {
01337                         for(std::multimap<int, Link>::const_iterator iter = allLinks.lower_bound(currentNode->id());
01338                                 iter!=allLinks.end() && iter->first == currentNode->id();
01339                                 ++iter)
01340                         {
01341                                 links.insert(std::make_pair(iter->second.to(), iter->second));
01342                         }
01343                 }
01344                 for(std::map<int, Link>::const_iterator iter = links.begin(); iter!=links.end(); ++iter)
01345                 {
01346                         Transform nextPose = currentNode->pose()*iter->second.transform();
01347                         float cost = 0.0f;
01348                         if(linearVelocity <= 0.0f && angularVelocity <= 0.0f)
01349                         {
01350                                 // use distance only
01351                                 cost = iter->second.transform().getNorm();
01352                         }
01353                         else // use time
01354                         {
01355                                 if(linearVelocity > 0.0f)
01356                                 {
01357                                         cost += iter->second.transform().getNorm()/linearVelocity;
01358                                 }
01359                                 if(angularVelocity > 0.0f)
01360                                 {
01361                                         Eigen::Vector4f v1 = Eigen::Vector4f(nextPose.x()-currentNode->pose().x(), nextPose.y()-currentNode->pose().y(), nextPose.z()-currentNode->pose().z(), 1.0f);
01362                                         Eigen::Vector4f v2 = nextPose.rotation().toEigen4f()*Eigen::Vector4f(1,0,0,1);
01363                                         float angle = pcl::getAngle3D(v1, v2);
01364                                         cost += angle / angularVelocity;
01365                                 }
01366                         }
01367 
01368                         std::map<int, Node>::iterator nodeIter = nodes.find(iter->first);
01369                         if(nodeIter == nodes.end())
01370                         {
01371                                 Node n(iter->second.to(), currentNode->id(), nextPose);
01372 
01373                                 n.setCostSoFar(currentNode->costSoFar() + cost);
01374                                 nodes.insert(std::make_pair(iter->second.to(), n));
01375                                 if(updateNewCosts)
01376                                 {
01377                                         pqmap.insert(std::make_pair(n.totalCost(), n.id()));
01378                                 }
01379                                 else
01380                                 {
01381                                         pq.push(Pair(n.id(), n.totalCost()));
01382                                 }
01383                         }
01384                         else if(updateNewCosts && nodeIter->second.isOpened())
01385                         {
01386                                 float newCostSoFar = currentNode->costSoFar() + cost;
01387                                 if(nodeIter->second.costSoFar() > newCostSoFar)
01388                                 {
01389                                         // update pose with new link
01390                                         nodeIter->second.setPose(nextPose);
01391 
01392                                         // update the cost in the priority queue
01393                                         for(std::multimap<float, int>::iterator mapIter=pqmap.begin(); mapIter!=pqmap.end(); ++mapIter)
01394                                         {
01395                                                 if(mapIter->second == nodeIter->first)
01396                                                 {
01397                                                         pqmap.erase(mapIter);
01398                                                         nodeIter->second.setCostSoFar(newCostSoFar);
01399                                                         pqmap.insert(std::make_pair(nodeIter->second.totalCost(), nodeIter->first));
01400                                                         break;
01401                                                 }
01402                                         }
01403                                 }
01404                         }
01405                 }
01406         }
01407 
01408         // Debugging stuff
01409         if(ULogger::level() == ULogger::kDebug)
01410         {
01411                 std::stringstream stream;
01412                 std::vector<int> linkTypes(Link::kUndef, 0);
01413                 std::list<std::pair<int, Transform> >::const_iterator previousIter = path.end();
01414                 float length = 0.0f;
01415                 for(std::list<std::pair<int, Transform> >::const_iterator iter=path.begin(); iter!=path.end();++iter)
01416                 {
01417                         if(iter!=path.begin())
01418                         {
01419                                 stream << ",";
01420                         }
01421 
01422                         if(previousIter!=path.end())
01423                         {
01424                                 //UDEBUG("current  %d = %s", iter->first, iter->second.prettyPrint().c_str());
01425                                 if(allLinks.size())
01426                                 {
01427                                         std::multimap<int, Link>::iterator jter = graph::findLink(allLinks, previousIter->first, iter->first);
01428                                         if(jter != allLinks.end())
01429                                         {
01430                                                 //Transform nextPose = iter->second;
01431                                                 //Eigen::Vector4f v1 = Eigen::Vector4f(nextPose.x()-previousIter->second.x(), nextPose.y()-previousIter->second.y(), nextPose.z()-previousIter->second.z(), 1.0f);
01432                                                 //Eigen::Vector4f v2 = nextPose.rotation().toEigen4f()*Eigen::Vector4f(1,0,0,1);
01433                                                 //float angle = pcl::getAngle3D(v1, v2);
01434                                                 //float cost = angle ;
01435                                                 //UDEBUG("v1=%f,%f,%f v2=%f,%f,%f a=%f", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], cost);
01436 
01437                                                 UASSERT(jter->second.type() >= Link::kNeighbor && jter->second.type()<Link::kUndef);
01438                                                 ++linkTypes[jter->second.type()];
01439                                                 stream << "[" << jter->second.type() << "]";
01440                                                 length += jter->second.transform().getNorm();
01441                                         }
01442                                 }
01443                         }
01444 
01445                         stream << iter->first;
01446 
01447                         previousIter=iter;
01448                 }
01449                 UDEBUG("Path (%f m) = [%s]", length, stream.str().c_str());
01450                 std::stringstream streamB;
01451                 for(unsigned int i=0; i<linkTypes.size(); ++i)
01452                 {
01453                         if(i > 0)
01454                         {
01455                                 streamB << " ";
01456                         }
01457                         streamB << i << "=" << linkTypes[i];
01458                 }
01459                 UDEBUG("Link types = %s", streamB.str().c_str());
01460         }
01461 
01462         return path;
01463 }
01464 
01465 int findNearestNode(
01466                 const std::map<int, rtabmap::Transform> & nodes,
01467                 const rtabmap::Transform & targetPose)
01468 {
01469         int id = 0;
01470         if(nodes.size() && !targetPose.isNull())
01471         {
01472                 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
01473                 cloud->resize(nodes.size());
01474                 std::vector<int> ids(nodes.size());
01475                 int oi = 0;
01476                 for(std::map<int, Transform>::const_iterator iter = nodes.begin(); iter!=nodes.end(); ++iter)
01477                 {
01478                         (*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
01479                         ids[oi++] = iter->first;
01480                 }
01481 
01482                 std::map<int, float> foundNodes;
01483                 if(cloud->size())
01484                 {
01485                         pcl::search::KdTree<pcl::PointXYZ>::Ptr kdTree(new pcl::search::KdTree<pcl::PointXYZ>);
01486                         kdTree->setInputCloud(cloud);
01487                         std::vector<int> ind;
01488                         std::vector<float> dist;
01489                         pcl::PointXYZ pt(targetPose.x(), targetPose.y(), targetPose.z());
01490                         kdTree->nearestKSearch(pt, 1, ind, dist);
01491                         if(ind.size() && dist.size() && ind[0] >= 0)
01492                         {
01493                                 UDEBUG("Nearest node = %d: %f", ids[ind[0]], dist[0]);
01494                                 id = ids[ind[0]];
01495                         }
01496                 }
01497         }
01498         return id;
01499 }
01500 
01501 // return <id, sqrd distance>, excluding query
01502 std::map<int, float> getNodesInRadius(
01503                 int nodeId,
01504                 const std::map<int, Transform> & nodes,
01505                 float radius)
01506 {
01507         UASSERT(uContains(nodes, nodeId));
01508         std::map<int, float> foundNodes;
01509         if(nodes.size() <= 1)
01510         {
01511                 return foundNodes;
01512         }
01513 
01514         pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
01515         cloud->resize(nodes.size());
01516         std::vector<int> ids(nodes.size());
01517         int oi = 0;
01518         for(std::map<int, Transform>::const_iterator iter = nodes.begin(); iter!=nodes.end(); ++iter)
01519         {
01520                 if(iter->first != nodeId)
01521                 {
01522                         (*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
01523                         UASSERT_MSG(pcl::isFinite((*cloud)[oi]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str());
01524                         ids[oi] = iter->first;
01525                         ++oi;
01526                 }
01527         }
01528         cloud->resize(oi);
01529         ids.resize(oi);
01530 
01531         Transform fromT = nodes.at(nodeId);
01532 
01533         if(cloud->size())
01534         {
01535                 pcl::search::KdTree<pcl::PointXYZ>::Ptr kdTree(new pcl::search::KdTree<pcl::PointXYZ>);
01536                 kdTree->setInputCloud(cloud);
01537                 std::vector<int> ind;
01538                 std::vector<float> sqrdDist;
01539                 pcl::PointXYZ pt(fromT.x(), fromT.y(), fromT.z());
01540                 kdTree->radiusSearch(pt, radius, ind, sqrdDist, 0);
01541                 for(unsigned int i=0; i<ind.size(); ++i)
01542                 {
01543                         if(ind[i] >=0)
01544                         {
01545                                 foundNodes.insert(std::make_pair(ids[ind[i]], sqrdDist[i]));
01546                         }
01547                 }
01548         }
01549         UDEBUG("found nodes=%d", (int)foundNodes.size());
01550         return foundNodes;
01551 }
01552 
01553 // return <id, Transform>, excluding query
01554 std::map<int, Transform> getPosesInRadius(
01555                 int nodeId,
01556                 const std::map<int, Transform> & nodes,
01557                 float radius,
01558                 float angle)
01559 {
01560         UASSERT(uContains(nodes, nodeId));
01561         std::map<int, Transform> foundNodes;
01562         if(nodes.size() <= 1)
01563         {
01564                 return foundNodes;
01565         }
01566 
01567         pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
01568         cloud->resize(nodes.size());
01569         std::vector<int> ids(nodes.size());
01570         int oi = 0;
01571         for(std::map<int, Transform>::const_iterator iter = nodes.begin(); iter!=nodes.end(); ++iter)
01572         {
01573                 if(iter->first != nodeId)
01574                 {
01575                         (*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
01576                         UASSERT_MSG(pcl::isFinite((*cloud)[oi]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str());
01577                         ids[oi] = iter->first;
01578                         ++oi;
01579                 }
01580         }
01581         cloud->resize(oi);
01582         ids.resize(oi);
01583 
01584         Transform fromT = nodes.at(nodeId);
01585 
01586         if(cloud->size())
01587         {
01588                 pcl::search::KdTree<pcl::PointXYZ>::Ptr kdTree(new pcl::search::KdTree<pcl::PointXYZ>);
01589                 kdTree->setInputCloud(cloud);
01590                 std::vector<int> ind;
01591                 std::vector<float> sqrdDist;
01592                 pcl::PointXYZ pt(fromT.x(), fromT.y(), fromT.z());
01593                 kdTree->radiusSearch(pt, radius, ind, sqrdDist, 0);
01594 
01595                 Eigen::Vector3f vA = fromT.toEigen3f().rotation()*Eigen::Vector3f(1,0,0);
01596 
01597                 for(unsigned int i=0; i<ind.size(); ++i)
01598                 {
01599                         if(ind[i] >=0)
01600                         {
01601                                 if(angle > 0.0f)
01602                                 {
01603                                         const Transform & checkT = nodes.at(ids[ind[i]]);
01604                                         // same orientation?
01605                                         Eigen::Vector3f vB = checkT.toEigen3f().rotation()*Eigen::Vector3f(1,0,0);
01606                                         double a = pcl::getAngle3D(Eigen::Vector4f(vA[0], vA[1], vA[2], 0), Eigen::Vector4f(vB[0], vB[1], vB[2], 0));
01607                                         if(a <= angle)
01608                                         {
01609                                                 foundNodes.insert(std::make_pair(ids[ind[i]], nodes.at(ids[ind[i]])));
01610                                         }
01611                                 }
01612                                 else
01613                                 {
01614                                         foundNodes.insert(std::make_pair(ids[ind[i]], nodes.at(ids[ind[i]])));
01615                                 }
01616                         }
01617                 }
01618         }
01619         UDEBUG("found nodes=%d", (int)foundNodes.size());
01620         return foundNodes;
01621 }
01622 
01623 float computePathLength(
01624                 const std::vector<std::pair<int, Transform> > & path,
01625                 unsigned int fromIndex,
01626                 unsigned int toIndex)
01627 {
01628         float length = 0.0f;
01629         if(path.size() > 1)
01630         {
01631                 UASSERT(fromIndex  < path.size() && toIndex < path.size() && fromIndex <= toIndex);
01632                 if(fromIndex >= toIndex)
01633                 {
01634                         toIndex = (unsigned int)path.size()-1;
01635                 }
01636                 float x=0, y=0, z=0;
01637                 for(unsigned int i=fromIndex; i<toIndex-1; ++i)
01638                 {
01639                         x += fabs(path[i].second.x() - path[i+1].second.x());
01640                         y += fabs(path[i].second.y() - path[i+1].second.y());
01641                         z += fabs(path[i].second.z() - path[i+1].second.z());
01642                 }
01643                 length = sqrt(x*x + y*y + z*z);
01644         }
01645         return length;
01646 }
01647 
01648 // return all paths linked only by neighbor links
01649 std::list<std::map<int, Transform> > getPaths(
01650                 std::map<int, Transform> poses,
01651                 const std::multimap<int, Link> & links)
01652 {
01653         std::list<std::map<int, Transform> > paths;
01654         if(poses.size() && links.size())
01655         {
01656                 // Segment poses connected only by neighbor links
01657                 while(poses.size())
01658                 {
01659                         std::map<int, Transform> path;
01660                         for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end();)
01661                         {
01662                                 std::multimap<int, Link>::const_iterator jter = findLink(links, path.rbegin()->first, iter->first);
01663                                 if(path.size() == 0 || (jter != links.end() && (jter->second.type() == Link::kNeighbor || jter->second.type() == Link::kNeighborMerged)))
01664                                 {
01665                                         path.insert(*iter);
01666                                         poses.erase(iter++);
01667                                 }
01668                                 else
01669                                 {
01670                                         break;
01671                                 }
01672                         }
01673                         UASSERT(path.size());
01674                         paths.push_back(path);
01675                 }
01676 
01677         }
01678         return paths;
01679 }
01680 
01681 } /* namespace graph */
01682 
01683 } /* namespace rtabmap */


rtabmap
Author(s): Mathieu Labbe
autogenerated on Sat Jul 23 2016 11:44:16