00001
00031 #include <ros/ros.h>
00032 #include <urdf_traverser/Types.h>
00033 #include <urdf_traverser/UrdfTraverser.h>
00034 #include <urdf_traverser/Functions.h>
00035 #include <urdf2inventor/Helpers.h>
00036 #include <urdf2inventor/IVHelpers.h>
00037 #include <urdf2inventor/ConvertMesh.h>
00038 #include <urdf2inventor/MeshConvertRecursionParams.h>
00039
00040 #include <urdf2inventor/AssimpImport.h>
00041
00042 #include <Inventor/nodes/SoGroup.h>
00043 #include <Inventor/nodes/SoTransform.h>
00044 #include <Inventor/nodes/SoSelection.h>
00045 #include <Inventor/nodes/SoTexture2.h>
00046 #include <Inventor/nodekits/SoNodeKit.h>
00047 #include <Inventor/actions/SoWriteAction.h>
00048 #include <Inventor/actions/SoSearchAction.h>
00049
00050 #include <assimp/Importer.hpp>
00051 #include <assimp/scene.h>
00052 #include <assimp/Importer.hpp>
00053 #include <assimp/importerdesc.h>
00054 #include <assimp/postprocess.h>
00055
00056
00057 using urdf_traverser::UrdfTraverser;
00058 using urdf_traverser::RecursionParams;
00059 using urdf_traverser::LinkRecursionParams;
00060
00061 typedef urdf_traverser::VisualPtr VisualPtr;
00062 typedef urdf_traverser::CollisionPtr CollisionPtr;
00063 typedef urdf_traverser::GeometryPtr GeometryPtr;
00064 typedef urdf_traverser::MaterialPtr MaterialPtr;
00065 typedef urdf_traverser::MeshPtr MeshPtr;
00066 typedef urdf_traverser::SpherePtr SpherePtr;
00067 typedef urdf_traverser::CylinderPtr CylinderPtr;
00068 typedef urdf_traverser::BoxPtr BoxPtr;
00069
00070
00074 SoNode * convertMeshFile(const std::string& filename, double scale_factor, bool setExplicitMaterial = false, double r = 0.5, double g = 0.5, double b = 0.5, double a = 1)
00075 {
00076
00077 Assimp::Importer importer;
00078 const aiScene* scene = importer.ReadFile(filename, aiProcess_OptimizeGraph |
00079 aiProcess_FindInvalidData);
00080
00081
00082
00083
00084
00085
00086 if (!scene || !scene->mRootNode)
00087 {
00088 ROS_ERROR_STREAM("Could not import file " << filename);
00089 return NULL;
00090 }
00091
00092
00093 if (fabs(scale_factor - 1.0) > 1e-06)
00094 {
00095 ROS_INFO_STREAM("Scaling the mesh " << filename << " with factor " << scale_factor);
00096
00097 aiMatrix4x4 scaleTransform;
00098 aiMatrix4x4::Scaling(aiVector3D(scale_factor, scale_factor, scale_factor), scaleTransform);
00099
00100 scene->mRootNode->mTransformation *= scaleTransform;
00101 }
00102
00103 std::string sceneDir = boost::filesystem::path(filename).parent_path().string();
00104
00105 SoMaterial * overrideMaterial = NULL;
00106 if (setExplicitMaterial)
00107 {
00108 overrideMaterial = new SoMaterial();
00109 overrideMaterial->diffuseColor.setValue(r, g, b);
00110 overrideMaterial->transparency.setValue(1.0 - a);
00111 }
00112
00113 SoSeparator * ivScene = Assimp2Inventor(scene, sceneDir, overrideMaterial);
00114 if (!ivScene)
00115 {
00116 ROS_ERROR("Could not convert scene");
00117 return NULL;
00118 }
00119 return ivScene;
00120 }
00121
00122
00126 void urdf2inventor::removeTextureCopies(SoNode * root)
00127 {
00128 ROS_INFO("Removing texture copies in the model");
00129
00130 SoSearchAction sa;
00131 sa.setType(SoTexture2::getClassTypeId());
00132 sa.setInterest(SoSearchAction::ALL);
00133 sa.setSearchingAll(TRUE);
00134 sa.apply(root);
00135 SoPathList & pl = sa.getPaths();
00136 SbDict namedict;
00137
00138 for (int i = 0; i < pl.getLength(); i++)
00139 {
00140 SoFullPath * p = (SoFullPath*) pl[i];
00141 if (p->getTail()->isOfType(SoTexture2::getClassTypeId()))
00142 {
00143 SoTexture2 * tex = (SoTexture2*) p->getTail();
00144 if (tex->filename.getValue().getLength())
00145 {
00146 SbName name = tex->filename.getValue().getString();
00147
00148 unsigned long key = (unsigned long)((void*) name.getString());
00149 void * tmp;
00150 if (!namedict.find(key, tmp))
00151 {
00152
00153 (void) namedict.enter(key, tex);
00154 }
00155 else if (tmp != (void*) tex)
00156 {
00157 SoGroup * parent = (SoGroup*) p->getNodeFromTail(1);
00158 int idx = p->getIndexFromTail(0);
00159 parent->replaceChild(idx, (SoNode*) tmp);
00160 }
00161 }
00162 }
00163 }
00164 sa.reset();
00165 }
00166
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 bool addGeometry(SoSeparator * addToNode, const std::string& linkName, double scale_factor,
00221 const GeometryPtr& geom,
00222 const int geomNum,
00223 const MaterialPtr& mat,
00224 const urdf_traverser::EigenTransform& geometryTransform,
00225 const urdf_traverser::EigenTransform& addMeshTransform,
00226 const bool scaleUrdfTransforms)
00227 {
00228
00229 urdf_traverser::EigenTransform geomTransform = geometryTransform;
00230
00231 urdf_traverser::EigenTransform meshGeomTransform = geomTransform * addMeshTransform;
00232
00233 if (scaleUrdfTransforms) urdf_traverser::scaleTranslation(geomTransform, scale_factor);
00234
00235 switch (geom->type)
00236 {
00237 case urdf::Geometry::MESH:
00238 {
00239
00240 MeshPtr mesh = shr_lib::dynamic_pointer_cast<urdf::Mesh>(geom);
00241 if (!mesh.get())
00242 {
00243 ROS_ERROR("Mesh cast error");
00244 return false;
00245 }
00246 std::string meshFilename = urdf_traverser::helpers::packagePathToAbsolute(mesh->filename);
00247
00248 ROS_INFO_STREAM("Converting mesh file " << meshFilename << " with factor " << scale_factor);
00249 float r = 0.5;
00250 float g = 0.5;
00251 float b = 0.5;
00252 float a = 1.0;
00253 if (mat)
00254 {
00255 r = mat->color.r;
00256 g = mat->color.g;
00257 b = mat->color.b;
00258 a = mat->color.a;
00259 }
00260 SoNode * somesh = convertMeshFile(meshFilename, scale_factor, mat != NULL, r, g, b, a);
00261
00262 if (!somesh)
00263 {
00264 ROS_ERROR("Mesh could not be read");
00265 return false;
00266 }
00267 std::stringstream str;
00268 str << "_visual_" << geomNum << "_" << linkName;
00269
00270 somesh->setName(str.str().c_str());
00271 urdf2inventor::addSubNode(somesh, addToNode, meshGeomTransform);
00272 break;
00273 }
00274 case urdf::Geometry::SPHERE:
00275 {
00276 ROS_INFO("Urdf2Inventor: Model has a Sphere");
00277 SpherePtr sphere = shr_lib::dynamic_pointer_cast<urdf::Sphere>(geom);
00278 if (!sphere.get())
00279 {
00280 ROS_ERROR("Sphere cast error");
00281 return false;
00282 }
00283
00284 SoSeparator * sphereNode = new SoSeparator();
00285 sphereNode->ref();
00286 urdf2inventor::addSphere(addToNode, geomTransform.translation(), sphere->radius * scale_factor, 1, 0, 0);
00287 break;
00288 }
00289 case urdf::Geometry::BOX:
00290 {
00291 ROS_INFO("Urdf2Inventor: Model has a box");
00292 BoxPtr box = shr_lib::dynamic_pointer_cast<urdf::Box>(geom);
00293 if (!box.get())
00294 {
00295 ROS_ERROR("Box cast error");
00296 return false;
00297 }
00298
00299 SoSeparator * boxNode = new SoSeparator();
00300 boxNode->ref();
00301 ROS_INFO_STREAM("Geometry "<<geomNum<<" of link "<<linkName<<" transform: "<<geometryTransform);
00302 urdf2inventor::EigenTransform tmpT;
00303 urdf2inventor::EigenTransform geomTransformInv = geomTransform.inverse();
00304 tmpT.setIdentity();
00305 tmpT.translate(geomTransform.translation());
00306 tmpT.rotate(geomTransform.rotation());
00307 urdf2inventor::addBox(addToNode, tmpT, box->dim.x * scale_factor, box->dim.y * scale_factor, box->dim.z * scale_factor, 1, 0, 0, 0);
00308 break;
00309 }
00310 case urdf::Geometry::CYLINDER:
00311 {
00312 ROS_INFO("Urdf2Inventor: Model has a cylinder");
00313 CylinderPtr cylinder = shr_lib::dynamic_pointer_cast<urdf::Cylinder>(geom);
00314 if (!cylinder.get())
00315 {
00316 ROS_ERROR("Cylinder cast error");
00317 return false;
00318 }
00319
00320 SoSeparator * cylinderNode = new SoSeparator();
00321 cylinderNode->ref();
00322 urdf2inventor::addCylinder(addToNode, geomTransform, cylinder->radius/2, cylinder->length, 1, 0, 0, 0);
00323 break;
00324 }
00325 default:
00326 {
00327 ROS_ERROR_STREAM("This geometry type not supported so far: " << geom->type);
00328 return false;
00329 }
00330 }
00331
00332 return true;
00333 }
00334
00335
00336
00337
00338
00339
00340
00341
00342 SoNode * urdf2inventor::getAllGeometry(const urdf_traverser::LinkPtr link, double scale_factor,
00343 const urdf_traverser::EigenTransform& addVisualTransform,
00344 const bool useVisuals,
00345 const bool scaleUrdfTransforms)
00346 {
00347 SoNodeKit::init();
00348 SoSeparator * allVisuals = new SoSeparator();
00349 allVisuals->ref();
00350 std::string linkName = link->name;
00351
00352 if (useVisuals)
00353 {
00354 unsigned int i = 0;
00355 for (std::vector<VisualPtr>::const_iterator vit = link->visual_array.begin();
00356 vit != link->visual_array.end(); ++vit)
00357 {
00358 VisualPtr visual = (*vit);
00359 GeometryPtr geom = visual->geometry;
00360 MaterialPtr mat = visual->material;
00361
00362
00363
00364
00365 urdf_traverser::EigenTransform vTransform = urdf_traverser::getTransform(visual->origin);
00366
00367
00368 if (!addGeometry(allVisuals, linkName, scale_factor,
00369 geom, i, mat, vTransform, addVisualTransform, scaleUrdfTransforms))
00370 {
00371 ROS_ERROR_STREAM("Could not add geometry of link "<<link->name);
00372 return NULL;
00373 }
00374 ++i;
00375 }
00376 }
00377 else
00378 {
00379 unsigned int i = 0;
00380 for (std::vector<CollisionPtr>::const_iterator cit = link->collision_array.begin();
00381 cit != link->collision_array.end(); ++cit)
00382 {
00383 CollisionPtr coll = (*cit);
00384 GeometryPtr geom = coll->geometry;
00385
00386
00387
00388 MaterialPtr mat(new urdf::Material());
00389 mat->color.r=0.1;
00390 mat->color.g=0.1;
00391 mat->color.b=0.5;
00392 mat->color.a=1;
00393
00394 urdf_traverser::EigenTransform cTransform = urdf_traverser::getTransform(coll->origin);
00395
00396
00397 if (!addGeometry(allVisuals, linkName, scale_factor,
00398 geom, i, mat, cTransform, addVisualTransform, scaleUrdfTransforms))
00399 {
00400 ROS_ERROR_STREAM("Could not add geometry of link "<<link->name);
00401 return NULL;
00402 }
00403 ++i;
00404 }
00405 }
00406
00407 std::stringstream str;
00408 str << "_" << linkName;
00409
00410 allVisuals->setName(str.str().c_str());
00411
00412 return allVisuals;
00413 }
00414
00415
00423 bool convertMeshToIVString(urdf_traverser::LinkPtr& link,
00424 const float scale_factor,
00425 const urdf_traverser::EigenTransform& addVisualTransform,
00426 const bool useVisuals,
00427 const bool scaleUrdfTransforms,
00428 std::string& resultIV,
00429 std::set<std::string>& textureFiles)
00430 {
00431 ROS_INFO("Convert mesh for link '%s'", link->name.c_str());
00432
00433 SoNode * allVisuals = urdf2inventor::getAllGeometry(link, scale_factor, addVisualTransform, useVisuals, scaleUrdfTransforms);
00434 if (!allVisuals)
00435 {
00436 ROS_ERROR("Could not get visuals");
00437 return false;
00438 }
00439
00440
00441 if (!urdf2inventor::writeInventorFileString(allVisuals, resultIV))
00442 {
00443 ROS_ERROR("Could not get the mesh file content");
00444 return false;
00445 }
00446
00447
00448
00449
00450 textureFiles = urdf2inventor::getAllTexturePaths(allVisuals);
00451 return true;
00452 }
00453
00454
00459 int convertMeshToIVString(urdf_traverser::RecursionParamsPtr& p)
00460 {
00461 typedef urdf2inventor::MeshConvertRecursionParams<std::string> MeshConvertRecursionParamsT;
00462 typename MeshConvertRecursionParamsT::Ptr param = baselib_binding_ns::dynamic_pointer_cast<MeshConvertRecursionParamsT>(p);
00463 if (!param.get())
00464 {
00465 ROS_ERROR("Wrong recursion parameter type");
00466 return -1;
00467 }
00468
00469 bool useVisuals=true;
00470 urdf_traverser::LinkPtr link = param->getLink();
00471 std::string resultFileContent;
00472 std::set<std::string> textureFiles;
00473 if (!convertMeshToIVString(link, param->factor, param->getVisualTransform(), useVisuals, false, resultFileContent, textureFiles))
00474 return -1;
00475
00476
00477 if (!param->resultMeshes.insert(std::make_pair(link->name, resultFileContent)).second)
00478 {
00479 ROS_ERROR("Could not insert the resulting mesh file for link %s to the map", link->name.c_str());
00480 return -1;
00481 }
00482
00483 param->textureFiles[link->name].insert(textureFiles.begin(), textureFiles.end());
00484 return 1;
00485 }
00486
00487 #if 0
00488 template <class MeshFormat>
00489 bool urdf2inventor::convertMeshesSimple(urdf_traverser::UrdfTraverser& traverser,
00490 const std::string& fromLink,
00491 const float scaleFactor,
00492 const std::string& material,
00493 const std::string& file_extension,
00494 const urdf_traverser::EigenTransform& addVisualTransform,
00495 std::map<std::string, MeshFormat>& meshes,
00496 std::map<std::string, std::set<std::string> >& textureFiles)
00497 {
00498 std::string startLinkName = fromLink;
00499 if (startLinkName.empty())
00500 {
00501 startLinkName = traverser.getRootLinkName();
00502 }
00503
00504 urdf_traverser::LinkPtr startLink = traverser.getLink(startLinkName);
00505 if (!startLink.get())
00506 {
00507 ROS_ERROR("Link %s does not exist", startLinkName.c_str());
00508 return false;
00509 }
00510
00511
00512 typedef urdf2inventor::MeshConvertRecursionParams<MeshFormat> MeshConvertRecursionParamsT;
00513 typename MeshConvertRecursionParamsT::Ptr meshParams(
00514 new MeshConvertRecursionParamsT(scaleFactor, material, file_extension, addVisualTransform));
00515
00516 urdf_traverser::RecursionParamsPtr p(meshParams);
00517
00518
00519 if (traverser.traverseTreeTopDown(startLinkName, shr_lib::bind(&convertMeshToIVString, _1), p, true) <= 0)
00520 {
00521 ROS_ERROR("Could nto convert meshes.");
00522 return false;
00523 }
00524 meshes = meshParams->resultMeshes;
00525 textureFiles = meshParams->textureFiles;
00526
00527 return true;
00528 }
00529 #endif
00530
00531 template <class MeshFormat>
00532 bool urdf2inventor::convertMeshes(urdf_traverser::UrdfTraverser& traverser,
00533 const std::string& fromLink,
00534 const typename urdf2inventor::MeshConvertRecursionParams<MeshFormat>::Ptr& meshParams)
00535 {
00536 if (!meshParams)
00537 {
00538 ROS_ERROR("Need to specify mesh parameters");
00539 return false;
00540 }
00541
00542 std::string startLinkName = fromLink;
00543 if (startLinkName.empty())
00544 {
00545 startLinkName = traverser.getRootLinkName();
00546 }
00547
00548 urdf_traverser::LinkPtr startLink = traverser.getLink(startLinkName);
00549 if (!startLink.get())
00550 {
00551 ROS_ERROR("Link %s does not exist", startLinkName.c_str());
00552 return false;
00553 }
00554
00555
00556 urdf_traverser::RecursionParamsPtr p(meshParams);
00557 if (traverser.traverseTreeTopDown(startLinkName, boost::bind(&convertMeshToIVString, _1), p, true) <= 0)
00558 {
00559 ROS_ERROR("Could nto convert meshes.");
00560 return false;
00561 }
00562 return true;
00563 }
00564
00565 bool urdf2inventor::fixTextureReferences(
00566 const std::string& relMeshDir,
00567 const std::string& relTexDir,
00568 const std::map<std::string, std::set<std::string> >& textureFiles,
00569 std::map<std::string, std::string>& meshes,
00570 std::map<std::string, std::set<std::string> >& texturesToCopy)
00571 {
00572
00573 std::set<std::string> allTextures;
00574 for (std::map<std::string, std::set<std::string> >::const_iterator it = textureFiles.begin(); it != textureFiles.end(); ++it)
00575 allTextures.insert(it->second.begin(), it->second.end());
00576
00577
00578 if (allTextures.empty()) return true;
00579
00580 ROS_INFO_STREAM("Fixing texture references to point from " << relMeshDir << " files to textures in " << relTexDir);
00581 std::string _relMeshDir(relMeshDir);
00582 std::string _relTexDir(relTexDir);
00583 urdf_traverser::helpers::enforceDirectory(_relMeshDir, true);
00584 urdf_traverser::helpers::enforceDirectory(_relTexDir, true);
00585
00586 std::string commonParent;
00587 if (!urdf_traverser::helpers::getCommonParentPath(allTextures, commonParent))
00588 {
00589 ROS_ERROR_STREAM("Could not find common parent path of all textures");
00590 return false;
00591 }
00592
00593 ROS_INFO_STREAM("Common parent path for all textures: " << commonParent);
00594
00595 for (std::map<std::string, std::set<std::string> >::const_iterator it = textureFiles.begin(); it != textureFiles.end(); ++it)
00596 {
00597 std::string meshFile = it->first;
00598 std::string meshDirectory = urdf_traverser::helpers::getDirectory(meshFile);
00599
00600 std::stringstream relMeshInstallFile;
00601 relMeshInstallFile << _relMeshDir << meshDirectory;
00602
00603
00604 typename std::map<std::string, std::string>::iterator meshString = meshes.find(meshFile);
00605 if (meshString == meshes.end())
00606 {
00607 ROS_ERROR_STREAM("Consistency: Mesh " << meshFile << " should have been in meshes map");
00608 return false;
00609 }
00610
00611 if (!urdf2inventor::helpers::fixFileReferences(relMeshInstallFile.str(), _relTexDir, commonParent, it->second,
00612 meshString->second, texturesToCopy))
00613 {
00614 ROS_ERROR_STREAM("Could not fix file references");
00615 return false;
00616 }
00617 }
00618 return true;
00619 }
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633 template bool urdf2inventor::convertMeshes<std::string>(urdf_traverser::UrdfTraverser& traverser,
00634 const std::string& fromLink,
00635 const urdf2inventor::MeshConvertRecursionParams<std::string>::Ptr& meshParams);