Urdf2Inventor.cpp
Go to the documentation of this file.
00001 
00032 #include <urdf2inventor/Urdf2Inventor.h>
00033 #include <urdf2inventor/Helpers.h>
00034 #include <urdf2inventor/IVHelpers.h>
00035 #include <urdf2inventor/ConvertMesh.h>
00036 
00037 #include <string>
00038 #include <ros/ros.h>
00039 #include <ros/package.h>
00040 
00041 #include <Inventor/SoDB.h>      // for file reading
00042 #include <Inventor/SoInput.h>   // for file reading
00043 #include <Inventor/actions/SoWriteAction.h>
00044 #include <Inventor/nodes/SoTransform.h>
00045 #include <Inventor/nodes/SoSelection.h>
00046 #include <Inventor/nodekits/SoNodeKit.h>
00047 
00048 #include <urdf_traverser/Functions.h>
00049 #include <urdf_transform/JoinFixedLinks.h>
00050 #include <urdf_transform/ScaleModel.h>
00051 #include <urdf_transform/AlignRotationAxis.h>
00052 
00053 #include <map>
00054 #include <vector>
00055 #include <set>
00056 #include <fstream>
00057 #include <algorithm>
00058 
00059 #define RAD_TO_DEG 180/M_PI
00060 
00061 // directory where to dump temporary mesh
00062 // files. Only required to read collada files.
00063 #define TEMP_MESH_DIR "/tmp/tempMeshes"
00064 
00065 using urdf2inventor::Urdf2Inventor;
00066 
00067 std::string Urdf2Inventor::OUTPUT_EXTENSION = ".iv";
00068 std::string Urdf2Inventor::MESH_OUTPUT_DIRECTORY_NAME = "iv/";
00069 std::string Urdf2Inventor::TEX_OUTPUT_DIRECTORY_NAME = "textures/";
00070 
00071 bool Urdf2Inventor::joinFixedLinks(const std::string& fromLink)
00072 {
00073     std::string startLinkName = fromLink;
00074     if (startLinkName.empty())
00075     {
00076         startLinkName = urdf_traverser->getRootLinkName();
00077     }
00078         
00079     ROS_INFO("############### Joining fixed links");
00080     ROS_INFO_STREAM("Start from root link: "<<startLinkName);
00081 //    ROS_INFO_STREAM("Getting as inventor starting from '"<<startLinkName<<"'");
00082     LinkPtr startLink = urdf_traverser->getLink(startLinkName);
00083     if (!startLink.get())
00084     {
00085         ROS_ERROR_STREAM("No link named '" << startLinkName << "'");
00086         return false;
00087     }
00088 
00089     if (!urdf_transform::joinFixedLinks(*urdf_traverser, startLinkName))
00090     {
00091         ROS_ERROR_STREAM("Could not join fixed links");
00092         return false;
00093     }
00094     return true;
00095 }
00096 
00097 bool Urdf2Inventor::allRotationsToAxis(const std::string& fromLinkName, const Eigen::Vector3d& axis)
00098 {
00099     std::string startLinkName = fromLinkName;
00100     if (startLinkName.empty())
00101     {
00102         startLinkName = urdf_traverser->getRootLinkName();
00103     }
00104 //    ROS_INFO_STREAM("Getting as inventor starting from '"<<startLinkName<<"'");
00105     LinkPtr startLink = urdf_traverser->getLink(startLinkName);
00106     if (!startLink.get())
00107     {
00108         ROS_ERROR_STREAM("No link named '" << startLink << "'");
00109         return false;
00110     }
00111 
00112     ROS_INFO_STREAM("############### Aligning rotation axis to " << axis);
00113     if (!urdf_transform::allRotationsToAxis(*urdf_traverser, fromLinkName, axis))
00114     {
00115         ROS_ERROR_STREAM("Could not align to axis");
00116         return false;
00117     }
00118     return true;
00119 }
00120 
00121 bool Urdf2Inventor::scale()
00122 {
00123     if (fabs(scaleFactor - 1.0) < 1e-04)
00124     {
00125         //ROS_INFO("Scale factor 1, so no need to scale model");
00126         return true;
00127     }
00128     ROS_INFO("############### Scaling model");
00129 
00130     if (!urdf_transform::scaleModel(*urdf_traverser, scaleFactor))
00131     {
00132         ROS_ERROR("Could not scale model");
00133         return false;
00134     }
00135 
00136     isScaled = true;
00137     return true;
00138 }
00139 
00140 
00141 bool Urdf2Inventor::loadModelFromFile(const std::string& urdfFilename)
00142 {
00143     return urdf_traverser->loadModelFromFile(urdfFilename);
00144 }
00145 
00146 
00147 urdf_traverser::EigenTransform Urdf2Inventor::getTransform(const LinkPtr& from_link,  const JointPtr& to_joint)
00148 {
00149     LinkPtr link1 = from_link;
00150     LinkPtr link2 = urdf_traverser->getLink(to_joint->child_link_name);
00151     if (!link1 || !link2)
00152     {
00153         ROS_ERROR("Invalid joint specifications (%s, %s), first needs parent and second child",
00154                   link1->name.c_str(), link2->name.c_str());
00155     }
00156     return urdf_traverser::getTransform(link1, link2);
00157 }
00158 
00159 Urdf2Inventor::ConversionResultPtr Urdf2Inventor::preConvert(const ConversionParametersPtr& params)
00160 {
00161     ConversionResultPtr res(new ConversionResultT(OUTPUT_EXTENSION, MESH_OUTPUT_DIRECTORY_NAME, TEX_OUTPUT_DIRECTORY_NAME));
00162     res->success = false;
00163     return res;
00164 }
00165 
00166 Urdf2Inventor::ConversionResultPtr Urdf2Inventor::postConvert(const ConversionParametersPtr& params, ConversionResultPtr& result)
00167 {
00168     result->success = true;
00169     return result;
00170 }
00171 
00172 
00173 Urdf2Inventor::ConversionResultPtr Urdf2Inventor::convert(const ConversionParametersPtr& params,
00174                                                           const MeshConvertRecursionParamsPtr& meshParams)
00175 {
00176     ConversionResultPtr res = preConvert(params);
00177     if (!res.get())
00178     {
00179         ROS_ERROR("Failed to pre-convert");
00180         return res;
00181     }
00182     res->success = false;
00183 
00184     if (!isScaled && !scale())
00185     {
00186         ROS_ERROR("Failed to scale model");
00187     }
00188 
00189     ROS_INFO_STREAM("############### Converting meshes"); //, base dir " << params->baseDir);
00190 
00191 /*    std::map<std::string, std::set<std::string> > textureFiles;
00192     if (!urdf2inventor::convertMeshesSimple(*urdf_traverser, params->rootLinkName,
00193                                       scaleFactor,
00194                                       params->material,
00195                                       OUTPUT_EXTENSION,
00196                                       params->addVisualTransform,
00197                                       res->meshes, textureFiles))
00198     {
00199         ROS_ERROR("Could not convert meshes");
00200         return res;
00201     }
00202     */
00203     MeshConvertRecursionParamsPtr mParams=meshParams;
00204     if (!mParams)
00205     {
00206         mParams.reset(new MeshConvertRecursionParamsT(scaleFactor, params->material,
00207                                         OUTPUT_EXTENSION, params->addVisualTransform));
00208     }
00209 
00210     if (!urdf2inventor::convertMeshes<MeshFormat>(*urdf_traverser, params->rootLinkName, mParams))
00211     {
00212         ROS_ERROR("Could not convert meshes");
00213         return res;
00214     }
00215 
00216     res->meshes = mParams->resultMeshes;
00217 
00218     if (!urdf2inventor::fixTextureReferences(
00219                 res->meshOutputDirectoryName,
00220                 res->texOutputDirectoryName,
00221                 mParams->textureFiles,
00222                 //textureFiles,
00223                 res->meshes, res->textureFiles))
00224     {
00225         ROS_ERROR("Could not fix texture references");
00226         return res;
00227     }
00228 
00229     /*    for (std::map<std::string, std::set<std::string> >::iterator mit=res->textureFiles.begin(); mit!=res->textureFiles.end(); ++mit)
00230         {
00231             for (std::set<std::string>::iterator tit=mit->second.begin(); tit!=mit->second.end(); ++tit)
00232                 ROS_INFO_STREAM("Required: cp "<<*tit<<" "<<mit->first);
00233         }*/
00234 
00235     return postConvert(params, res);
00236 }
00237 
00238 
00239 bool Urdf2Inventor::printModel(const std::string& fromLink)
00240 {
00241     return urdf_traverser->printModel(fromLink, false);
00242 }
00243 
00244 bool Urdf2Inventor::printModel()
00245 {
00246     return urdf_traverser->printModel(false);
00247 }
00248 
00249 
00250 bool Urdf2Inventor::getJointNames(const std::string& fromLink, const bool skipFixed, std::vector<std::string>& result)
00251 {
00252     return urdf_traverser->getJointNames(fromLink, skipFixed, result);
00253 }
00254 
00255 
00256 
00257 void Urdf2Inventor::cleanup()
00258 {
00259     if (urdf_traverser::helpers::fileExists(TMP_FILE_IV))
00260     {
00261         urdf_traverser::helpers::deleteFile(TMP_FILE_IV);
00262     }
00263 }
00264 
00265 bool Urdf2Inventor::writeInventorFile(SoNode * node, const std::string& filename)
00266 {
00267     SoOutput out;
00268     if (!out.openFile(filename.c_str())) return false;
00269     out.setBinary(false);
00270     SoWriteAction write(&out);
00271     write.apply(node);
00272     write.getOutput()->closeFile();
00273     return true;
00274 }
00275 
00276 
00277 /*SoTransform * Urdf2Inventor::getTransform(const EigenTransform& eTrans) const
00278 {
00279     SoTransform * transform = new SoTransform();
00280 
00281     SoSFVec3f translation;
00282     translation.setValue(eTrans.translation().x(), eTrans.translation().y(), eTrans.translation().z());
00283     transform->translation = translation;
00284 
00285     SoSFRotation rotation;
00286     Eigen::Quaterniond vQuat(eTrans.rotation());
00287     rotation.setValue(vQuat.x(), vQuat.y(), vQuat.z(), vQuat.w());
00288     transform->rotation = rotation;
00289     return transform;
00290 }*/
00291 
00292 void Urdf2Inventor::printJointNames(const std::string& fromLink)
00293 {
00294     std::vector<std::string> jointNames;
00295     if (!getJointNames(fromLink, false, jointNames))
00296     {
00297         ROS_WARN("Could not retrieve joint names to print on screen");
00298     }
00299     else
00300     {
00301         ROS_INFO_STREAM("Joint names starting from " << fromLink << ":");
00302         for (int i = 0; i < jointNames.size(); ++i) ROS_INFO_STREAM(jointNames[i]);
00303         ROS_INFO("---");
00304     }
00305 }
00306 
00307 /*
00308 SoNode * Urdf2Inventor::loadAndGetAsInventor(const std::string& urdfFilename,
00309     const std::string from_link, bool useScaleFactor,   )
00310 {
00311     if (!loadModelFromFile(urdfFilename))
00312     {
00313         ROS_ERROR("Could not load file");
00314         return NULL;
00315     }
00316 
00317 
00318     ROS_INFO("Converting robot %s URDF to inventor", getRobotName().c_str());
00319     std::string rootLink=from_link;
00320     if (rootLink.empty()){
00321         rootLink = getRootLinkName();
00322     }
00323     printJointNames(rootLink);
00324     return getAsInventor(rootLink, useScaleFactor, addAxes, axesRadius, axesLength);
00325 }*/
00326 
00327 
00328 void Urdf2Inventor::addLocalAxes(const LinkConstPtr& link, SoSeparator * addToNode, bool useScaleFactor,
00329                                  float _axesRadius, float _axesLength) const
00330 {
00331     bool active = urdf_traverser::isActive(link->parent_joint);
00332     float rad = _axesRadius;
00333     float rotRad = _axesRadius / 3;
00334     float h = _axesLength;
00335     float rotH = h * 1.8;
00336     float rtr, rtg, rtb;
00337     // rotation axis pink
00338     rtr = rtb = 1;
00339     rtg = 0;
00340     if (useScaleFactor)
00341     {
00342         rad *= scaleFactor;
00343         h *= scaleFactor;
00344         rotRad *= scaleFactor;
00345         rotH *= scaleFactor;
00346     }
00347     if (!active)
00348     {
00349         rad /= 2;
00350         h *= 1.5;
00351     }
00352     urdf2inventor::addLocalAxes(addToNode, rad, h);
00353 
00354     // add the rotation axis as well:
00355     Eigen::Vector3d rotAxis(0, 0, 1);
00356     if (link->parent_joint)
00357       rotAxis = urdf_traverser::getRotationAxis(link->parent_joint);
00358     Eigen::Vector3d z(0, 0, 1);
00359     Eigen::Quaterniond q;
00360     q.setIdentity();
00361     if (active) q = Eigen::Quaterniond::FromTwoVectors(z, rotAxis);
00362     urdf2inventor::addCylinder(addToNode, Eigen::Vector3d(0, 0, 0), q, rotRad, rotH, rtr, rtg, rtb);
00363 }
00364 
00365 
00366 SoNode * Urdf2Inventor::getAsInventor(const LinkPtr& from_link, bool useScaleFactor,
00367                                       bool _addAxes, float _axesRadius, float _axesLength,
00368                                       const EigenTransform& addVisualTransform,
00369                                       std::set<std::string> * textureFiles
00370                                      )
00371 {
00372     if (!from_link.get())
00373     {
00374         ROS_ERROR("getAsInventor: from_link is NULL");
00375         return NULL;
00376     }
00377     
00378     bool useVisuals = true; // XXX TODO: Parameterize
00379 
00380     // ROS_INFO_STREAM("Get all visuals of "<<from_link->name);//<<" (parent joint "<<from_link->parent_joint->name<<")");
00381     SoNode * allVisuals = getAllGeometry(from_link,
00382                                         useScaleFactor ? scaleFactor : 1.0,
00383                                         addVisualTransform,
00384                                         useVisuals,
00385                                         useScaleFactor);
00386     if (!allVisuals)
00387     {
00388         ROS_ERROR("Could not get visuals");
00389         return NULL;
00390     }
00391 
00392     if (textureFiles)
00393     {
00394         // collect all relative texture filenames from the absolute texture paths.
00395         std::set<std::string> allFiles =  urdf2inventor::getAllTexturePaths(allVisuals);
00396         textureFiles->insert(allFiles.begin(), allFiles.end());
00397     }
00398 
00399     if (_addAxes)
00400     {
00401         SoSeparator * _allVisuals = dynamic_cast<SoSeparator*>(allVisuals);
00402         if (!_allVisuals)
00403         {
00404             ROS_WARN_STREAM("The node for link " << from_link->name << " is not a separator, so cannot add axes");
00405         }
00406         else
00407         {
00408             // ROS_INFO_STREAM("Adding local axes for "<<from_link->name);
00409             addLocalAxes(from_link, _allVisuals, useScaleFactor, _axesRadius, _axesLength);
00410         }
00411     }
00412 
00413     for (std::vector<JointPtr>::const_iterator pj = from_link->child_joints.begin();
00414             pj != from_link->child_joints.end(); pj++)
00415     {
00416         JointPtr joint = *pj;
00417         // ROS_INFO_STREAM("Get inventor files down from joint "<<joint->name);
00418         LinkPtr childLink = urdf_traverser->getLink(joint->child_link_name);
00419         if (!childLink.get())
00420         {
00421             ROS_ERROR_STREAM("Consistency: Link " << joint->child_link_name << " does not exist.");
00422             return NULL;
00423         }
00424         SoNode * childNode = getAsInventor(childLink, useScaleFactor,
00425                                            _addAxes, _axesRadius, _axesLength, addVisualTransform, textureFiles);
00426         if (!childNode)
00427         {
00428             ROS_ERROR_STREAM("Could not get child node for " << childLink->name);
00429             return NULL;
00430         }
00431         EigenTransform jointTransform = urdf_traverser::getTransform(joint);
00432         if (useScaleFactor) urdf_traverser::scaleTranslation(jointTransform, scaleFactor);
00433 
00434         // ROS_WARN_STREAM("Transform joint "<<joint->name<<": "<<jointTransform);
00435         // ROS_INFO_STREAM("Adding sub node for "<<childLink->name);
00436 
00437         urdf2inventor::addSubNode(childNode, allVisuals, jointTransform);
00438     }
00439 
00440     return allVisuals;
00441 }
00442 
00443 
00444 SoNode * Urdf2Inventor::getAsInventor(const std::string& fromLink, bool useScaleFactor,
00445                                       bool _addAxes, float _axesRadius, float _axesLength, const EigenTransform& addVisualTransform,
00446                                       std::set<std::string> * textureFiles
00447                                      )
00448 {
00449     std::string startLinkName = fromLink;
00450     if (startLinkName.empty())
00451     {
00452         startLinkName = urdf_traverser->getRootLinkName();
00453     }
00454 //    ROS_INFO_STREAM("Getting as inventor starting from '"<<startLinkName<<"'");
00455     LinkPtr startLink = urdf_traverser->getLink(startLinkName);
00456     if (!startLink.get())
00457     {
00458         ROS_ERROR_STREAM("No link named '" << startLink << "'");
00459         return NULL;
00460     }
00461     SoNode * root = getAsInventor(startLink, useScaleFactor, _addAxes, _axesRadius, _axesLength,
00462                                   addVisualTransform, textureFiles);
00463     urdf2inventor::removeTextureCopies(root);
00464     return root;
00465 }
00466 
00467 
00468 bool Urdf2Inventor::writeAsInventor(const std::string& ivFilename,
00469                                     const std::string& fromLink,
00470                                     bool useScaleFactor, const EigenTransform& addVisualTransform,
00471                                     bool _addAxes, float _axesRadius, float _axesLength)
00472 {
00473     std::string startLinkName = fromLink;
00474     if (startLinkName.empty())
00475     {
00476         startLinkName = urdf_traverser->getRootLinkName();
00477     }
00478 //    ROS_INFO_STREAM("Getting as inventor starting from '"<<startLinkName<<"'");
00479     LinkPtr startLink = urdf_traverser->getLink(startLinkName);
00480     if (!startLink.get())
00481     {
00482         ROS_ERROR_STREAM("No link named '" << startLinkName << "'");
00483         return false;
00484     }
00485 
00486     ROS_INFO_STREAM("Writing from link '" << startLinkName << "' to file " << ivFilename);
00487     return writeAsInventor(ivFilename, startLink, useScaleFactor, addVisualTransform, _addAxes, _axesRadius, _axesLength);
00488 }
00489 
00490 bool Urdf2Inventor::writeAsInventor(const std::string& ivFilename, const LinkPtr& from_link,
00491                                     bool useScaleFactor, const EigenTransform& addVisualTransform,
00492                                     bool _addAxes, float _axesRadius, float _axesLength)
00493 {
00494     ROS_INFO("Converting model...");
00495 
00496     std::set<std::string> textureFiles;
00497     SoNode * inv = getAsInventor(from_link, useScaleFactor, _addAxes, _axesRadius, _axesLength,
00498                                  addVisualTransform, &textureFiles);
00499     if (!inv)
00500     {
00501         ROS_ERROR("could not generate overall inventor file");
00502         return false;
00503     }
00504 
00505     // get the node to IV XML format
00506     std::string resultFileContent;
00507     if (!urdf2inventor::writeInventorFileString(inv, resultFileContent))
00508     {
00509         ROS_ERROR("Could not get the mesh file content");
00510         return false;
00511     }
00512 
00513     // handle textures: adjust file references, if required.
00514     if (!textureFiles.empty())
00515     {
00516 
00517         // get common parent path of all textures
00518         std::string commonParent;
00519         if (!urdf_traverser::helpers::getCommonParentPath(textureFiles, commonParent))
00520         {
00521             ROS_ERROR_STREAM("Could not find common parent path of all files");
00522             return false;
00523         }
00524 
00525         // ROS_INFO_STREAM("Common parent path for all textures: "<<commonParent);
00526 
00527         std::string fileDir = urdf_traverser::helpers::getDirectory(ivFilename);
00528         //std::string fileDir = urdf_traverser::helpers::getDirectoryName(ivFilename);
00529 
00530         // ROS_INFO_STREAM("Directory name: "<<fileDir);
00531 
00532         std::map<std::string, std::set<std::string> > texToCopy;
00533 
00534         ROS_INFO("Fixing texture file references...");
00535         if (!urdf2inventor::helpers::fixFileReferences(
00536                     fileDir,
00537                     fileDir + TEX_OUTPUT_DIRECTORY_NAME,
00538                     commonParent,
00539                     textureFiles,
00540                     resultFileContent, texToCopy))
00541         {
00542             ROS_ERROR("Could not fix texture references");
00543             return false;
00544         }
00545 
00546         ROS_INFO("Copying texture files...");
00547         if (!urdf2inventor::helpers::writeFiles(texToCopy, fileDir))
00548         {
00549             ROS_ERROR("Could not write textures");
00550             return false;
00551         }
00552     }
00553 
00554     ROS_INFO("Writing model...");
00555 
00556     // write content to file
00557     if (!urdf_traverser::helpers::writeToFile(resultFileContent, ivFilename))
00558     {
00559         ROS_ERROR_STREAM("Could not write file " << ivFilename);
00560         return false;
00561     }
00562 
00563     ROS_INFO_STREAM("Whole robot model written to " << ivFilename);
00564 
00565 
00566     return true;
00567 }
00568 
00569 Urdf2Inventor::ConversionResultPtr Urdf2Inventor::loadAndConvert(const std::string& urdfFilename,
00570         bool joinFixed,
00571         const ConversionParametersPtr& params)
00572 {
00573     ConversionResultPtr failResult(new ConversionResultT(OUTPUT_EXTENSION, MESH_OUTPUT_DIRECTORY_NAME, TEX_OUTPUT_DIRECTORY_NAME));
00574     failResult->success = false;
00575 
00576     ROS_INFO_STREAM("Loading model from file " << urdfFilename);
00577 
00578     if (!urdf_traverser->loadModelFromFile(urdfFilename))
00579     {
00580         ROS_ERROR("Could not load file");
00581         return failResult;
00582     }
00583 
00584     if (joinFixed) ROS_INFO("Joining fixed links..");
00585     if (joinFixed && !joinFixedLinks(params->rootLinkName))
00586     {
00587         ROS_ERROR("Could not join fixed links");
00588         return failResult;
00589     }
00590 
00591     // ROS_INFO("00000000000000000000000");
00592     // p.printModel(rootLink);
00593 
00594     ConversionResultPtr result = convert(params);
00595     if (!result.get() || !result->success)
00596     {
00597         ROS_ERROR("Could not do the conversion");
00598         return result;
00599     }
00600 
00601     // ROS_INFO_STREAM("Contacts generated: "<<result.contacts);
00602     return result;
00603 }


urdf2inventor
Author(s): Jennifer Buehler
autogenerated on Fri Mar 1 2019 03:38:11