geometry.hxx 13.05 KiB
//
// Copyright (c) 2015-2016 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_algo_geometry_hxx__
#define __se3_algo_geometry_hxx__
#include <boost/foreach.hpp>
namespace se3
{
/* --- GEOMETRY PLACEMENTS -------------------------------------------------------- */
/* --- GEOMETRY PLACEMENTS -------------------------------------------------------- */
/* --- GEOMETRY PLACEMENTS -------------------------------------------------------- */
inline void updateGeometryPlacements(const Model & model,
Data & data,
const GeometryModel & geomModel,
GeometryData & geomData,
const Eigen::VectorXd & q
)
{
forwardKinematics(model, data, q);
updateGeometryPlacements(model, data, geomModel, geomData);
}
inline void updateGeometryPlacements(const Model &,
const Data & data,
const GeometryModel & geomModel,
GeometryData & geomData
)
{
for (GeomIndex i=0; i < (GeomIndex) geomModel.ngeoms; ++i)
{
const Model::JointIndex & joint = geomModel.geometryObjects[i].parentJoint;
if (joint>0) geomData.oMg[i] = (data.oMi[joint] * geomModel.geometryObjects[i].placement);
else geomData.oMg[i] = geomModel.geometryObjects[i].placement;
#ifdef WITH_HPP_FCL
geomData.collisionObjects[i].setTransform( toFclTransform3f(geomData.oMg[i]) );
#endif // WITH_HPP_FCL
}
}
#ifdef WITH_HPP_FCL
/* --- COLLISIONS ----------------------------------------------------------------- */
/* --- COLLISIONS ----------------------------------------------------------------- */
/* --- COLLISIONS ----------------------------------------------------------------- */
inline bool computeCollision(const GeometryModel & geomModel,
GeometryData & geomData,
const PairIndex& pairId)
{
assert( pairId < geomModel.collisionPairs.size() );
const CollisionPair & pair = geomModel.collisionPairs[pairId];
assert( pairId < geomData.collisionResults.size() );
assert( pair.first < geomData.collisionObjects.size() );
assert( pair.second < geomData.collisionObjects.size() );
fcl::CollisionResult& collisionResult = geomData.collisionResults[pairId];
collisionResult.clear();
fcl::collide (&geomData.collisionObjects[pair.first],
&geomData.collisionObjects[pair.second],
geomData.collisionRequest,
collisionResult);
return collisionResult.isCollision();
}
inline bool computeCollisions(const GeometryModel & geomModel,
GeometryData & geomData,
const bool stopAtFirstCollision = true)
{
bool isColliding = false;
for (std::size_t cpt = 0; cpt < geomModel.collisionPairs.size(); ++cpt)
{
if(geomData.activeCollisionPairs[cpt])
{
computeCollision(geomModel,geomData,cpt);
isColliding |= geomData.collisionResults[cpt].isCollision();
if(isColliding && stopAtFirstCollision)
return true;
}
}
return isColliding;
}
// WARNING, if stopAtFirstcollision = true, then the collisions vector will not be fulfilled.
inline bool computeCollisions(const Model & model,
Data & data,
const GeometryModel & geomModel,
GeometryData & geomData,
const Eigen::VectorXd & q,
const bool stopAtFirstCollision
)
{
updateGeometryPlacements (model, data, geomModel, geomData, q);
return computeCollisions(geomModel,geomData, stopAtFirstCollision);
}
/* --- DISTANCES ----------------------------------------------------------------- */
/* --- DISTANCES ----------------------------------------------------------------- */
/* --- DISTANCES ----------------------------------------------------------------- */
inline fcl::DistanceResult & computeDistance(const GeometryModel & geomModel,
GeometryData & geomData,
const PairIndex & pairId )
{
assert( pairId < geomModel.collisionPairs.size() );
const CollisionPair & pair = geomModel.collisionPairs[pairId];
assert( pairId < geomData.distanceResults.size() );
assert( pair.first < geomData.collisionObjects.size() );
assert( pair.second < geomData.collisionObjects.size() );
geomData.distanceResults[pairId].clear();
fcl::distance ( &geomData.collisionObjects[pair.first],
&geomData.collisionObjects[pair.second],
geomData.distanceRequest,
geomData.distanceResults[pairId]);
return geomData.distanceResults[pairId];
}
template <bool COMPUTE_SHORTEST>
inline std::size_t computeDistances(const GeometryModel & geomModel,
GeometryData & geomData)
{
std::size_t min_index = geomModel.collisionPairs.size();
double min_dist = std::numeric_limits<double>::infinity();
for (std::size_t cpt = 0; cpt < geomModel.collisionPairs.size(); ++cpt)
{
if(geomData.activeCollisionPairs[cpt])
{
computeDistance(geomModel,geomData,cpt);
if (COMPUTE_SHORTEST && geomData.distanceResults[cpt].min_distance < min_dist)
{
min_index = cpt;
min_dist = geomData.distanceResults[cpt].min_distance;
}
}
}
return min_index;
}
// Required to have a default template argument on templated free function
inline std::size_t computeDistances(const GeometryModel& geomModel,
GeometryData & geomData)
{
return computeDistances<true>(geomModel,geomData);
}
// Required to have a default template argument on templated free function
inline std::size_t computeDistances(const Model & model,
Data & data,
const GeometryModel & geomModel,
GeometryData & geomData,
const Eigen::VectorXd & q
)
{
return computeDistances<true>(model, data, geomModel, geomData, q);
}
template <bool ComputeShortest>
inline std::size_t computeDistances(const Model & model,
Data & data,
const GeometryModel & geomModel,
GeometryData & geomData,
const Eigen::VectorXd & q
)
{
updateGeometryPlacements (model, data, geomModel, geomData, q);
return computeDistances<ComputeShortest>(geomModel,geomData);
}
/* --- RADIUS -------------------------------------------------------------------- */
/* --- RADIUS -------------------------------------------------------------------- */
/* --- RADIUS -------------------------------------------------------------------- */
/// Given p1..3 being either "min" or "max", return one of the corners of the
/// AABB cub of the FCL object.
#define SE3_GEOM_AABB(FCL,p1,p2,p3) \
SE3::Vector3( \
FCL->aabb_local.p1##_ [0], \
FCL->aabb_local.p2##_ [1], \
FCL->aabb_local.p3##_ [2])
/// For all bodies of the model, compute the point of the geometry model
/// that is the further from the center of the joint. This quantity is used
/// in some continuous collision test.
inline void computeBodyRadius(const Model & model,
const GeometryModel & geomModel,
GeometryData & geomData)
{
geomData.radius.resize(model.joints.size(),0);
BOOST_FOREACH(const GeometryObject & geom,geomModel.geometryObjects)
{
const boost::shared_ptr<const fcl::CollisionGeometry> & fcl
= geom.fcl;
const SE3 & jMb = geom.placement; // placement in joint.
const Model::JointIndex & i = geom.parentJoint;
assert (i<geomData.radius.size());
double radius = geomData.radius[i];
// The radius is simply the one of the 8 corners of the AABB cube, expressed
// in the joint frame, whose norm is the highest.
radius = std::max (jMb.act(SE3_GEOM_AABB(fcl,min,min,min)).squaredNorm(),radius);
radius = std::max (jMb.act(SE3_GEOM_AABB(fcl,min,min,max)).squaredNorm(),radius);
radius = std::max (jMb.act(SE3_GEOM_AABB(fcl,min,max,min)).squaredNorm(),radius);
radius = std::max (jMb.act(SE3_GEOM_AABB(fcl,min,max,max)).squaredNorm(),radius);
radius = std::max (jMb.act(SE3_GEOM_AABB(fcl,max,min,min)).squaredNorm(),radius);
radius = std::max (jMb.act(SE3_GEOM_AABB(fcl,max,min,max)).squaredNorm(),radius);
radius = std::max (jMb.act(SE3_GEOM_AABB(fcl,max,max,min)).squaredNorm(),radius);
radius = std::max (jMb.act(SE3_GEOM_AABB(fcl,max,max,max)).squaredNorm(),radius);
// Don't forget to sqroot the squared norm before storing it.
geomData.radius[i] = sqrt(radius);
}
}
#undef SE3_GEOM_AABB
#endif // WITH_HPP_FCL
/* --- APPEND GEOMETRY MODEL ----------------------------------------------------------- */
inline void appendGeometryModel(GeometryModel & geomModel1,
const GeometryModel & geomModel2)
{
assert (geomModel1.ngeoms == geomModel1.geometryObjects.size());
Index nGeom1 = geomModel1.geometryObjects.size();
Index nColPairs1 = geomModel1.collisionPairs.size();
assert (geomModel2.ngeoms == geomModel2.geometryObjects.size());
Index nGeom2 = geomModel2.geometryObjects.size();
Index nColPairs2 = geomModel2.collisionPairs.size();
/// Append the geometry objects and geometry positions
geomModel1.geometryObjects.insert(geomModel1.geometryObjects.end(),
geomModel2.geometryObjects.begin(), geomModel2.geometryObjects.end());
geomModel1.ngeoms += nGeom2;
/// 1. copy the collision pairs and update geomData1 accordingly.
geomModel1.collisionPairs.reserve(nColPairs1 + nColPairs2 + nGeom1 * nGeom2);
for (Index i = 0; i < nColPairs2; ++i)
{
const CollisionPair& cp = geomModel2.collisionPairs[i];
geomModel1.collisionPairs.push_back(
CollisionPair (cp.first + nGeom1, cp.second + nGeom1)
);
}
/// 2. add the collision pairs between geomModel1 and geomModel2.
for (Index i = 0; i < nGeom1; ++i) {
for (Index j = 0; j < nGeom2; ++j) {
geomModel1.collisionPairs.push_back(CollisionPair(i, nGeom1 + j));
}
}
}
inline void appendGeometryModel(GeometryModel & geomModel1,
GeometryData & geomData1,
const GeometryModel & geomModel2,
const GeometryData & geomData2)
{
/// 1&2. Call previous function.
appendGeometryModel(geomModel1,geomModel2);
/// 3. Update the inner/outer objects
Index nGeom1 = geomModel1.geometryObjects.size();
typedef GeometryData::GeomIndexList GeomIndexList;
typedef std::map < JointIndex, GeomIndexList > Map_t;
BOOST_FOREACH(const Map_t::value_type& innerObject, geomData2.innerObjects)
{
GeomIndexList& innerGeoms = geomData1.innerObjects[innerObject.first];
innerGeoms.reserve(innerGeoms.size() + innerObject.second.size());
BOOST_FOREACH(const GeomIndex& gid, innerObject.second)
{
innerGeoms.push_back(nGeom1 + gid);
}
}
BOOST_FOREACH(const Map_t::value_type& outerObject, geomData2.outerObjects)
{
GeomIndexList& outerGeoms = geomData1.outerObjects[outerObject.first];
outerGeoms.reserve(outerGeoms.size() + outerObject.second.size());
BOOST_FOREACH(const GeomIndex& gid, outerObject.second)
{
outerGeoms.push_back(nGeom1 + gid);
}
}
// FIXME: I copy here the previous algo. Maybe it would be safer to simply use the
// fillInnerOuterObjectMaps() method (however marginally less efficient: is it important?).
}
} // namespace se3
#endif // ifnded __se3_algo_geometry_hxx__