00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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,
00055 const std::map<int, Transform> & poses,
00056 const std::multimap<int, Link> & constraints,
00057 const std::map<int, double> & stamps,
00058 bool g2oRobust)
00059 {
00060 UDEBUG("%s", filePath.c_str());
00061 std::string tmpPath = filePath;
00062 if(format==3)
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)
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)
00110 {
00111
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
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
00136 {
00137 Transform pose = iter->second;
00138 if(format == 2)
00139 {
00140
00141
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
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,
00169 std::map<int, Transform> & poses,
00170 std::multimap<int, Link> * constraints,
00171 std::map<int, double> * stamps)
00172 {
00173 UDEBUG("%s format=%d", filePath.c_str(), format);
00174 if(format==3)
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)
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)
00215 {
00216 std::vector<std::string> strList = uListToVector(uSplit(str));
00217 if(strList.size() == 10)
00218 {
00219
00220
00221
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;
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)
00247 {
00248 std::vector<std::string> strList = uListToVector(uSplit(str));
00249 if(strList.size() == 12)
00250 {
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
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
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)
00297 {
00298 std::vector<std::string> strList = uListToVector(uSplit(str));
00299 if(strList.size() == 25)
00300 {
00301
00302
00303
00304
00305
00306
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
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)
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
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;
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)
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
00394
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
00412 {
00413 Transform pose = Transform::fromString(str);
00414 if(format == 2)
00415 {
00416
00417
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
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
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
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
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
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,
00598 float verticalFOV,
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
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
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
00732
00733 UINFO("Cloud filtered In = %d, Out = %d", cloud->size(), indicesKept.size());
00734
00735
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
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
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
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,
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
00836 }
00837 }
00838 }
00839
00840 UINFO("Clustering hyper nodes...");
00841
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
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
00915 hyperLinks.erase(tmpIter);
00916 }
00917
00918
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
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_;}
01015 float distToEnd() const {return distToEnd_;}
01016 float totalCost() const {return costSoFar_ + distToEnd_;}
01017 rtabmap::Transform pose() const {return pose_;}
01018 float distFrom(const rtabmap::Transform & pose) const
01019 {
01020 return pose_.getDistance(pose);
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;
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
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
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
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
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
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
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
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,
01263 float angularVelocity)
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
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
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
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
01351 cost = iter->second.transform().getNorm();
01352 }
01353 else
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
01390 nodeIter->second.setPose(nextPose);
01391
01392
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
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
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
01431
01432
01433
01434
01435
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
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
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
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
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
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 }
01682
01683 }