00001
00031 #include <urdf_traverser/Helpers.h>
00032
00033 #include <ros/ros.h>
00034 #include <ros/package.h>
00035
00036 #include <fcntl.h>
00037 #include <fstream>
00038 #include <string>
00039
00040 #define BOOST_NO_CXX11_SCOPED_ENUMS
00041 #include <boost/filesystem.hpp>
00042 #undef BOOST_NO_CXX11_SCOPED_ENUMS
00043
00052 void urdf_traverser::helpers::findAndReplace(const std::string& newStr, const std::string& oldStr, const std::string& in, std::string& out)
00053 {
00054 size_t pos = 0;
00055 out = in;
00056 while ((pos = out.find(oldStr, pos)) != std::string::npos)
00057 {
00058 out = out.replace(pos, oldStr.length(), newStr);
00059 pos += newStr.length();
00060 }
00061 }
00062
00063 void urdf_traverser::helpers::deleteFile(const char* file)
00064 {
00065 std::remove(file);
00066 }
00067
00068 bool urdf_traverser::helpers::fileExists(const char* file)
00069 {
00070 return boost::filesystem::exists(file);
00071 }
00072
00073 std::string urdf_traverser::helpers::getFilename(const char* file)
00074 {
00075 boost::filesystem::path dPath(file);
00076 return dPath.filename().string();
00077 }
00078
00079 std::string urdf_traverser::helpers::getFilenameWithoutExtension(const char* file)
00080 {
00081 boost::filesystem::path dPath(file);
00082 return dPath.stem().string();
00083 }
00084
00085
00086 std::string urdf_traverser::helpers::fileExtension(const char* file)
00087 {
00088 boost::filesystem::path dPath(file);
00089 std::string extension = dPath.extension().string();
00090 extension.erase(0, 1);
00091 return extension;
00092 }
00093
00094 bool urdf_traverser::helpers::directoryExists(const char* dPath)
00095 {
00096
00097 return boost::filesystem::exists(dPath);
00098 }
00099
00100 std::string urdf_traverser::helpers::getPath(const char * file)
00101 {
00102 boost::filesystem::path dPath(file);
00103 return dPath.parent_path().string();
00104 }
00105
00106 bool urdf_traverser::helpers::makeDirectoryIfNeeded(const char * dPath)
00107 {
00108 if (directoryExists(dPath)) return true;
00109 try
00110 {
00111 boost::filesystem::path dir(dPath);
00112 boost::filesystem::path buildPath;
00113
00114 for (boost::filesystem::path::iterator it(dir.begin()), it_end(dir.end()); it != it_end; ++it)
00115 {
00116 buildPath /= *it;
00117
00118
00119 if (!boost::filesystem::exists(buildPath) &&
00120 !boost::filesystem::create_directory(buildPath))
00121 {
00122 ROS_ERROR_STREAM("Could not create directory " << buildPath);
00123 return false;
00124 }
00125 }
00126 }
00127 catch (const boost::filesystem::filesystem_error& ex)
00128 {
00129 ROS_ERROR_STREAM(ex.what());
00130 return false;
00131 }
00132 return true;
00133 }
00134
00135 bool urdf_traverser::helpers::isDirectoryPath(const std::string& path)
00136 {
00137 if (path.empty()) return false;
00138 if ((path == ".") || (path == "..")) return true;
00139 return path[path.length() - 1] == boost::filesystem::path::preferred_separator;
00140 }
00141
00142 bool urdf_traverser::helpers::getSubdirPath(const std::string& from, const std::string& to, std::string& result)
00143 {
00144 if (!isDirectoryPath(from))
00145 {
00146 ROS_ERROR_STREAM("Base path (" << from << ") must be a directory");
00147 throw std::exception();
00148 }
00149
00150 if (from == to)
00151 {
00152 result = ".";
00153 return true;
00154 }
00155
00156 boost::filesystem::path _from(from);
00157 boost::filesystem::path _to(to);
00158
00159 boost::filesystem::path _absFrom = boost::filesystem::absolute(_from);
00160 boost::filesystem::path _absTo = boost::filesystem::absolute(_to);
00161
00162 boost::filesystem::path::iterator it(_absFrom.begin());
00163 boost::filesystem::path::iterator it_end(_absFrom.end());
00164 boost::filesystem::path::iterator it2(_absTo.begin());
00165 boost::filesystem::path::iterator it2_end(_absTo.end());
00166 --it_end;
00167 for (; it != it_end; ++it, ++it2)
00168 {
00169 if (it2 == it2_end) return false;
00170 if (it->string() != it2->string())
00171 {
00172
00173 return false;
00174 }
00175 }
00176
00177 boost::filesystem::path buildPath;
00178 for (; it2 != it2_end; ++it2)
00179 {
00180 buildPath /= *it2;
00181 }
00182 result = buildPath.string();
00183
00184 if (!result.empty() && (result[result.length() - 1] == '.'))
00185 result.erase(result.length() - 1, 1);
00186
00187
00188
00189 boost::filesystem::path _res(result);
00190 if (!_res.is_relative())
00191 {
00192 ROS_ERROR_STREAM("Could not correctly construct a relative path, got "
00193 << result << " (input: " << from << " and " << to << ")");
00194 return false;
00195 }
00196 return true;
00197 }
00198
00199 void urdf_traverser::helpers::enforceDirectory(std::string& path, bool printWarn)
00200 {
00201 if (path.empty()) return;
00202 if (!isDirectoryPath(path))
00203 {
00204 if (printWarn)
00205 ROS_WARN_STREAM("Path " << path << " supposed to be a directory but does not end with separator. Enforcing.");
00206 path.append(1, boost::filesystem::path::preferred_separator);
00207 }
00208 assert(isDirectoryPath(path));
00209 }
00210
00211
00212 std::string urdf_traverser::helpers::replaceAll(const std::string& text, const std::string& from, const std::string& to)
00213 {
00214
00215 std::string ret = text;
00216 for (size_t start_pos = ret.find(from); start_pos != std::string::npos; start_pos = ret.find(from, start_pos))
00217 {
00218
00219 ret.replace(start_pos, from.length(), to);
00220 }
00221 return ret;
00222 }
00223
00224 int numDirectories(const std::string& path)
00225 {
00226
00227 int cnt = 0;
00228 boost::filesystem::path _path(path);
00229 boost::filesystem::path::iterator it(_path.begin());
00230 boost::filesystem::path::iterator it_end(_path.end());
00231 for (; it != it_end; ++it)
00232 {
00233
00234
00235 ++cnt;
00236 }
00237 if (cnt > 0)
00238 {
00239
00240
00241 --cnt;
00242 }
00243
00244 return cnt;
00245 }
00246
00247 std::string urdf_traverser::helpers::getDirectory(const std::string& path)
00248 {
00249 if (urdf_traverser::helpers::isDirectoryPath(path)) return path;
00250
00251 boost::filesystem::path _path(path);
00252 std::string ret = _path.parent_path().string();
00253
00254 urdf_traverser::helpers::enforceDirectory(ret, false);
00255 return ret;
00256 }
00257
00258 std::string urdf_traverser::helpers::getDirectoryName(const std::string& path)
00259 {
00260 std::string dir = getDirectory(path);
00261
00262
00263
00264 boost::filesystem::path ret(dir);
00265 return ret.parent_path().filename().string();
00266 }
00267
00268
00269
00270 bool urdf_traverser::helpers::getCommonParentPath(const std::string& p1, const std::string& p2, std::string& result)
00271 {
00272 if (p1.empty() || p2.empty())
00273 {
00274 ROS_ERROR("Both p1 and p2 have to be set in getCommonParentPath()");
00275 return false;
00276 }
00277 boost::filesystem::path __p1(p1);
00278 boost::filesystem::path __p2(p2);
00279 bool correctAbsolute = __p1.is_relative() || __p2.is_relative();
00280
00281 boost::filesystem::path _p1(boost::filesystem::absolute(__p1));
00282 boost::filesystem::path _p2(boost::filesystem::absolute(__p2));
00283 boost::filesystem::path buildPath;
00284
00285 boost::filesystem::path::iterator it1(_p1.begin());
00286 boost::filesystem::path::iterator it1_end(_p1.end());
00287 boost::filesystem::path::iterator it2(_p2.begin());
00288 boost::filesystem::path::iterator it2_end(_p2.end());
00289
00290 int p1Len = numDirectories(p1);
00291 int p2Len = numDirectories(p2);
00292
00293
00294 if (p2Len > p1Len)
00295 {
00296
00297 boost::filesystem::path::iterator tmp(it2);
00298 it2 = it1;
00299 it1 = tmp;
00300 tmp = it2_end;
00301 it2_end = it1_end;
00302 it1_end = tmp;
00303 }
00304
00305 --it1_end;
00306
00307 for (; it1 != it1_end; ++it1, ++it2)
00308 {
00309
00310 if ((it2 == it2_end)
00311 || (*it1 != *it2))
00312 {
00313 break;
00314 }
00315
00316
00317 buildPath /= *it1;
00318
00319
00320 }
00321 if (!buildPath.empty())
00322 {
00323 result = buildPath.string();
00324
00325
00326
00327 enforceDirectory(result, false);
00328
00329 if (correctAbsolute)
00330 {
00331 std::string currDir = boost::filesystem::current_path().string();
00332 urdf_traverser::helpers::enforceDirectory(currDir, false);
00333 if (!urdf_traverser::helpers::getSubdirPath(currDir, result, result))
00334 {
00335 ROS_ERROR_STREAM("Could not remove temporarily created current directory for absolute path");
00336 return false;
00337 }
00338 }
00339 return true;
00340 }
00341 return false;
00342 }
00343
00344
00345
00346 bool urdf_traverser::helpers::getCommonParentPath(const std::set<std::string>& allFiles, std::string& result)
00347 {
00348 if (allFiles.empty())
00349 {
00350 ROS_ERROR("Cannot get common path of empty set");
00351 return false;
00352 }
00353 std::set<std::string>::const_iterator it = allFiles.begin();
00354 std::string commonPath = urdf_traverser::helpers::getDirectory(*it);
00355 ++it;
00356
00357 while (it != allFiles.end())
00358 {
00359 std::string dir = urdf_traverser::helpers::getDirectory(*it);
00360 if (!getCommonParentPath(commonPath, dir, commonPath))
00361 {
00362
00363 ROS_ERROR_STREAM("There is no root between " <<
00364 dir << " and " << commonPath << ", cannot determine common parent!");
00365 }
00366
00367 ++it;
00368 }
00369 result = commonPath;
00370 return true;
00371 }
00372
00373 bool urdf_traverser::helpers::getRelativeDirectory(const std::string& path, const std::string& relTo, std::string& result)
00374 {
00375
00376
00377 boost::filesystem::path _path(boost::filesystem::absolute(path));
00378 boost::filesystem::path _relTo(boost::filesystem::absolute(relTo));
00379
00380 std::string commonParent;
00381 if (!getCommonParentPath(path, relTo, commonParent))
00382 {
00383 ROS_ERROR_STREAM("Directories " << path << " and " << relTo << " have no common parent directory.");
00384 return false;
00385 }
00386
00387
00388
00389
00390 std::string relPath;
00391 if (!urdf_traverser::helpers::getSubdirPath(commonParent, path, relPath))
00392 {
00393 ROS_ERROR_STREAM("The file " << path << " is not in a subdirectory of " << commonParent);
00394 return false;
00395 }
00396
00397
00398 std::string relToTarget;
00399 if (!urdf_traverser::helpers::getSubdirPath(commonParent, relTo, relToTarget))
00400 {
00401 ROS_ERROR_STREAM("Relative path " << relTo << " is not a subdirectory of " << commonParent);
00402 return false;
00403 }
00404
00405
00406
00407 std::string relToDir = getDirectory(relToTarget);
00408
00409
00410
00411
00412 int relToLen = numDirectories(relToDir);
00413
00414 std::stringstream upDirs;
00415 for (int i = 0; i < relToLen; ++i)
00416 upDirs << ".." << boost::filesystem::path::preferred_separator;
00417
00418
00419 upDirs << relPath;
00420
00421 result = upDirs.str();
00422
00423 return true;
00424 }
00425
00426 bool urdf_traverser::helpers::writeToFile(const std::string& content, const std::string& filename)
00427 {
00428 std::string dir = getDirectory(filename);
00429 if (!urdf_traverser::helpers::makeDirectoryIfNeeded(dir.c_str()))
00430 {
00431 return false;
00432 }
00433
00434 std::ofstream outf(filename.c_str());
00435 if (!outf)
00436 {
00437 ROS_ERROR("%s could not be opened for writing!", filename.c_str());
00438 return false;
00439 }
00440 outf << content;
00441 outf.close();
00442 return true;
00443 }
00444
00445
00446
00447 std::string urdf_traverser::helpers::packagePathToAbsolute(std::string& packagePath)
00448 {
00449
00450 char pack[1000];
00451 char rest[1000];
00452 int numScanned = sscanf(packagePath.c_str(), "package://%[^/]/%s", pack, rest);
00453
00454 if (numScanned != 2)
00455 {
00456 ROS_ERROR("Only package:// style mesh file specifications supported!");
00457 return std::string();
00458 }
00459
00460 std::string packPath = ros::package::getPath(pack);
00461
00462 if (packPath.empty())
00463 {
00464 ROS_ERROR("No package for file specified");
00465 return std::string();
00466 }
00467
00468 std::stringstream absolute;
00469 absolute << packPath << "/" << rest;
00470
00471 return absolute.str();
00472 }
00473
00474
00475 std::ostream& operator<<(std::ostream& o, const Eigen::Vector3f& v)
00476 {
00477 o << "[" << v[0] << ", " << v[1] << ", " << v[2] << "]";
00478 return o;
00479 }
00480
00481
00482 std::ostream& operator<<(std::ostream& o, const Eigen::Vector3d& v)
00483 {
00484 o << "[" << v[0] << ", " << v[1] << ", " << v[2] << "]";
00485 return o;
00486 }
00487 std::ostream& operator<<(std::ostream& o, const Eigen::Quaterniond& v)
00488 {
00489 o << "[" << v.x() << ", " << v.y() << ", " << v.z() << ", " << v.w() << "]";
00490 return o;
00491 }
00492
00493 std::ostream& operator<<(std::ostream& o, const Eigen::Transform<double, 3, Eigen::Affine>& t)
00494 {
00495
00496 Eigen::AngleAxisd ax(t.rotation());
00497 o << "T: trans=" << Eigen::Vector3d(t.translation()) << " rot=" << ax.angle() << " / " << ax.axis();
00498 return o;
00499 }
00500
00501 std::ostream& operator<<(std::ostream& o, const Eigen::Matrix4d& m)
00502 {
00503 o << m(0, 0) << "," << m(0, 1) << "," << m(0, 2) << "," << m(0, 3) << "," <<
00504 m(1, 0) << "," << m(1, 1) << "," << m(1, 2) << "," << m(1, 3) << "," <<
00505 m(2, 0) << "," << m(2, 1) << "," << m(2, 2) << "," << m(2, 3) << "," <<
00506 m(3, 0) << "," << m(3, 1) << "," << m(3, 2) << "," << m(3, 3);
00507 return o;
00508 }
00509
00510
00511 std::ostream& operator<<(std::ostream& o, const urdf::Pose& p)
00512 {
00513 o << "trans=[" << p.position.x << ", " << p.position.y << ", " << p.position.z << "], ";
00514 o << "rot=[" << p.rotation.x << ", " << p.rotation.y << ", " << p.rotation.z << ", " << p.rotation.w << "]";
00515 return o;
00516 }
00517
00518 std::ostream& operator<<(std::ostream& o, const urdf::Vector3& p)
00519 {
00520 o << "v=[" << p.x << ", " << p.y << ", " << p.z << "], ";
00521 return o;
00522 }