From c258d7b00a91c759147d4f1f33553bda5e73e932 Mon Sep 17 00:00:00 2001 From: Valenza Florian <fvalenza@laas.fr> Date: Mon, 11 Jan 2016 11:13:24 +0100 Subject: [PATCH] [C++][CMake][Doc] Split geometry parser into two parts.Added guard to file to avoid multiple redefinition --- CMakeLists.txt | 2 + src/multibody/geometry.hpp | 194 +-------------- src/multibody/geometry.hxx | 237 +++++++++++++++++++ src/multibody/parser/from-collada-to-fcl.hpp | 50 +++- src/multibody/parser/urdf-with-geometry.hpp | 130 ++++------ src/multibody/parser/urdf-with-geometry.hxx | 130 ++++++++++ 6 files changed, 468 insertions(+), 275 deletions(-) create mode 100644 src/multibody/geometry.hxx create mode 100644 src/multibody/parser/urdf-with-geometry.hxx diff --git a/CMakeLists.txt b/CMakeLists.txt index 33ffd5999..71bea9b02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -178,6 +178,7 @@ IF(URDFDOM_FOUND) LIST(APPEND ${PROJECT_NAME}_MULTIBODY_PARSER_HEADERS multibody/parser/from-collada-to-fcl.hpp multibody/parser/urdf-with-geometry.hpp + multibody/parser/urdf-with-geometry.hxx ) ENDIF(HPP_FCL_FOUND) @@ -190,6 +191,7 @@ IF(HPP_FCL_FOUND) ) LIST(APPEND ${PROJECT_NAME}_MULTIBODY_HEADERS multibody/geometry.hpp + multibody/geometry.hxx ) ENDIF(HPP_FCL_FOUND) diff --git a/src/multibody/geometry.hpp b/src/multibody/geometry.hpp index 0966c5986..9f7851de7 100644 --- a/src/multibody/geometry.hpp +++ b/src/multibody/geometry.hpp @@ -189,195 +189,11 @@ namespace se3 }; - inline GeometryModel::Index GeometryModel::addGeomObject( Index parent,const fcl::CollisionObject & co, const SE3 & placement, const std::string & geoName ) - { - - Index idx = (Index) (ngeom ++); - - - collision_objects .push_back(co); - geom_parents .push_back(parent); - geometryPlacement .push_back(placement); - geom_names .push_back( (geoName!="")?geoName:random(8)); - - return idx; - } - inline GeometryModel::Index GeometryModel::getGeomId( const std::string & name ) const - { - std::vector<std::string>::iterator::difference_type - res = std::find(geom_names.begin(),geom_names.end(),name) - geom_names.begin(); - assert( (res<INT_MAX) && "Id superior to int range. Should never happen."); - assert( (res>=0)&&(res<(long)collision_objects.size())&&"The joint name you asked do not exist" ); - return Index(res); - } - inline bool GeometryModel::existGeomName( const std::string & name ) const - { - return (geom_names.end() != std::find(geom_names.begin(),geom_names.end(),name)); - } - inline const std::string& GeometryModel::getGeomName( Index index ) const - { - assert( index < (Index)collision_objects.size() ); - return geom_names[index]; - } - - inline void GeometryModel::addInnerObject(Index joint, Index inner_object) - { - innerObjects[joint].push_back(inner_object); - } - - inline void GeometryModel::addOutterObject(Index joint, Index outer_object) - { - outerObjects[joint].push_back(outer_object); - } - - inline std::ostream& operator<<(std::ostream& os, const GeometryModel& model_geom) - { - os << "Nb collision objects = " << model_geom.ngeom << std::endl; - - for(GeometryModel::Index i=0;i<(GeometryModel::Index)(model_geom.ngeom);++i) - { - os << "Object n " << i << " : " << model_geom.geom_names[i] << ": attached to joint = " << model_geom.geom_parents[i] - << "\nwith offset \n" << model_geom.geometryPlacement[i] <<std::endl; - } - - return os; - } - - inline std::ostream& operator<<(std::ostream& os, const GeometryData& data_geom) - { - - for(GeometryData::Index i=0;i<(GeometryData::Index)(data_geom.model_geom.ngeom);++i) - { - os << "collision object oMi " << data_geom.oMg[i] << std::endl; - } - - return os; - } - - inline void GeometryData::addCollisionPair (Index co1, Index co2) - { - assert ( co1 < co2); - assert ( co2 < model_geom.ngeom); - CollisionPair_t pair(co1, co2); - - addCollisionPair(pair); - } - - inline void GeometryData::addCollisionPair (const CollisionPair_t& pair) - { - assert(pair.first < pair.second); - assert(pair.second < model_geom.ngeom); - collision_pairs.push_back(pair); - nCollisionPairs++; - } - - inline void GeometryData::removeCollisionPair (Index co1, Index co2) - { - assert(co1 < co2); - assert(co2 < model_geom.ngeom); - assert(isCollisionPair(co1,co2)); - - removeCollisionPair (CollisionPair_t(co1,co2)); - } - - inline void GeometryData::removeCollisionPair (const CollisionPair_t& pair) - { - assert(pair.first < pair.second); - assert(pair.second < model_geom.ngeom); - assert(isCollisionPair(pair)); - - collision_pairs.erase(std::remove(collision_pairs.begin(), collision_pairs.end(), pair), collision_pairs.end()); - nCollisionPairs--; - } - - inline bool GeometryData::isCollisionPair (Index co1, Index co2) const - { - return isCollisionPair(CollisionPair_t(co1,co2)); - } - - inline bool GeometryData::isCollisionPair (const CollisionPair_t& pair) const - { - return (std::find_if ( collision_pairs.begin(), collision_pairs.end(), - IsSameCollisionPair(pair)) != collision_pairs.end()); - - } - - inline void GeometryData::fillAllPairsAsCollisions() - { - for (Index i = 0; i < model_geom.ngeom; ++i) - { - for (Index j = i+1; j < model_geom.ngeom; ++j) - { - addCollisionPair(i,j); - } - } - } - - // TODO : give a srdf file as argument, read it, and remove corresponding - // pairs from list collision_pairs - inline void GeometryData::desactivateCollisionPairs() - { - - } - - inline void GeometryData::initializeListOfCollisionPairs() - { - fillAllPairsAsCollisions(); - desactivateCollisionPairs(); - assert(nCollisionPairs == collision_pairs.size()); - } - - inline bool GeometryData::collide(Index co1, Index co2) const - { - fcl::CollisionRequest collisionRequest (1, false, false, 1, false, true, fcl::GST_INDEP); - fcl::CollisionResult collisionResult; - - if (fcl::collide (model_geom.collision_objects[co1].collisionGeometry().get(), oMg_fcl[co1], - model_geom.collision_objects[co2].collisionGeometry().get(), oMg_fcl[co2], - collisionRequest, collisionResult) != 0) - { - return true; - } - return false; - } - - inline bool GeometryData::isColliding() const - { - for (std::vector<CollisionPair_t>::const_iterator it = collision_pairs.begin(); it != collision_pairs.end(); ++it) - { - if (collide(it->first, it->second)) - { - return true; - } - } - return false; - } - - inline fcl::DistanceResult GeometryData::computeDistance(Index co1, Index co2) const - { - fcl::DistanceRequest distanceRequest (true, 0, 0, fcl::GST_INDEP); - fcl::DistanceResult result; - fcl::distance ( model_geom.collision_objects[co1].collisionGeometry().get(), oMg_fcl[co1], - model_geom.collision_objects[co2].collisionGeometry().get(), oMg_fcl[co2], - distanceRequest, result); - return result; - } - - inline void GeometryData::resetDistances() - { - std::fill(distances.begin(), distances.end(), DistanceResult( fcl::DistanceResult(), 0, 0) ); - } - - inline void GeometryData::computeDistances () - { - std::size_t cpt = 0; - for (std::vector<CollisionPair_t>::iterator it = collision_pairs.begin(); it != collision_pairs.end(); ++it) - { - distances[cpt] = DistanceResult(computeDistance(it->first, it->second), it->first, it->second); - cpt++; - } - } - } // namespace se3 +/* --- Details -------------------------------------------------------------- */ +/* --- Details -------------------------------------------------------------- */ +/* --- Details -------------------------------------------------------------- */ +#include "pinocchio/multibody/geometry.hxx" + #endif // ifndef __se3_geom_hpp__ diff --git a/src/multibody/geometry.hxx b/src/multibody/geometry.hxx new file mode 100644 index 000000000..1812367d8 --- /dev/null +++ b/src/multibody/geometry.hxx @@ -0,0 +1,237 @@ +// +// Copyright (c) 2015 CNRS +// +// This file is part of Pinocchio +// Pinocchio is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation, either version +// 3 of the License, or (at your option) any later version. +// +// Pinocchio is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Lesser Public License for more details. You should have +// received a copy of the GNU Lesser General Public License along with +// Pinocchio If not, see +// <http://www.gnu.org/licenses/>. + +#ifndef __se3_geom_hxx__ +#define __se3_geom_hxx__ + + +#include "pinocchio/spatial/fwd.hpp" +#include "pinocchio/spatial/se3.hpp" +#include "pinocchio/spatial/force.hpp" +#include "pinocchio/spatial/motion.hpp" +#include "pinocchio/spatial/inertia.hpp" +#include "pinocchio/spatial/fcl-pinocchio-conversions.hpp" +#include "pinocchio/multibody/model.hpp" +#include "pinocchio/multibody/joint/joint-variant.hpp" +#include <iostream> + +#include <hpp/fcl/collision_object.h> +#include <hpp/fcl/collision.h> +#include <hpp/fcl/distance.h> +#include <map> +#include <list> +#include <utility> + + +namespace se3 +{ + + inline GeometryModel::Index GeometryModel::addGeomObject( Index parent,const fcl::CollisionObject & co, const SE3 & placement, const std::string & geoName ) + { + + Index idx = (Index) (ngeom ++); + + + collision_objects .push_back(co); + geom_parents .push_back(parent); + geometryPlacement .push_back(placement); + geom_names .push_back( (geoName!="")?geoName:random(8)); + + return idx; + } + + inline GeometryModel::Index GeometryModel::getGeomId( const std::string & name ) const + { + std::vector<std::string>::iterator::difference_type + res = std::find(geom_names.begin(),geom_names.end(),name) - geom_names.begin(); + assert( (res<INT_MAX) && "Id superior to int range. Should never happen."); + assert( (res>=0)&&(res<(long)collision_objects.size())&&"The joint name you asked do not exist" ); + return Index(res); + } + + inline bool GeometryModel::existGeomName( const std::string & name ) const + { + return (geom_names.end() != std::find(geom_names.begin(),geom_names.end(),name)); + } + + inline const std::string& GeometryModel::getGeomName( Index index ) const + { + assert( index < (Index)collision_objects.size() ); + return geom_names[index]; + } + + inline void GeometryModel::addInnerObject(Index joint, Index inner_object) + { + innerObjects[joint].push_back(inner_object); + } + + inline void GeometryModel::addOutterObject(Index joint, Index outer_object) + { + outerObjects[joint].push_back(outer_object); + } + + inline std::ostream& operator<<(std::ostream& os, const GeometryModel& model_geom) + { + os << "Nb collision objects = " << model_geom.ngeom << std::endl; + + for(GeometryModel::Index i=0;i<(GeometryModel::Index)(model_geom.ngeom);++i) + { + os << "Object n " << i << " : " << model_geom.geom_names[i] << ": attached to joint = " << model_geom.geom_parents[i] + << "\nwith offset \n" << model_geom.geometryPlacement[i] <<std::endl; + } + + return os; + } + + inline std::ostream& operator<<(std::ostream& os, const GeometryData& data_geom) + { + + for(GeometryData::Index i=0;i<(GeometryData::Index)(data_geom.model_geom.ngeom);++i) + { + os << "collision object oMi " << data_geom.oMg[i] << std::endl; + } + + return os; + } + + inline void GeometryData::addCollisionPair (Index co1, Index co2) + { + assert ( co1 < co2); + assert ( co2 < model_geom.ngeom); + CollisionPair_t pair(co1, co2); + + addCollisionPair(pair); + } + + inline void GeometryData::addCollisionPair (const CollisionPair_t& pair) + { + assert(pair.first < pair.second); + assert(pair.second < model_geom.ngeom); + collision_pairs.push_back(pair); + nCollisionPairs++; + } + + inline void GeometryData::removeCollisionPair (Index co1, Index co2) + { + assert(co1 < co2); + assert(co2 < model_geom.ngeom); + assert(isCollisionPair(co1,co2)); + + removeCollisionPair (CollisionPair_t(co1,co2)); + } + + inline void GeometryData::removeCollisionPair (const CollisionPair_t& pair) + { + assert(pair.first < pair.second); + assert(pair.second < model_geom.ngeom); + assert(isCollisionPair(pair)); + + collision_pairs.erase(std::remove(collision_pairs.begin(), collision_pairs.end(), pair), collision_pairs.end()); + nCollisionPairs--; + } + + inline bool GeometryData::isCollisionPair (Index co1, Index co2) const + { + return isCollisionPair(CollisionPair_t(co1,co2)); + } + + inline bool GeometryData::isCollisionPair (const CollisionPair_t& pair) const + { + return (std::find_if ( collision_pairs.begin(), collision_pairs.end(), + IsSameCollisionPair(pair)) != collision_pairs.end()); + + } + + inline void GeometryData::fillAllPairsAsCollisions() + { + for (Index i = 0; i < model_geom.ngeom; ++i) + { + for (Index j = i+1; j < model_geom.ngeom; ++j) + { + addCollisionPair(i,j); + } + } + } + + // TODO : give a srdf file as argument, read it, and remove corresponding + // pairs from list collision_pairs + inline void GeometryData::desactivateCollisionPairs() + { + + } + + inline void GeometryData::initializeListOfCollisionPairs() + { + fillAllPairsAsCollisions(); + desactivateCollisionPairs(); + assert(nCollisionPairs == collision_pairs.size()); + } + + inline bool GeometryData::collide(Index co1, Index co2) const + { + fcl::CollisionRequest collisionRequest (1, false, false, 1, false, true, fcl::GST_INDEP); + fcl::CollisionResult collisionResult; + + if (fcl::collide (model_geom.collision_objects[co1].collisionGeometry().get(), oMg_fcl[co1], + model_geom.collision_objects[co2].collisionGeometry().get(), oMg_fcl[co2], + collisionRequest, collisionResult) != 0) + { + return true; + } + return false; + } + + inline bool GeometryData::isColliding() const + { + for (std::vector<CollisionPair_t>::const_iterator it = collision_pairs.begin(); it != collision_pairs.end(); ++it) + { + if (collide(it->first, it->second)) + { + return true; + } + } + return false; + } + + inline fcl::DistanceResult GeometryData::computeDistance(Index co1, Index co2) const + { + fcl::DistanceRequest distanceRequest (true, 0, 0, fcl::GST_INDEP); + fcl::DistanceResult result; + fcl::distance ( model_geom.collision_objects[co1].collisionGeometry().get(), oMg_fcl[co1], + model_geom.collision_objects[co2].collisionGeometry().get(), oMg_fcl[co2], + distanceRequest, result); + return result; + } + + inline void GeometryData::resetDistances() + { + std::fill(distances.begin(), distances.end(), DistanceResult( fcl::DistanceResult(), 0, 0) ); + } + + inline void GeometryData::computeDistances () + { + std::size_t cpt = 0; + for (std::vector<CollisionPair_t>::iterator it = collision_pairs.begin(); it != collision_pairs.end(); ++it) + { + distances[cpt] = DistanceResult(computeDistance(it->first, it->second), it->first, it->second); + cpt++; + } + } + +} // namespace se3 + +#endif // ifndef __se3_geom_hxx__ diff --git a/src/multibody/parser/from-collada-to-fcl.hpp b/src/multibody/parser/from-collada-to-fcl.hpp index d46ec85c3..75938acb5 100644 --- a/src/multibody/parser/from-collada-to-fcl.hpp +++ b/src/multibody/parser/from-collada-to-fcl.hpp @@ -15,6 +15,10 @@ // received a copy of the GNU Lesser General Public License along with // Pinocchio If not, see // <http://www.gnu.org/licenses/>. + +#ifndef __se3_collada_to_fcl_hpp__ +#define __se3_collada_to_fcl_hpp__ + #include <limits> #include <boost/filesystem/fstream.hpp> @@ -47,7 +51,18 @@ struct TriangleAndVertices std::vector <fcl::Triangle> triangles_; }; -void buildMesh (const ::urdf::Vector3& scale, const aiScene* scene, const aiNode* node, + +/** + * @brief Recursive procedure for building a mesh + * + * @param[in] scale Scale to apply when reading the ressource + * @param[in] scene Pointer to the assimp scene + * @param[in] node Current node of the scene + * @param subMeshIndexes Submesh triangles indexes interval + * @param[in] mesh The mesh that must be built + * @param tv Triangles and Vertices of the mesh submodels + */ +inline void buildMesh (const ::urdf::Vector3& scale, const aiScene* scene, const aiNode* node, std::vector<unsigned>& subMeshIndexes, const PolyhedronPtrType& mesh, TriangleAndVertices& tv) { @@ -109,7 +124,16 @@ void buildMesh (const ::urdf::Vector3& scale, const aiScene* scene, const aiNode } -void meshFromAssimpScene (const std::string& name, const ::urdf::Vector3& scale, + +/** + * @brief Convert an assimp scene to a mesh + * + * @param[in] name File (ressource) transformed into an assimp scene in loa + * @param[in] scale Scale to apply when reading the ressource + * @param[in] scene Pointer to the assimp scene + * @param[in] mesh The mesh that must be built + */ +inline void meshFromAssimpScene (const std::string& name, const ::urdf::Vector3& scale, const aiScene* scene,const PolyhedronPtrType& mesh) { TriangleAndVertices tv; @@ -138,7 +162,15 @@ void meshFromAssimpScene (const std::string& name, const ::urdf::Vector3& scale, mesh->endModel (); } -void loadPolyhedronFromResource ( const std::string& resource_path, const ::urdf::Vector3& scale, + +/** + * @brief Read a mesh file and convert it to a polyhedral mesh + * + * @param[in] resource_path Path to the ressource mesh file to be read + * @param[in] scale Scale to apply when reading the ressource + * @param[in] polyhedron The resulted polyhedron + */ +inline void loadPolyhedronFromResource ( const std::string& resource_path, const ::urdf::Vector3& scale, const PolyhedronPtrType& polyhedron) { Assimp::Importer importer; @@ -154,7 +186,16 @@ void loadPolyhedronFromResource ( const std::string& resource_path, const ::urdf meshFromAssimpScene (resource_path, scale, scene, polyhedron); } -std::string fromURDFMeshPathToAbsolutePath(std::string & urdf_mesh_path, std::string meshRootDir) + +/** + * @brief Transform a cURL readable path (package://..) to an absolute path for urdf collision path + * + * @param urdf_mesh_path The path given in the urdf file (package://..) + * @param[in] meshRootDir Root path to the directory where meshes are located + * + * @return The absolute path to the mesh file + */ +inline std::string fromURDFMeshPathToAbsolutePath(std::string & urdf_mesh_path, std::string meshRootDir) { std::string absolutePath = std::string(meshRootDir + @@ -163,3 +204,4 @@ std::string fromURDFMeshPathToAbsolutePath(std::string & urdf_mesh_path, std::st return absolutePath; } +#endif // __se3_collada_to_fcl_hpp__ diff --git a/src/multibody/parser/urdf-with-geometry.hpp b/src/multibody/parser/urdf-with-geometry.hpp index 1fa726017..27c7227c1 100644 --- a/src/multibody/parser/urdf-with-geometry.hpp +++ b/src/multibody/parser/urdf-with-geometry.hpp @@ -47,95 +47,61 @@ namespace se3 { -fcl::CollisionObject retrieveCollisionGeometry (const ::urdf::LinkConstPtr & link, std::string meshRootDir) - { - boost::shared_ptr < ::urdf::Collision> collision = link->collision; - boost::shared_ptr < fcl::CollisionGeometry > geometry; - - // Handle the case where collision geometry is a mesh - if (collision->geometry->type == ::urdf::Geometry::MESH) - { - boost::shared_ptr < ::urdf::Mesh> collisionGeometry = boost::dynamic_pointer_cast< ::urdf::Mesh> (collision->geometry); - std::string collisionFilename = collisionGeometry->filename; - - std::string full_path = fromURDFMeshPathToAbsolutePath(collisionFilename, meshRootDir); + /** + * @brief Get a CollisionObject from an urdf link, reading the + * corresponding mesh + * + * @param[in] link The input urdf link + * @param[in] meshRootDir Root path to the directory where meshes are located + * + * @return The mesh converted as a fcl::CollisionObject + */ + inline fcl::CollisionObject retrieveCollisionGeometry (const ::urdf::LinkConstPtr & link, std::string meshRootDir); - ::urdf::Vector3 scale = collisionGeometry->scale; - - // Create FCL mesh by parsing Collada file. - PolyhedronPtrType polyhedron (new PolyhedronType); - - loadPolyhedronFromResource (full_path, scale, polyhedron); - geometry = polyhedron; - } - - // Compute body position in world frame. - // MatrixHomogeneousType position = computeBodyAbsolutePosition (link, collision->origin); - if (!geometry) - { - throw std::runtime_error(std::string("The polyhedron retrived is empty")); - } - fcl::CollisionObject collisionObject (geometry, fcl::Transform3f()); - - return collisionObject; // TO CHECK: what happens if geometry is empty ? - - } - - void parseTreeForGeom( ::urdf::LinkConstPtr link, Model & model,GeometryModel & model_geom, std::string meshRootDir) throw (std::invalid_argument) -{ - - ::urdf::JointConstPtr joint = link->parent_joint; - - if(joint!=NULL) - { - assert(link->getParent()!=NULL); - - if (link->collision) - { - fcl::CollisionObject collision_object = retrieveCollisionGeometry(link, meshRootDir); - SE3 geomPlacement = convertFromUrdf(link->collision->origin); - std::string collision_object_name = link->name ; - model_geom.addGeomObject(model.getJointId(joint->name), collision_object, geomPlacement, collision_object_name); - } - } - else if (link->getParent() != NULL) - { - const std::string exception_message (link->name + " - joint information missing."); - throw std::invalid_argument(exception_message); - } - - BOOST_FOREACH(::urdf::LinkConstPtr child,link->child_links) - { - parseTreeForGeom(child, model, model_geom, meshRootDir); - } -} - + /** + * @brief Recursive procedure for reading the URDF tree, looking for geometries + * This function fill the geometric model whith geometry objects retrieved from the URDF tree + * + * @param[in] link The current URDF link + * @param model The model to which is the Geometry Model associated + * @param model_geom The Geometry Model where the Collision Objects must be added + * @param[in] meshRootDir Root path to the directory where meshes are located + */ + inline void parseTreeForGeom( ::urdf::LinkConstPtr link, Model & model,GeometryModel & model_geom, std::string meshRootDir) throw (std::invalid_argument); + + + + /** + * @brief Build The Model and GeometryModel from a URDF file with a particular joint as root of the model tree + * + * @param[in] filename The URDF complete file path + * @param[in] meshRootDir Root path to the directory where meshes are located + * + * @return The pair <se3::Model, se3::GeometryModel> the Model tree and its geometric model associated + */ + template <typename D> + std::pair<Model, GeometryModel > buildModelAndGeom( const std::string & filename, const std::string & meshRootDir, const JointModelBase<D> & root_joint ); - template <typename D> - std::pair<Model, GeometryModel > buildModelAndGeom( const std::string & filename, const std::string & meshRootDir, const JointModelBase<D> & root_joint ) - { - Model model; GeometryModel model_geom; - - ::urdf::ModelInterfacePtr urdfTree = ::urdf::parseURDFFile (filename); - parseTree(urdfTree->getRoot(), model, SE3::Identity(), root_joint); - parseTreeForGeom(urdfTree->getRoot(), model, model_geom, meshRootDir); - return std::make_pair(model, model_geom); - } - - std::pair<Model, GeometryModel > buildModelAndGeom( const std::string & filename, const std::string & meshRootDir) - { - Model model; GeometryModel model_geom; - - ::urdf::ModelInterfacePtr urdfTree = ::urdf::parseURDFFile (filename); - parseTree(urdfTree->getRoot(), model, SE3::Identity()); - parseTreeForGeom(urdfTree->getRoot(), model, model_geom, meshRootDir); - return std::make_pair(model, model_geom); - } + /** + * @brief Build The Model and GeometryModel from a URDF file with no root joint added to the model tree + * + * @param[in] filename The URDF complete file path + * @param[in] meshRootDir Root path to the directory where meshes are located + * + * @return The pair <se3::Model, se3::GeometryModel> the Model tree and its geometric model associated + */ + inline std::pair<Model, GeometryModel > buildModelAndGeom( const std::string & filename, const std::string & meshRootDir); } // namespace urdf } // namespace se3 + +/* --- Details -------------------------------------------------------------- */ +/* --- Details -------------------------------------------------------------- */ +/* --- Details -------------------------------------------------------------- */ +#include "pinocchio/multibody/parser/urdf-with-geometry.hxx" + #endif // ifndef __se3_urdf_geom_hpp__ diff --git a/src/multibody/parser/urdf-with-geometry.hxx b/src/multibody/parser/urdf-with-geometry.hxx new file mode 100644 index 000000000..7ff1fa337 --- /dev/null +++ b/src/multibody/parser/urdf-with-geometry.hxx @@ -0,0 +1,130 @@ +// +// Copyright (c) 2015 CNRS +// +// This file is part of Pinocchio +// Pinocchio is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation, either version +// 3 of the License, or (at your option) any later version. +// +// Pinocchio is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Lesser Public License for more details. You should have +// received a copy of the GNU Lesser General Public License along with +// Pinocchio If not, see +// <http://www.gnu.org/licenses/>. + +#ifndef __se3_urdf_geom_hxx__ +#define __se3_urdf_geom_hxx__ + +#include <urdf_model/model.h> +#include <urdf_parser/urdf_parser.h> + +#include <iostream> +#include <boost/foreach.hpp> +#include "pinocchio/multibody/model.hpp" + +#include <hpp/fcl/collision_object.h> +#include <hpp/fcl/collision.h> +#include <hpp/fcl/shape/geometric_shapes.h> +#include "pinocchio/multibody/parser/from-collada-to-fcl.hpp" + +#include <exception> + + +namespace se3 +{ + namespace urdf + { + + + inline fcl::CollisionObject retrieveCollisionGeometry (const ::urdf::LinkConstPtr & link, std::string meshRootDir) + { + boost::shared_ptr < ::urdf::Collision> collision = link->collision; + boost::shared_ptr < fcl::CollisionGeometry > geometry; + + // Handle the case where collision geometry is a mesh + if (collision->geometry->type == ::urdf::Geometry::MESH) + { + boost::shared_ptr < ::urdf::Mesh> collisionGeometry = boost::dynamic_pointer_cast< ::urdf::Mesh> (collision->geometry); + std::string collisionFilename = collisionGeometry->filename; + + std::string full_path = fromURDFMeshPathToAbsolutePath(collisionFilename, meshRootDir); + + ::urdf::Vector3 scale = collisionGeometry->scale; + + // Create FCL mesh by parsing Collada file. + PolyhedronPtrType polyhedron (new PolyhedronType); + + loadPolyhedronFromResource (full_path, scale, polyhedron); + geometry = polyhedron; + } + + if (!geometry) + { + throw std::runtime_error(std::string("The polyhedron retrived is empty")); + } + fcl::CollisionObject collisionObject (geometry, fcl::Transform3f()); + + return collisionObject; // TO CHECK: what happens if geometry is empty ? + } + + + inline void parseTreeForGeom( ::urdf::LinkConstPtr link, Model & model,GeometryModel & model_geom, std::string meshRootDir) throw (std::invalid_argument) + { + + ::urdf::JointConstPtr joint = link->parent_joint; + + if(joint!=NULL) + { + assert(link->getParent()!=NULL); + + if (link->collision) + { + fcl::CollisionObject collision_object = retrieveCollisionGeometry(link, meshRootDir); + SE3 geomPlacement = convertFromUrdf(link->collision->origin); + std::string collision_object_name = link->name ; + model_geom.addGeomObject(model.getJointId(joint->name), collision_object, geomPlacement, collision_object_name); + } + } + else if (link->getParent() != NULL) + { + const std::string exception_message (link->name + " - joint information missing."); + throw std::invalid_argument(exception_message); + } + + BOOST_FOREACH(::urdf::LinkConstPtr child,link->child_links) + { + parseTreeForGeom(child, model, model_geom, meshRootDir); + } + } + + + + template <typename D> + std::pair<Model, GeometryModel > buildModelAndGeom( const std::string & filename, const std::string & meshRootDir, const JointModelBase<D> & root_joint ) + { + Model model; GeometryModel model_geom; + + ::urdf::ModelInterfacePtr urdfTree = ::urdf::parseURDFFile (filename); + parseTree(urdfTree->getRoot(), model, SE3::Identity(), root_joint); + parseTreeForGeom(urdfTree->getRoot(), model, model_geom, meshRootDir); + return std::make_pair(model, model_geom); + } + + inline std::pair<Model, GeometryModel > buildModelAndGeom( const std::string & filename, const std::string & meshRootDir) + { + Model model; GeometryModel model_geom; + + ::urdf::ModelInterfacePtr urdfTree = ::urdf::parseURDFFile (filename); + parseTree(urdfTree->getRoot(), model, SE3::Identity()); + parseTreeForGeom(urdfTree->getRoot(), model, model_geom, meshRootDir); + return std::make_pair(model, model_geom); + } + + } // namespace urdf +} // namespace se3 + +#endif // ifndef __se3_urdf_geom_hxx__ + -- GitLab