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 <pcl/search/kdtree.h>
00034 #include <pcl/common/eigen.h>
00035 #include <pcl/common/common.h>
00036 #include <set>
00037 #include <queue>
00038 #include "toro3d/treeoptimizer3.hh"
00039 #include "toro3d/treeoptimizer2.hh"
00040
00041 #ifdef WITH_G2O
00042 #include "g2o/core/sparse_optimizer.h"
00043 #include "g2o/core/block_solver.h"
00044 #include "g2o/core/factory.h"
00045 #include "g2o/core/optimization_algorithm_factory.h"
00046 #include "g2o/core/optimization_algorithm_gauss_newton.h"
00047 #include "g2o/core/optimization_algorithm_levenberg.h"
00048 #include "g2o/solvers/csparse/linear_solver_csparse.h"
00049 #include "g2o/types/slam3d/vertex_se3.h"
00050 #include "g2o/types/slam3d/edge_se3.h"
00051 #include "g2o/types/slam2d/vertex_se2.h"
00052 #include "g2o/types/slam2d/edge_se2.h"
00053 #endif
00054
00055 namespace rtabmap {
00056
00057 namespace graph {
00058
00060
00062
00063 Optimizer * Optimizer::create(const ParametersMap & parameters)
00064 {
00065 int optimizerTypeInt = Parameters::defaultRGBDOptimizeStrategy();
00066 Parameters::parse(parameters, Parameters::kRGBDOptimizeStrategy(), optimizerTypeInt);
00067 graph::Optimizer::Type type = (graph::Optimizer::Type)optimizerTypeInt;
00068
00069 if(!G2OOptimizer::available() && type == Optimizer::kTypeG2O)
00070 {
00071 UWARN("g2o optimizer not available. TORO will be used instead.");
00072 type = Optimizer::kTypeTORO;
00073 }
00074 Optimizer * optimizer = 0;
00075 switch(type)
00076 {
00077 case Optimizer::kTypeG2O:
00078 optimizer = new G2OOptimizer(parameters);
00079 break;
00080 case Optimizer::kTypeTORO:
00081 default:
00082 optimizer = new TOROOptimizer(parameters);
00083 type = Optimizer::kTypeTORO;
00084 break;
00085
00086 }
00087 return optimizer;
00088 }
00089
00090 Optimizer * Optimizer::create(Optimizer::Type & type, const ParametersMap & parameters)
00091 {
00092 if(!G2OOptimizer::available() && type == Optimizer::kTypeG2O)
00093 {
00094 UWARN("g2o optimizer not available. TORO will be used instead.");
00095 type = Optimizer::kTypeTORO;
00096 }
00097 Optimizer * optimizer = 0;
00098 switch(type)
00099 {
00100 case Optimizer::kTypeG2O:
00101 optimizer = new G2OOptimizer(parameters);
00102 break;
00103 case Optimizer::kTypeTORO:
00104 default:
00105 optimizer = new TOROOptimizer(parameters);
00106 type = Optimizer::kTypeTORO;
00107 break;
00108
00109 }
00110 return optimizer;
00111 }
00112
00113 Optimizer::Optimizer(int iterations, bool slam2d, bool covarianceIgnored) :
00114 iterations_(iterations),
00115 slam2d_(slam2d),
00116 covarianceIgnored_(covarianceIgnored)
00117 {
00118 }
00119
00120 Optimizer::Optimizer(const ParametersMap & parameters) :
00121 iterations_(100),
00122 slam2d_(false),
00123 covarianceIgnored_(false)
00124 {
00125 parseParameters(parameters);
00126 }
00127
00128 void Optimizer::parseParameters(const ParametersMap & parameters)
00129 {
00130 Parameters::parse(parameters, Parameters::kRGBDOptimizeIterations(), iterations_);
00131 Parameters::parse(parameters, Parameters::kRGBDOptimizeVarianceIgnored(), covarianceIgnored_);
00132 Parameters::parse(parameters, Parameters::kRGBDOptimizeSlam2D(), slam2d_);
00133 }
00134
00135 void Optimizer::getConnectedGraph(
00136 int fromId,
00137 const std::map<int, Transform> & posesIn,
00138 const std::multimap<int, Link> & linksIn,
00139 std::map<int, Transform> & posesOut,
00140 std::multimap<int, Link> & linksOut,
00141 int depth)
00142 {
00143 UASSERT(depth >= 0);
00144 UASSERT(fromId>0);
00145 UASSERT(uContains(posesIn, fromId));
00146
00147 posesOut.clear();
00148 linksOut.clear();
00149
00150 std::set<int> ids;
00151 std::set<int> curentDepth;
00152 std::set<int> nextDepth;
00153 nextDepth.insert(fromId);
00154 int d = 0;
00155 while((depth == 0 || d < depth) && nextDepth.size())
00156 {
00157 curentDepth = nextDepth;
00158 nextDepth.clear();
00159
00160 for(std::set<int>::iterator jter = curentDepth.begin(); jter!=curentDepth.end(); ++jter)
00161 {
00162 if(ids.find(*jter) == ids.end())
00163 {
00164 ids.insert(*jter);
00165 posesOut.insert(*posesIn.find(*jter));
00166
00167 for(std::multimap<int, Link>::const_iterator iter=linksIn.begin(); iter!=linksIn.end(); ++iter)
00168 {
00169 if(iter->second.from() == *jter)
00170 {
00171 if(ids.find(iter->second.to()) == ids.end() && uContains(posesIn, iter->second.to()))
00172 {
00173 nextDepth.insert(iter->second.to());
00174 if(depth == 0 || d < depth-1)
00175 {
00176 linksOut.insert(*iter);
00177 }
00178 else if(curentDepth.find(iter->second.to()) != curentDepth.end() ||
00179 ids.find(iter->second.to()) != ids.end())
00180 {
00181 linksOut.insert(*iter);
00182 }
00183 }
00184 }
00185 else if(iter->second.to() == *jter)
00186 {
00187 if(ids.find(iter->second.from()) == ids.end() && uContains(posesIn, iter->second.from()))
00188 {
00189 nextDepth.insert(iter->second.from());
00190
00191 if(depth == 0 || d < depth-1)
00192 {
00193 linksOut.insert(*iter);
00194 }
00195 else if(curentDepth.find(iter->second.from()) != curentDepth.end() ||
00196 ids.find(iter->second.from()) != ids.end())
00197 {
00198 linksOut.insert(*iter);
00199 }
00200 }
00201 }
00202 }
00203 }
00204 }
00205 ++d;
00206 }
00207 }
00208
00210
00212 std::map<int, Transform> TOROOptimizer::optimize(
00213 int rootId,
00214 const std::map<int, Transform> & poses,
00215 const std::multimap<int, Link> & edgeConstraints,
00216 std::list<std::map<int, Transform> > * intermediateGraphes)
00217 {
00218 std::map<int, Transform> optimizedPoses;
00219 UDEBUG("Optimizing graph (pose=%d constraints=%d)...", (int)poses.size(), (int)edgeConstraints.size());
00220 if(edgeConstraints.size()>=1 && poses.size()>=2 && iterations() > 0)
00221 {
00222
00223 AISNavigation::TreeOptimizer2 pg2;
00224 AISNavigation::TreeOptimizer3 pg3;
00225 pg2.verboseLevel = 0;
00226 pg3.verboseLevel = 0;
00227
00228 UDEBUG("fill poses to TORO...");
00229 if(isSlam2d())
00230 {
00231 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00232 {
00233 UASSERT(!iter->second.isNull());
00234 AISNavigation::TreePoseGraph2::Pose p(iter->second.x(), iter->second.y(), iter->second.theta());
00235 AISNavigation::TreePoseGraph2::Vertex* v = pg2.addVertex(iter->first, p);
00236 UASSERT_MSG(v != 0, uFormat("cannot insert vertex %d!?", iter->first).c_str());
00237 }
00238 }
00239 else
00240 {
00241 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00242 {
00243 UASSERT(!iter->second.isNull());
00244 float x,y,z, roll,pitch,yaw;
00245 iter->second.getTranslationAndEulerAngles(x,y,z, roll,pitch,yaw);
00246 AISNavigation::TreePoseGraph3::Pose p(x, y, z, roll, pitch, yaw);
00247 AISNavigation::TreePoseGraph3::Vertex* v = pg3.addVertex(iter->first, p);
00248 UASSERT_MSG(v != 0, uFormat("cannot insert vertex %d!?", iter->first).c_str());
00249 v->transformation=AISNavigation::TreePoseGraph3::Transformation(p);
00250 }
00251
00252 }
00253
00254 UDEBUG("fill edges to TORO...");
00255 if(isSlam2d())
00256 {
00257 for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
00258 {
00259 UASSERT(!iter->second.transform().isNull());
00260 AISNavigation::TreePoseGraph2::Pose p(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().theta());
00261 AISNavigation::TreePoseGraph2::InformationMatrix inf;
00262
00263 inf.values[0][0] = 1.0f; inf.values[0][1] = 0.0f; inf.values[0][2] = 0.0f;
00264 inf.values[1][0] = 0.0f; inf.values[1][1] = 1.0f; inf.values[1][2] = 0.0f;
00265 inf.values[2][0] = 0.0f; inf.values[2][1] = 0.0f; inf.values[2][2] = 1.0f;
00266 if(!isCovarianceIgnored())
00267 {
00268 if(iter->second.transVariance()>0)
00269 {
00270 inf.values[0][0] = 1.0f/iter->second.transVariance();
00271 inf.values[1][1] = 1.0f/iter->second.transVariance();
00272 }
00273 if(iter->second.rotVariance()>0)
00274 {
00275 inf.values[2][2] = 1.0f/iter->second.rotVariance();
00276 }
00277 }
00278
00279 int id1 = iter->first;
00280 int id2 = iter->second.to();
00281 AISNavigation::TreePoseGraph2::Vertex* v1=pg2.vertex(id1);
00282 AISNavigation::TreePoseGraph2::Vertex* v2=pg2.vertex(id2);
00283 UASSERT(v1 != 0);
00284 UASSERT(v2 != 0);
00285 AISNavigation::TreePoseGraph2::Transformation t(p);
00286 if (!pg2.addEdge(v1, v2, t, inf))
00287 {
00288 UERROR("Map: Edge already exits between nodes %d and %d, skipping", id1, id2);
00289 }
00290 }
00291 }
00292 else
00293 {
00294 for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
00295 {
00296 UASSERT(!iter->second.transform().isNull());
00297 float x,y,z, roll,pitch,yaw;
00298 iter->second.transform().getTranslationAndEulerAngles(x,y,z, roll,pitch,yaw);
00299
00300 AISNavigation::TreePoseGraph3::Pose p(x, y, z, roll, pitch, yaw);
00301 AISNavigation::TreePoseGraph3::InformationMatrix inf = DMatrix<double>::I(6);
00302 if(!isCovarianceIgnored())
00303 {
00304 if(iter->second.rotVariance()>0)
00305 {
00306 inf[0][0] = 1.0f/iter->second.rotVariance();
00307 inf[1][1] = 1.0f/iter->second.rotVariance();
00308 inf[2][2] = 1.0f/iter->second.rotVariance();
00309 }
00310 if(iter->second.transVariance()>0)
00311 {
00312 inf[3][3] = 1.0f/iter->second.transVariance();
00313 inf[4][4] = 1.0f/iter->second.transVariance();
00314 inf[5][5] = 1.0f/iter->second.transVariance();
00315 }
00316 }
00317
00318 int id1 = iter->first;
00319 int id2 = iter->second.to();
00320 AISNavigation::TreePoseGraph3::Vertex* v1=pg3.vertex(id1);
00321 AISNavigation::TreePoseGraph3::Vertex* v2=pg3.vertex(id2);
00322 UASSERT(v1 != 0);
00323 UASSERT(v2 != 0);
00324 AISNavigation::TreePoseGraph3::Transformation t(p);
00325 if (!pg3.addEdge(v1, v2, t, inf))
00326 {
00327 UERROR("Map: Edge already exits between nodes %d and %d, skipping", id1, id2);
00328 }
00329 }
00330 }
00331 UDEBUG("buildMST...");
00332 UASSERT(uContains(poses, rootId));
00333 if(isSlam2d())
00334 {
00335 pg2.buildMST(rootId);
00336 pg2.initializeOnTree();
00337 pg2.initializeTreeParameters();
00338 UDEBUG("Building TORO tree... (if a crash happens just after this msg, "
00339 "TORO is not able to find the root of the graph!)");
00340 pg2.initializeOptimization();
00341 }
00342 else
00343 {
00344 pg3.buildMST(rootId);
00345 pg3.initializeOnTree();
00346 pg3.initializeTreeParameters();
00347 UDEBUG("Building TORO tree... (if a crash happens just after this msg, "
00348 "TORO is not able to find the root of the graph!)");
00349 pg3.initializeOptimization();
00350 }
00351
00352 UINFO("TORO iterate begin (iterations=%d)", iterations());
00353 for (int i=0; i<iterations(); i++)
00354 {
00355 if(intermediateGraphes && i>0)
00356 {
00357 std::map<int, Transform> tmpPoses;
00358 if(isSlam2d())
00359 {
00360 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00361 {
00362 AISNavigation::TreePoseGraph2::Vertex* v=pg2.vertex(iter->first);
00363 float roll, pitch, yaw;
00364 iter->second.getEulerAngles(roll, pitch, yaw);
00365 Transform newPose(v->pose.x(), v->pose.y(), iter->second.z(), roll, pitch, v->pose.theta());
00366
00367 UASSERT_MSG(!newPose.isNull(), uFormat("Optimized pose %d is null!?!?", iter->first).c_str());
00368 tmpPoses.insert(std::pair<int, Transform>(iter->first, newPose));
00369 }
00370 }
00371 else
00372 {
00373 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00374 {
00375 AISNavigation::TreePoseGraph3::Vertex* v=pg3.vertex(iter->first);
00376 AISNavigation::TreePoseGraph3::Pose pose=v->transformation.toPoseType();
00377 Transform newPose(pose.x(), pose.y(), pose.z(), pose.roll(), pose.pitch(), pose.yaw());
00378
00379 UASSERT_MSG(!newPose.isNull(), uFormat("Optimized pose %d is null!?!?", iter->first).c_str());
00380 tmpPoses.insert(std::pair<int, Transform>(iter->first, newPose));
00381 }
00382 }
00383 intermediateGraphes->push_back(tmpPoses);
00384 }
00385 if(isSlam2d())
00386 {
00387 pg2.iterate();
00388
00389
00390 double error=pg2.error();
00391 UDEBUG("iteration %d global error=%f error/constraint=%f", i, error, error/pg2.edges.size());
00392 }
00393 else
00394 {
00395 pg3.iterate();
00396
00397
00398 double mte, mre, are, ate;
00399 double error=pg3.error(&mre, &mte, &are, &ate);
00400 UDEBUG("i %d RotGain=%f global error=%f error/constraint=%f",
00401 i, pg3.getRotGain(), error, error/pg3.edges.size());
00402 }
00403 }
00404 UINFO("TORO iterate end");
00405
00406 if(isSlam2d())
00407 {
00408 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00409 {
00410 AISNavigation::TreePoseGraph2::Vertex* v=pg2.vertex(iter->first);
00411 float roll, pitch, yaw;
00412 iter->second.getEulerAngles(roll, pitch, yaw);
00413 Transform newPose(v->pose.x(), v->pose.y(), iter->second.z(), roll, pitch, v->pose.theta());
00414
00415 UASSERT_MSG(!newPose.isNull(), uFormat("Optimized pose %d is null!?!?", iter->first).c_str());
00416 optimizedPoses.insert(std::pair<int, Transform>(iter->first, newPose));
00417 }
00418 }
00419 else
00420 {
00421 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00422 {
00423 AISNavigation::TreePoseGraph3::Vertex* v=pg3.vertex(iter->first);
00424 AISNavigation::TreePoseGraph3::Pose pose=v->transformation.toPoseType();
00425 Transform newPose(pose.x(), pose.y(), pose.z(), pose.roll(), pose.pitch(), pose.yaw());
00426
00427 UASSERT_MSG(!newPose.isNull(), uFormat("Optimized pose %d is null!?!?", iter->first).c_str());
00428 optimizedPoses.insert(std::pair<int, Transform>(iter->first, newPose));
00429 }
00430 }
00431 }
00432 else if(poses.size() == 1 || iterations() <= 0)
00433 {
00434 optimizedPoses = poses;
00435 }
00436 else
00437 {
00438 UWARN("This method should be called at least with 1 pose!");
00439 }
00440 UDEBUG("Optimizing graph...end!");
00441 return optimizedPoses;
00442 }
00443
00444 bool TOROOptimizer::saveGraph(
00445 const std::string & fileName,
00446 const std::map<int, Transform> & poses,
00447 const std::multimap<int, Link> & edgeConstraints)
00448 {
00449 FILE * file = 0;
00450
00451 #ifdef _MSC_VER
00452 fopen_s(&file, fileName.c_str(), "w");
00453 #else
00454 file = fopen(fileName.c_str(), "w");
00455 #endif
00456
00457 if(file)
00458 {
00459
00460 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00461 {
00462 float x,y,z, yaw,pitch,roll;
00463 pcl::getTranslationAndEulerAngles(iter->second.toEigen3f(), x,y,z, roll, pitch, yaw);
00464 fprintf(file, "VERTEX3 %d %f %f %f %f %f %f\n",
00465 iter->first,
00466 x,
00467 y,
00468 z,
00469 roll,
00470 pitch,
00471 yaw);
00472 }
00473
00474
00475 for(std::multimap<int, Link>::const_iterator iter = edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
00476 {
00477 float x,y,z, yaw,pitch,roll;
00478 pcl::getTranslationAndEulerAngles(iter->second.transform().toEigen3f(), x,y,z, roll, pitch, yaw);
00479 fprintf(file, "EDGE3 %d %d %f %f %f %f %f %f %f 0 0 0 0 0 %f 0 0 0 0 %f 0 0 0 %f 0 0 %f 0 %f\n",
00480 iter->first,
00481 iter->second.to(),
00482 x,
00483 y,
00484 z,
00485 roll,
00486 pitch,
00487 yaw,
00488 iter->second.rotVariance()>0?1.0f/iter->second.rotVariance():1.0f,
00489 iter->second.rotVariance()>0?1.0f/iter->second.rotVariance():1.0f,
00490 iter->second.rotVariance()>0?1.0f/iter->second.rotVariance():1.0f,
00491 iter->second.transVariance()>0?1.0f/iter->second.transVariance():1.0f,
00492 iter->second.transVariance()>0?1.0f/iter->second.transVariance():1.0f,
00493 iter->second.transVariance()>0?1.0f/iter->second.transVariance():1.0f);
00494 }
00495 UINFO("Graph saved to %s", fileName.c_str());
00496 fclose(file);
00497 }
00498 else
00499 {
00500 UERROR("Cannot save to file %s", fileName.c_str());
00501 return false;
00502 }
00503 return true;
00504 }
00505
00506 bool TOROOptimizer::loadGraph(
00507 const std::string & fileName,
00508 std::map<int, Transform> & poses,
00509 std::multimap<int, Link> & edgeConstraints)
00510 {
00511 FILE * file = 0;
00512 #ifdef _MSC_VER
00513 fopen_s(&file, fileName.c_str(), "r");
00514 #else
00515 file = fopen(fileName.c_str(), "r");
00516 #endif
00517
00518 if(file)
00519 {
00520 char line[400];
00521 while ( fgets (line , 400 , file) != NULL )
00522 {
00523 std::vector<std::string> strList = uListToVector(uSplit(uReplaceChar(line, '\n', ' '), ' '));
00524 if(strList.size() == 8)
00525 {
00526
00527 int id = atoi(strList[1].c_str());
00528 float x = uStr2Float(strList[2]);
00529 float y = uStr2Float(strList[3]);
00530 float z = uStr2Float(strList[4]);
00531 float roll = uStr2Float(strList[5]);
00532 float pitch = uStr2Float(strList[6]);
00533 float yaw = uStr2Float(strList[7]);
00534 Transform pose = Transform::fromEigen3f(pcl::getTransformation(x, y, z, roll, pitch, yaw));
00535 if(poses.find(id) == poses.end())
00536 {
00537 poses.insert(std::make_pair(id, pose));
00538 }
00539 else
00540 {
00541 UFATAL("Pose %d already added", id);
00542 }
00543 }
00544 else if(strList.size() == 30)
00545 {
00546
00547 int idFrom = atoi(strList[1].c_str());
00548 int idTo = atoi(strList[2].c_str());
00549 float x = uStr2Float(strList[3]);
00550 float y = uStr2Float(strList[4]);
00551 float z = uStr2Float(strList[5]);
00552 float roll = uStr2Float(strList[6]);
00553 float pitch = uStr2Float(strList[7]);
00554 float yaw = uStr2Float(strList[8]);
00555 float infR = uStr2Float(strList[9]);
00556 float infP = uStr2Float(strList[15]);
00557 float infW = uStr2Float(strList[20]);
00558 UASSERT_MSG(infR > 0 && infP > 0 && infW > 0, uFormat("Information matrix should not be null! line=\"%s\"", line).c_str());
00559 float rotVariance = infR<=infP && infR<=infW?infR:infP<=infW?infP:infW;
00560 float infX = uStr2Float(strList[24]);
00561 float infY = uStr2Float(strList[27]);
00562 float infZ = uStr2Float(strList[29]);
00563 UASSERT_MSG(infX > 0 && infY > 0 && infZ > 0, uFormat("Information matrix should not be null! line=\"%s\"", line).c_str());
00564 float transVariance = 1.0f/(infX<=infY && infX<=infZ?infX:infY<=infW?infY:infZ);
00565 UINFO("id=%d rotV=%f transV=%f", idFrom, rotVariance, transVariance);
00566 Transform transform = Transform::fromEigen3f(pcl::getTransformation(x, y, z, roll, pitch, yaw));
00567 if(poses.find(idFrom) != poses.end() && poses.find(idTo) != poses.end())
00568 {
00569
00570 Link link(idFrom, idTo, Link::kUndef, transform, rotVariance, transVariance);
00571 edgeConstraints.insert(std::pair<int, Link>(idFrom, link));
00572 }
00573 else
00574 {
00575 UFATAL("Referred poses from the link not exist!");
00576 }
00577 }
00578 else if(strList.size())
00579 {
00580 UFATAL("Error parsing graph file %s on line \"%s\" (strList.size()=%d)", fileName.c_str(), line, (int)strList.size());
00581 }
00582 }
00583
00584 UINFO("Graph loaded from %s", fileName.c_str());
00585 fclose(file);
00586 }
00587 else
00588 {
00589 UERROR("Cannot open file %s", fileName.c_str());
00590 return false;
00591 }
00592 return true;
00593 }
00594
00595
00597
00599 bool G2OOptimizer::available()
00600 {
00601 #ifdef WITH_G2O
00602 return true;
00603 #else
00604 return false;
00605 #endif
00606 }
00607
00608 std::map<int, Transform> G2OOptimizer::optimize(
00609 int rootId,
00610 const std::map<int, Transform> & poses,
00611 const std::multimap<int, Link> & edgeConstraints,
00612 std::list<std::map<int, Transform> > * intermediateGraphes)
00613 {
00614 std::map<int, Transform> optimizedPoses;
00615 #ifdef WITH_G2O
00616 UDEBUG("Optimizing graph...");
00617 optimizedPoses.clear();
00618 if(edgeConstraints.size()>=1 && poses.size()>=2 && iterations() > 0)
00619 {
00620
00621
00622
00623 g2o::BlockSolverX::LinearSolverType * linearSolver = new g2o::LinearSolverCSparse<g2o::BlockSolverX::PoseMatrixType>();
00624
00625
00626 g2o::BlockSolverX* blockSolver = new g2o::BlockSolverX(linearSolver);
00627
00628
00629
00630 g2o::OptimizationAlgorithmLevenberg* optimizationAlgorithm = new g2o::OptimizationAlgorithmLevenberg(blockSolver);
00631
00632
00633 g2o::SparseOptimizer optimizer;
00634 optimizer.setVerbose(false);
00635 optimizer.setAlgorithm(optimizationAlgorithm);
00636
00637 UDEBUG("fill poses to g2o...");
00638 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00639 {
00640 UASSERT(!iter->second.isNull());
00641 g2o::HyperGraph::Vertex * vertex = 0;
00642 if(isSlam2d())
00643 {
00644 g2o::VertexSE2 * v2 = new g2o::VertexSE2();
00645 v2->setEstimate(g2o::SE2(iter->second.x(), iter->second.y(), iter->second.theta()));
00646 vertex = v2;
00647 }
00648 else
00649 {
00650 g2o::VertexSE3 * v3 = new g2o::VertexSE3();
00651 Eigen::Isometry3d pose;
00652 Eigen::Affine3d a = iter->second.toEigen3d();
00653 pose.translation() = a.translation();
00654 pose.linear() = a.rotation();
00655 v3->setEstimate(pose);
00656 vertex = v3;
00657 }
00658 vertex->setId(iter->first);
00659 UASSERT_MSG(optimizer.addVertex(vertex), uFormat("cannot insert vertex %d!?", iter->first).c_str());
00660 }
00661
00662 UDEBUG("fill edges to g2o...");
00663 for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
00664 {
00665 int id1 = iter->first;
00666 int id2 = iter->second.to();
00667
00668 UASSERT(!iter->second.transform().isNull());
00669
00670 g2o::HyperGraph::Edge * edge = 0;
00671
00672 if(isSlam2d())
00673 {
00674 Eigen::Matrix<double, 3, 3> information = Eigen::Matrix<double, 3, 3>::Identity();
00675 if(!isCovarianceIgnored())
00676 {
00677 if(iter->second.transVariance()>0)
00678 {
00679 information(0,0) = 1.0f/iter->second.transVariance();
00680 information(1,1) = 1.0f/iter->second.transVariance();
00681 }
00682 if(iter->second.rotVariance()>0)
00683 {
00684 information(2,2) = 1.0f/iter->second.rotVariance();
00685 }
00686 }
00687
00688 g2o::EdgeSE2 * e = new g2o::EdgeSE2();
00689 g2o::VertexSE2* v1 = (g2o::VertexSE2*)optimizer.vertex(id1);
00690 g2o::VertexSE2* v2 = (g2o::VertexSE2*)optimizer.vertex(id2);
00691 UASSERT(v1 != 0);
00692 UASSERT(v2 != 0);
00693 e->setVertex(0, v1);
00694 e->setVertex(1, v2);
00695 e->setMeasurement(g2o::SE2(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().theta()));
00696 e->setInformation(information);
00697 edge = e;
00698 }
00699 else
00700 {
00701 Eigen::Matrix<double, 6, 6> information = Eigen::Matrix<double, 6, 6>::Identity();
00702 if(!isCovarianceIgnored())
00703 {
00704 if(iter->second.transVariance()>0)
00705 {
00706 information(0,0) = 1.0f/iter->second.transVariance();
00707 information(1,1) = 1.0f/iter->second.transVariance();
00708 information(2,2) = 1.0f/iter->second.transVariance();
00709 }
00710 if(iter->second.rotVariance()>0)
00711 {
00712 information(3,3) = 1.0f/iter->second.rotVariance();
00713 information(4,4) = 1.0f/iter->second.rotVariance();
00714 information(5,5) = 1.0f/iter->second.rotVariance();
00715 }
00716 }
00717
00718 Eigen::Affine3d a = iter->second.transform().toEigen3d();
00719 Eigen::Isometry3d constraint;
00720 constraint.translation() = a.translation();
00721 constraint.linear() = a.rotation();
00722
00723 g2o::EdgeSE3 * e = new g2o::EdgeSE3();
00724 g2o::VertexSE3* v1 = (g2o::VertexSE3*)optimizer.vertex(id1);
00725 g2o::VertexSE3* v2 = (g2o::VertexSE3*)optimizer.vertex(id2);
00726 UASSERT(v1 != 0);
00727 UASSERT(v2 != 0);
00728 e->setVertex(0, v1);
00729 e->setVertex(1, v2);
00730 e->setMeasurement(constraint);
00731 e->setInformation(information);
00732 edge = e;
00733 }
00734
00735 if (!optimizer.addEdge(edge))
00736 {
00737 delete edge;
00738 UERROR("Map: Failed adding constraint between %d and %d, skipping", id1, id2);
00739 }
00740 }
00741
00742 UDEBUG("Initial optimization...");
00743 UASSERT(uContains(poses, rootId));
00744 if(isSlam2d())
00745 {
00746 g2o::VertexSE2* firstRobotPose = (g2o::VertexSE2*)optimizer.vertex(rootId);
00747 UASSERT(firstRobotPose != 0);
00748 firstRobotPose->setFixed(true);
00749 }
00750 else
00751 {
00752 g2o::VertexSE3* firstRobotPose = (g2o::VertexSE3*)optimizer.vertex(rootId);
00753 UASSERT(firstRobotPose != 0);
00754 firstRobotPose->setFixed(true);
00755 }
00756
00757 UINFO("g2o iterate begin (max iterations=%d)", iterations());
00758 int it = 0;
00759 if(intermediateGraphes)
00760 {
00761 optimizer.initializeOptimization();
00762 for(int i=0; i<iterations(); ++i)
00763 {
00764 if(i > 0)
00765 {
00766 std::map<int, Transform> tmpPoses;
00767 if(isSlam2d())
00768 {
00769 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00770 {
00771 const g2o::VertexSE2* v = (const g2o::VertexSE2*)optimizer.vertex(iter->first);
00772 if(v)
00773 {
00774 float roll, pitch, yaw;
00775 iter->second.getEulerAngles(roll, pitch, yaw);
00776 Transform t(v->estimate().translation()[0], v->estimate().translation()[1], iter->second.z(), roll, pitch, v->estimate().rotation().angle());
00777 tmpPoses.insert(std::pair<int, Transform>(iter->first, t));
00778 UASSERT_MSG(!t.isNull(), uFormat("Optimized pose %d is null!?!?", iter->first).c_str());
00779 }
00780 else
00781 {
00782 UERROR("Vertex %d not found!?", iter->first);
00783 }
00784 }
00785 }
00786 else
00787 {
00788 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00789 {
00790 const g2o::VertexSE3* v = (const g2o::VertexSE3*)optimizer.vertex(iter->first);
00791 if(v)
00792 {
00793 Transform t = Transform::fromEigen3d(v->estimate());
00794 tmpPoses.insert(std::pair<int, Transform>(iter->first, t));
00795 UASSERT_MSG(!t.isNull(), uFormat("Optimized pose %d is null!?!?", iter->first).c_str());
00796 }
00797 else
00798 {
00799 UERROR("Vertex %d not found!?", iter->first);
00800 }
00801 }
00802 }
00803 intermediateGraphes->push_back(tmpPoses);
00804 }
00805
00806 it += optimizer.optimize(1);
00807 if(ULogger::level() == ULogger::kDebug)
00808 {
00809 optimizer.computeActiveErrors();
00810 UDEBUG("iteration %d: %d nodes, %d edges, chi2: %f", i, (int)optimizer.vertices().size(), (int)optimizer.edges().size(), optimizer.chi2());
00811 }
00812 }
00813 }
00814 else
00815 {
00816 optimizer.initializeOptimization();
00817 it = optimizer.optimize(iterations());
00818 optimizer.computeActiveErrors();
00819 UDEBUG("%d nodes, %d edges, chi2: %f", (int)optimizer.vertices().size(), (int)optimizer.edges().size(), optimizer.chi2());
00820 }
00821 UINFO("g2o iterate end (%d iterations done)", it);
00822
00823 if(isSlam2d())
00824 {
00825 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00826 {
00827 const g2o::VertexSE2* v = (const g2o::VertexSE2*)optimizer.vertex(iter->first);
00828 if(v)
00829 {
00830 float roll, pitch, yaw;
00831 iter->second.getEulerAngles(roll, pitch, yaw);
00832 Transform t(v->estimate().translation()[0], v->estimate().translation()[1], iter->second.z(), roll, pitch, v->estimate().rotation().angle());
00833 optimizedPoses.insert(std::pair<int, Transform>(iter->first, t));
00834 UASSERT_MSG(!t.isNull(), uFormat("Optimized pose %d is null!?!?", iter->first).c_str());
00835 }
00836 else
00837 {
00838 UERROR("Vertex %d not found!?", iter->first);
00839 }
00840 }
00841 }
00842 else
00843 {
00844 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00845 {
00846 const g2o::VertexSE3* v = (const g2o::VertexSE3*)optimizer.vertex(iter->first);
00847 if(v)
00848 {
00849 Transform t = Transform::fromEigen3d(v->estimate());
00850 optimizedPoses.insert(std::pair<int, Transform>(iter->first, t));
00851 UASSERT_MSG(!t.isNull(), uFormat("Optimized pose %d is null!?!?", iter->first).c_str());
00852 }
00853 else
00854 {
00855 UERROR("Vertex %d not found!?", iter->first);
00856 }
00857 }
00858 }
00859 optimizer.clear();
00860 g2o::Factory::destroy();
00861 g2o::OptimizationAlgorithmFactory::destroy();
00862 g2o::HyperGraphActionLibrary::destroy();
00863 }
00864 else if(poses.size() == 1 || iterations() <= 0)
00865 {
00866 optimizedPoses = poses;
00867 }
00868 else
00869 {
00870 UWARN("This method should be called at least with 1 pose!");
00871 }
00872 UDEBUG("Optimizing graph...end!");
00873 #else
00874 UERROR("Not built with G2O support!");
00875 #endif
00876 return optimizedPoses;
00877 }
00878
00880
00882 std::multimap<int, Link>::iterator findLink(
00883 std::multimap<int, Link> & links,
00884 int from,
00885 int to)
00886 {
00887 std::multimap<int, Link>::iterator iter = links.find(from);
00888 while(iter != links.end() && iter->first == from)
00889 {
00890 if(iter->second.to() == to)
00891 {
00892 return iter;
00893 }
00894 ++iter;
00895 }
00896
00897
00898 iter = links.find(to);
00899 while(iter != links.end() && iter->first == to)
00900 {
00901 if(iter->second.to() == from)
00902 {
00903 return iter;
00904 }
00905 ++iter;
00906 }
00907 return links.end();
00908 }
00909
00910 std::multimap<int, int>::iterator findLink(
00911 std::multimap<int, int> & links,
00912 int from,
00913 int to)
00914 {
00915 std::multimap<int, int>::iterator iter = links.find(from);
00916 while(iter != links.end() && iter->first == from)
00917 {
00918 if(iter->second == to)
00919 {
00920 return iter;
00921 }
00922 ++iter;
00923 }
00924
00925
00926 iter = links.find(to);
00927 while(iter != links.end() && iter->first == to)
00928 {
00929 if(iter->second == from)
00930 {
00931 return iter;
00932 }
00933 ++iter;
00934 }
00935 return links.end();
00936 }
00937
00938 std::map<int, Transform> radiusPosesFiltering(
00939 const std::map<int, Transform> & poses,
00940 float radius,
00941 float angle,
00942 bool keepLatest)
00943 {
00944 if(poses.size() > 1 && radius > 0.0f)
00945 {
00946 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
00947 cloud->resize(poses.size());
00948 int i=0;
00949 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter, ++i)
00950 {
00951 (*cloud)[i] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
00952 UASSERT_MSG(pcl::isFinite((*cloud)[i]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str());
00953 }
00954
00955
00956 std::vector<int> names = uKeys(poses);
00957 std::vector<Transform> transforms = uValues(poses);
00958
00959 pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> (false));
00960 tree->setInputCloud(cloud);
00961 std::set<int> indicesChecked;
00962 std::set<int> indicesKept;
00963
00964 for(unsigned int i=0; i<cloud->size(); ++i)
00965 {
00966 if(indicesChecked.find(i) == indicesChecked.end())
00967 {
00968 std::vector<int> kIndices;
00969 std::vector<float> kDistances;
00970 tree->radiusSearch(cloud->at(i), radius, kIndices, kDistances);
00971
00972 std::set<int> cloudIndices;
00973 const Transform & currentT = transforms.at(i);
00974 Eigen::Vector3f vA = currentT.toEigen3f().rotation()*Eigen::Vector3f(1,0,0);
00975 for(unsigned int j=0; j<kIndices.size(); ++j)
00976 {
00977 if(indicesChecked.find(kIndices[j]) == indicesChecked.end())
00978 {
00979 if(angle > 0.0f)
00980 {
00981 const Transform & checkT = transforms.at(kIndices[j]);
00982
00983 Eigen::Vector3f vB = checkT.toEigen3f().rotation()*Eigen::Vector3f(1,0,0);
00984 double a = pcl::getAngle3D(Eigen::Vector4f(vA[0], vA[1], vA[2], 0), Eigen::Vector4f(vB[0], vB[1], vB[2], 0));
00985 if(a <= angle)
00986 {
00987 cloudIndices.insert(kIndices[j]);
00988 }
00989 }
00990 else
00991 {
00992 cloudIndices.insert(kIndices[j]);
00993 }
00994 }
00995 }
00996
00997 if(keepLatest)
00998 {
00999 bool lastAdded = false;
01000 for(std::set<int>::reverse_iterator iter = cloudIndices.rbegin(); iter!=cloudIndices.rend(); ++iter)
01001 {
01002 if(!lastAdded)
01003 {
01004 indicesKept.insert(*iter);
01005 lastAdded = true;
01006 }
01007 indicesChecked.insert(*iter);
01008 }
01009 }
01010 else
01011 {
01012 bool firstAdded = false;
01013 for(std::set<int>::iterator iter = cloudIndices.begin(); iter!=cloudIndices.end(); ++iter)
01014 {
01015 if(!firstAdded)
01016 {
01017 indicesKept.insert(*iter);
01018 firstAdded = true;
01019 }
01020 indicesChecked.insert(*iter);
01021 }
01022 }
01023 }
01024 }
01025
01026
01027
01028 UINFO("Cloud filtered In = %d, Out = %d", cloud->size(), indicesKept.size());
01029
01030
01031
01032 std::map<int, Transform> keptPoses;
01033 for(std::set<int>::iterator iter = indicesKept.begin(); iter!=indicesKept.end(); ++iter)
01034 {
01035 keptPoses.insert(std::make_pair(names.at(*iter), transforms.at(*iter)));
01036 }
01037
01038 return keptPoses;
01039 }
01040 else
01041 {
01042 return poses;
01043 }
01044 }
01045
01046 std::multimap<int, int> radiusPosesClustering(const std::map<int, Transform> & poses, float radius, float angle)
01047 {
01048 std::multimap<int, int> clusters;
01049 if(poses.size() > 1 && radius > 0.0f)
01050 {
01051 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
01052 cloud->resize(poses.size());
01053 int i=0;
01054 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter, ++i)
01055 {
01056 (*cloud)[i] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
01057 UASSERT_MSG(pcl::isFinite((*cloud)[i]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str());
01058 }
01059
01060
01061 std::vector<int> ids = uKeys(poses);
01062 std::vector<Transform> transforms = uValues(poses);
01063
01064 pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> (false));
01065 tree->setInputCloud(cloud);
01066
01067 for(unsigned int i=0; i<cloud->size(); ++i)
01068 {
01069 std::vector<int> kIndices;
01070 std::vector<float> kDistances;
01071 tree->radiusSearch(cloud->at(i), radius, kIndices, kDistances);
01072
01073 std::set<int> cloudIndices;
01074 const Transform & currentT = transforms.at(i);
01075 Eigen::Vector3f vA = currentT.toEigen3f().rotation()*Eigen::Vector3f(1,0,0);
01076 for(unsigned int j=0; j<kIndices.size(); ++j)
01077 {
01078 if((int)i != kIndices[j])
01079 {
01080 if(angle > 0.0f)
01081 {
01082 const Transform & checkT = transforms.at(kIndices[j]);
01083
01084 Eigen::Vector3f vB = checkT.toEigen3f().rotation()*Eigen::Vector3f(1,0,0);
01085 double a = pcl::getAngle3D(Eigen::Vector4f(vA[0], vA[1], vA[2], 0), Eigen::Vector4f(vB[0], vB[1], vB[2], 0));
01086 if(a <= angle)
01087 {
01088 clusters.insert(std::make_pair(ids[i], ids[kIndices[j]]));
01089 }
01090 }
01091 else
01092 {
01093 clusters.insert(std::make_pair(ids[i], ids[kIndices[j]]));
01094 }
01095 }
01096 }
01097 }
01098 }
01099 return clusters;
01100 }
01101
01102
01103 class Node
01104 {
01105 public:
01106 Node(int id, int fromId, const rtabmap::Transform & pose) :
01107 id_(id),
01108 costSoFar_(0.0f),
01109 distToEnd_(0.0f),
01110 fromId_(fromId),
01111 closed_(false),
01112 pose_(pose)
01113 {}
01114
01115 int id() const {return id_;}
01116 int fromId() const {return fromId_;}
01117 bool isClosed() const {return closed_;}
01118 bool isOpened() const {return !closed_;}
01119 float costSoFar() const {return costSoFar_;}
01120 float distToEnd() const {return distToEnd_;}
01121 float totalCost() const {return costSoFar_ + distToEnd_;}
01122 rtabmap::Transform pose() const {return pose_;}
01123 float distFrom(const rtabmap::Transform & pose) const
01124 {
01125 return pose_.getDistance(pose);
01126 }
01127
01128 void setClosed(bool closed) {closed_ = closed;}
01129 void setFromId(int fromId) {fromId_ = fromId;}
01130 void setCostSoFar(float costSoFar) {costSoFar_ = costSoFar;}
01131 void setDistToEnd(float distToEnd) {distToEnd_ = distToEnd;}
01132
01133 private:
01134 int id_;
01135 float costSoFar_;
01136 float distToEnd_;
01137 int fromId_;
01138 bool closed_;
01139 rtabmap::Transform pose_;
01140 };
01141
01142 typedef std::pair<int, float> Pair;
01143 struct Order
01144 {
01145 bool operator()(Pair const& a, Pair const& b) const
01146 {
01147 return a.second > b.second;
01148 }
01149 };
01150
01151 std::list<std::pair<int, Transform> > computePath(
01152 const std::map<int, rtabmap::Transform> & poses,
01153 const std::multimap<int, int> & links,
01154 int from,
01155 int to,
01156 bool updateNewCosts)
01157 {
01158 std::list<std::pair<int, Transform> > path;
01159
01160
01161 int startNode = from;
01162 int endNode = to;
01163 rtabmap::Transform endPose = poses.at(endNode);
01164 std::map<int, Node> nodes;
01165 nodes.insert(std::make_pair(startNode, Node(startNode, 0, poses.at(startNode))));
01166 std::priority_queue<Pair, std::vector<Pair>, Order> pq;
01167 std::multimap<float, int> pqmap;
01168 if(updateNewCosts)
01169 {
01170 pqmap.insert(std::make_pair(0, startNode));
01171 }
01172 else
01173 {
01174 pq.push(Pair(startNode, 0));
01175 }
01176
01177 while((updateNewCosts && pqmap.size()) || (!updateNewCosts && pq.size()))
01178 {
01179 Node * currentNode;
01180 if(updateNewCosts)
01181 {
01182 currentNode = &nodes.find(pqmap.begin()->second)->second;
01183 pqmap.erase(pqmap.begin());
01184 }
01185 else
01186 {
01187 currentNode = &nodes.find(pq.top().first)->second;
01188 pq.pop();
01189 }
01190
01191 currentNode->setClosed(true);
01192
01193 if(currentNode->id() == endNode)
01194 {
01195 while(currentNode->id()!=startNode)
01196 {
01197 path.push_front(std::make_pair(currentNode->id(), currentNode->pose()));
01198 currentNode = &nodes.find(currentNode->fromId())->second;
01199 }
01200 path.push_front(std::make_pair(startNode, poses.at(startNode)));
01201 break;
01202 }
01203
01204
01205 for(std::multimap<int, int>::const_iterator iter = links.find(currentNode->id());
01206 iter!=links.end() && iter->first == currentNode->id();
01207 ++iter)
01208 {
01209 std::map<int, Node>::iterator nodeIter = nodes.find(iter->second);
01210 if(nodeIter == nodes.end())
01211 {
01212 std::map<int, rtabmap::Transform>::const_iterator poseIter = poses.find(iter->second);
01213 UASSERT(poseIter != poses.end());
01214 Node n(iter->second, currentNode->id(), poseIter->second);
01215 n.setCostSoFar(currentNode->costSoFar() + currentNode->distFrom(poseIter->second));
01216 n.setDistToEnd(n.distFrom(endPose));
01217 nodes.insert(std::make_pair(iter->second, n));
01218 if(updateNewCosts)
01219 {
01220 pqmap.insert(std::make_pair(n.totalCost(), n.id()));
01221 }
01222 else
01223 {
01224 pq.push(Pair(n.id(), n.totalCost()));
01225 }
01226 }
01227 else if(updateNewCosts && nodeIter->second.isOpened())
01228 {
01229 float newCostSoFar = currentNode->costSoFar() + currentNode->distFrom(nodeIter->second.pose());
01230 if(nodeIter->second.costSoFar() > newCostSoFar)
01231 {
01232
01233 for(std::multimap<float, int>::iterator mapIter=pqmap.begin(); mapIter!=pqmap.end(); ++mapIter)
01234 {
01235 if(mapIter->second == nodeIter->first)
01236 {
01237 pqmap.erase(mapIter);
01238 nodeIter->second.setCostSoFar(newCostSoFar);
01239 pqmap.insert(std::make_pair(nodeIter->second.totalCost(), nodeIter->first));
01240 break;
01241 }
01242 }
01243 }
01244 }
01245 }
01246 }
01247 return path;
01248 }
01249
01250 int findNearestNode(
01251 const std::map<int, rtabmap::Transform> & nodes,
01252 const rtabmap::Transform & targetPose)
01253 {
01254 int id = 0;
01255 if(nodes.size() && !targetPose.isNull())
01256 {
01257 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
01258 cloud->resize(nodes.size());
01259 std::vector<int> ids(nodes.size());
01260 int oi = 0;
01261 for(std::map<int, Transform>::const_iterator iter = nodes.begin(); iter!=nodes.end(); ++iter)
01262 {
01263 (*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
01264 ids[oi++] = iter->first;
01265 }
01266
01267 std::map<int, float> foundNodes;
01268 if(cloud->size())
01269 {
01270 pcl::search::KdTree<pcl::PointXYZ>::Ptr kdTree(new pcl::search::KdTree<pcl::PointXYZ>);
01271 kdTree->setInputCloud(cloud);
01272 std::vector<int> ind;
01273 std::vector<float> dist;
01274 pcl::PointXYZ pt(targetPose.x(), targetPose.y(), targetPose.z());
01275 kdTree->nearestKSearch(pt, 1, ind, dist);
01276 if(ind.size() && dist.size() && ind[0] >= 0)
01277 {
01278 UDEBUG("Nearest node = %d: %f", ids[ind[0]], dist[0]);
01279 id = ids[ind[0]];
01280 }
01281 }
01282 }
01283 return id;
01284 }
01285
01286
01287 std::map<int, float> getNodesInRadius(
01288 int nodeId,
01289 const std::map<int, Transform> & nodes,
01290 float radius)
01291 {
01292 UASSERT(uContains(nodes, nodeId));
01293 std::map<int, float> foundNodes;
01294 if(nodes.size() <= 1)
01295 {
01296 return foundNodes;
01297 }
01298
01299 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
01300 cloud->resize(nodes.size());
01301 std::vector<int> ids(nodes.size());
01302 int oi = 0;
01303 for(std::map<int, Transform>::const_iterator iter = nodes.begin(); iter!=nodes.end(); ++iter)
01304 {
01305 if(iter->first != nodeId)
01306 {
01307 (*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
01308 UASSERT_MSG(pcl::isFinite((*cloud)[oi]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str());
01309 ids[oi] = iter->first;
01310 ++oi;
01311 }
01312 }
01313 cloud->resize(oi);
01314 ids.resize(oi);
01315
01316 Transform fromT = nodes.at(nodeId);
01317
01318 if(cloud->size())
01319 {
01320 pcl::search::KdTree<pcl::PointXYZ>::Ptr kdTree(new pcl::search::KdTree<pcl::PointXYZ>);
01321 kdTree->setInputCloud(cloud);
01322 std::vector<int> ind;
01323 std::vector<float> dist;
01324 pcl::PointXYZ pt(fromT.x(), fromT.y(), fromT.z());
01325 kdTree->radiusSearch(pt, radius, ind, dist, 0);
01326 for(unsigned int i=0; i<ind.size(); ++i)
01327 {
01328 if(ind[i] >=0)
01329 {
01330 UDEBUG("Inlier %d: %f", ids[ind[i]], sqrt(dist[i]));
01331 foundNodes.insert(std::make_pair(ids[ind[i]], dist[i]));
01332 }
01333 }
01334 }
01335 UDEBUG("found nodes=%d", (int)foundNodes.size());
01336 return foundNodes;
01337 }
01338
01339
01340 std::map<int, Transform> getPosesInRadius(
01341 int nodeId,
01342 const std::map<int, Transform> & nodes,
01343 float radius)
01344 {
01345 UASSERT(uContains(nodes, nodeId));
01346 std::map<int, Transform> foundNodes;
01347 if(nodes.size() <= 1)
01348 {
01349 return foundNodes;
01350 }
01351
01352 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
01353 cloud->resize(nodes.size());
01354 std::vector<int> ids(nodes.size());
01355 int oi = 0;
01356 for(std::map<int, Transform>::const_iterator iter = nodes.begin(); iter!=nodes.end(); ++iter)
01357 {
01358 if(iter->first != nodeId)
01359 {
01360 (*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
01361 UASSERT_MSG(pcl::isFinite((*cloud)[oi]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str());
01362 ids[oi] = iter->first;
01363 ++oi;
01364 }
01365 }
01366 cloud->resize(oi);
01367 ids.resize(oi);
01368
01369 Transform fromT = nodes.at(nodeId);
01370
01371 if(cloud->size())
01372 {
01373 pcl::search::KdTree<pcl::PointXYZ>::Ptr kdTree(new pcl::search::KdTree<pcl::PointXYZ>);
01374 kdTree->setInputCloud(cloud);
01375 std::vector<int> ind;
01376 std::vector<float> dist;
01377 pcl::PointXYZ pt(fromT.x(), fromT.y(), fromT.z());
01378 kdTree->radiusSearch(pt, radius, ind, dist, 0);
01379 for(unsigned int i=0; i<ind.size(); ++i)
01380 {
01381 if(ind[i] >=0)
01382 {
01383 UDEBUG("Inlier %d: %f", ids[ind[i]], sqrt(dist[i]));
01384 foundNodes.insert(std::make_pair(ids[ind[i]], nodes.at(ids[ind[i]])));
01385 }
01386 }
01387 }
01388 UDEBUG("found nodes=%d", (int)foundNodes.size());
01389 return foundNodes;
01390 }
01391
01392 float computePathLength(
01393 const std::vector<std::pair<int, Transform> > & path,
01394 unsigned int fromIndex,
01395 unsigned int toIndex)
01396 {
01397 float length = 0.0f;
01398 if(path.size() > 1)
01399 {
01400 UASSERT(fromIndex < path.size() && toIndex < path.size() && fromIndex <= toIndex);
01401 if(fromIndex >= toIndex)
01402 {
01403 toIndex = (unsigned int)path.size()-1;
01404 }
01405 float x=0, y=0, z=0;
01406 for(unsigned int i=fromIndex; i<toIndex-1; ++i)
01407 {
01408 x += fabs(path[i].second.x() - path[i+1].second.x());
01409 y += fabs(path[i].second.y() - path[i+1].second.y());
01410 z += fabs(path[i].second.z() - path[i+1].second.z());
01411 }
01412 length = sqrt(x*x + y*y + z*z);
01413 }
01414 return length;
01415 }
01416
01417 }
01418
01419 }