Commit 26342669 authored by Joseph Mirabel's avatar Joseph Mirabel
Browse files

[GJK] Fix normalization issues

parent 88e90823
......@@ -50,7 +50,7 @@ namespace details
{
/// @brief the support function for shape
Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir);
Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir, bool dirIsNormalized);
/// @brief Minkowski difference class of two shapes
///
......@@ -86,15 +86,15 @@ struct MinkowskiDiff
}
/// @brief support function for shape0
inline Vec3f support0(const Vec3f& d) const
inline Vec3f support0(const Vec3f& d, bool dIsNormalized) const
{
return getSupport(shapes[0], d);
return getSupport(shapes[0], d, dIsNormalized);
}
/// @brief support function for shape1
inline Vec3f support1(const Vec3f& d) const
inline Vec3f support1(const Vec3f& d, bool dIsNormalized) const
{
return oR1 * getSupport(shapes[1], oR1.transpose() * d) + ot1;
return oR1 * getSupport(shapes[1], oR1.transpose() * d, dIsNormalized) + ot1;
}
/// @brief support function for the pair of shapes
......@@ -169,6 +169,10 @@ struct GJK
return simplex;
}
/// Get the closest points on each object.
/// \return true on success
bool getClosestPoints (const MinkowskiDiff& shape, Vec3f& w0, Vec3f& w1) const;
/// @brief get the guess from current simplex
Vec3f getGuessFromSimplex() const;
......
......@@ -80,7 +80,7 @@ namespace fcl
Vec3f w0 (Vec3f::Zero());
for(size_t i = 0; i < epa.result.rank; ++i)
{
w0 += shape.support0(epa.result.vertex[i]->d) *
w0 += shape.support0(epa.result.vertex[i]->d, false) *
epa.result.coefficient[i];
}
if(penetration_depth) *penetration_depth = -epa.depth;
......@@ -131,7 +131,7 @@ namespace fcl
Vec3f w0 (Vec3f::Zero());
for(size_t i = 0; i < epa.result.rank; ++i)
{
w0 += shape.support0(epa.result.vertex[i]->d) *
w0 += shape.support0(epa.result.vertex[i]->d, false) *
epa.result.coefficient[i];
}
distance = -epa.depth;
......@@ -144,16 +144,15 @@ namespace fcl
case details::GJK::Failed:
{
col = false;
Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero());
for(size_t i = 0; i < gjk.getSimplex()->rank; ++i)
{
FCL_REAL p = gjk.getSimplex()->coefficient[i];
w0 += shape.support0( gjk.getSimplex()->vertex[i]->d) * p;
w1 += shape.support1(-gjk.getSimplex()->vertex[i]->d) * p;
}
distance = (w0 - w1).norm();
p1 = tf1.transform (w0);
p2 = tf1.transform (w1);
gjk.getClosestPoints (shape, p1, p2);
// TODO On degenerated case, the closest point may be wrong
// (i.e. an object face normal is colinear to gjk.ray
// assert (distance == (w0 - w1).norm());
distance = gjk.distance;
p1 = tf1.transform (p1);
p2 = tf1.transform (p2);
assert (distance > 0);
}
break;
......@@ -190,13 +189,8 @@ namespace fcl
{
// TODO: understand why GJK fails between cylinder and box
assert (distance * distance < sqrt (eps));
Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero());
for(size_t i = 0; i < gjk.getSimplex()->rank; ++i)
{
FCL_REAL p = gjk.getSimplex()->coefficient[i];
w0 += shape.support0( gjk.getSimplex()->vertex[i]->d) * p;
w1 += shape.support1(-gjk.getSimplex()->vertex[i]->d) * p;
}
Vec3f w0, w1;
gjk.getClosestPoints (shape, w0, w1);
distance = 0;
p1 = p2 = tf1.transform (.5* (w0 + w1));
normal = Vec3f (0,0,0);
......@@ -204,18 +198,14 @@ namespace fcl
}
else if(gjk_status == details::GJK::Valid)
{
Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero());
for(size_t i = 0; i < gjk.getSimplex()->rank; ++i)
{
FCL_REAL p = gjk.getSimplex()->coefficient[i];
w0 += shape.support0( gjk.getSimplex()->vertex[i]->d) * p;
w1 += shape.support1(-gjk.getSimplex()->vertex[i]->d) * p;
}
distance = (w0 - w1).norm();
p1 = tf1.transform (w0);
p2 = tf1.transform (w1);
gjk.getClosestPoints (shape, p1, p2);
// TODO On degenerated case, the closest point may be wrong
// (i.e. an object face normal is colinear to gjk.ray
// assert (distance == (w0 - w1).norm());
distance = gjk.distance;
p1 = tf1.transform (p1);
p2 = tf1.transform (p2);
return true;
}
else
......@@ -231,7 +221,7 @@ namespace fcl
Vec3f w0 (Vec3f::Zero());
for(size_t i = 0; i < epa.result.rank; ++i)
{
w0 += shape.support0(epa.result.vertex[i]->d) *
w0 += shape.support0(epa.result.vertex[i]->d, false) *
epa.result.coefficient[i];
}
assert (epa.depth >= -eps);
......@@ -242,17 +232,11 @@ namespace fcl
}
else
{
Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero());
for(size_t i = 0; i < gjk.getSimplex()->rank; ++i)
{
FCL_REAL p = gjk.getSimplex()->coefficient[i];
w0 += shape.support0( gjk.getSimplex()->vertex[i]->d) * p;
w1 += shape.support1(-gjk.getSimplex()->vertex[i]->d) * p;
}
gjk.getClosestPoints (shape, p1, p2);
distance = 0;
p1 = tf1.transform (w0);
p2 = tf1.transform (w1);
p1 = tf1.transform (p1);
p2 = tf1.transform (p2);
}
return false;
}
......
......@@ -166,41 +166,50 @@ void getShapeSupport(const Convex* convex, const Vec3f& dir, Vec3f& support)
}
}
Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir)
#define CALL_GET_SHAPE_SUPPORT(ShapeType) \
getShapeSupport (static_cast<const ShapeType*>(shape), \
(shape_traits<ShapeType>::NeedNormalizedDir && !dirIsNormalized) \
? dir.normalized() : dir, \
support)
Vec3f getSupport(const ShapeBase* shape, const Vec3f& dir, bool dirIsNormalized)
{
Vec3f support;
switch(shape->getNodeType())
{
case GEOM_TRIANGLE:
getShapeSupport (static_cast<const TriangleP*>(shape), dir, support);
CALL_GET_SHAPE_SUPPORT(TriangleP);
break;
case GEOM_BOX:
getShapeSupport (static_cast<const Box*>(shape), dir, support);
CALL_GET_SHAPE_SUPPORT(Box);
break;
case GEOM_SPHERE:
getShapeSupport (static_cast<const Sphere*>(shape), dir, support);
CALL_GET_SHAPE_SUPPORT(Sphere);
break;
case GEOM_CAPSULE:
getShapeSupport (static_cast<const Capsule*>(shape), dir, support);
CALL_GET_SHAPE_SUPPORT(Capsule);
break;
case GEOM_CONE:
getShapeSupport (static_cast<const Cone*>(shape), dir, support);
CALL_GET_SHAPE_SUPPORT(Cone);
break;
case GEOM_CYLINDER:
getShapeSupport (static_cast<const Cylinder*>(shape), dir, support);
CALL_GET_SHAPE_SUPPORT(Cylinder);
break;
case GEOM_CONVEX:
getShapeSupport (static_cast<const Convex*>(shape), dir, support);
CALL_GET_SHAPE_SUPPORT(Convex);
break;
case GEOM_PLANE:
case GEOM_HALFSPACE:
default:
support.setZero();
; // nothing
}
return support;
}
#undef CALL_GET_SHAPE_SUPPORT
template <typename Shape0, typename Shape1>
void getSupportTpl (const Shape0* s0, const Shape1* s1,
const Matrix3f& oR1, const Vec3f& ot1,
......@@ -300,6 +309,19 @@ Vec3f GJK::getGuessFromSimplex() const
return ray;
}
bool GJK::getClosestPoints (const MinkowskiDiff& shape, Vec3f& w0, Vec3f& w1) const
{
w0.setZero();
w1.setZero();
for(size_t i = 0; i < getSimplex()->rank; ++i)
{
FCL_REAL p = getSimplex()->coefficient[i];
w0 += shape.support0( getSimplex()->vertex[i]->d, false) * p;
w1 += shape.support1(-getSimplex()->vertex[i]->d, false) * p;
}
return true;
}
GJK::Status GJK::evaluate(const MinkowskiDiff& shape_, const Vec3f& guess)
{
size_t iterations = 0;
......
......@@ -644,26 +644,24 @@ bool GJKSolver_indep::shapeDistance<Capsule, Capsule>
details::GJK::Status gjk_status = gjk.evaluate(shape, -guess);
if(enable_cached_guess) cached_guess = gjk.getGuessFromSimplex();
Vec3f w0 (Vec3f::Zero()), w1 (Vec3f::Zero());
for(size_t i = 0; i < gjk.getSimplex()->rank; ++i)
{
FCL_REAL p = gjk.getSimplex()->coefficient[i];
w0 += shape.support0( gjk.getSimplex()->vertex[i]->d) * p;
w1 += shape.support1(-gjk.getSimplex()->vertex[i]->d) * p;
}
gjk.getClosestPoints (shape, p1, p2);
if((gjk_status == details::GJK::Valid) ||
(gjk_status == details::GJK::Failed))
{
dist = (w0 - w1).norm();
p1 = tf1.transform (w0);
p2 = tf1.transform (w1);
// TODO On degenerated case, the closest point may be wrong
// (i.e. an object face normal is colinear to gjk.ray
// assert (dist == (w0 - w1).norm());
dist = gjk.distance;
p1 = tf1.transform (p1);
p2 = tf1.transform (p2);
return true;
}
else if (gjk_status == details::GJK::Inside)
{
p1 = tf1.transform (w0);
p2 = tf1.transform (w1);
p1 = tf1.transform (p1);
p2 = tf1.transform (p2);
if (enable_penetration) {
FCL_REAL penetrationDepth = details::computePenetration
......
......@@ -78,7 +78,8 @@ BOOST_AUTO_TEST_CASE(distance_capsule_box)
BOOST_CHECK_CLOSE (o1 [0], 1.0, 1e-1);
CHECK_CLOSE_TO_0 (o1 [1], 1e-1);
BOOST_CHECK_CLOSE (o2 [0], 0.5, 1e-1);
CHECK_CLOSE_TO_0 (o1 [1], 1e-1);
// This cannot be ensured with the current code.
// CHECK_CLOSE_TO_0 (o2 [1], 1e-1);
// Move capsule above box
tf1 = hpp::fcl::Transform3f (hpp::fcl::Vec3f (0., 0., 8.));
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment