Skip to content

Commit 2112037

Browse files
authored
Fix epa box support (#397)
Make sure that the support point of a box is always one of the box vertices, not the middle of an edge or a face. This helps to reduce the "degenerate triangle issue" reported in #395
1 parent 09f846c commit 2112037

File tree

4 files changed

+83
-31
lines changed

4 files changed

+83
-31
lines changed

include/fcl/narrowphase/detail/convexity_based_algorithm/gjk_libccd-inl.h

+22-3
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,17 @@ static void ComputeVisiblePatchRecursive(
11861186
// g is not a visible face
11871187
if (!isOutsidePolytopeFace(&polytope, g, &query_point)) {
11881188
// Cannot see the neighbouring face from the new vertex.
1189+
1190+
// TODO(hongkai.dai@tri.global): when the new vertex is colinear with a
1191+
// border edge, we should remove the degenerate triangle. We could remove
1192+
// the middle vertex on that line from the polytope, and then reconnect
1193+
// the polytope.
1194+
if (triangle_area_is_zero(query_point, f.edge[edge_index]->vertex[0]->v.v,
1195+
f.edge[edge_index]->vertex[1]->v.v)) {
1196+
FCL_THROW_FAILED_AT_THIS_CONFIGURATION(
1197+
"The new vertex is colinear with an existing edge. The added "
1198+
"triangle would be degenerate.");
1199+
}
11891200
border_edges->insert(f.edge[edge_index]);
11901201
return;
11911202
}
@@ -2241,13 +2252,21 @@ static void convexToGJK(const Convex<S>& s, const Transform3<S>& tf,
22412252
static inline void supportBox(const void* obj, const ccd_vec3_t* dir_,
22422253
ccd_vec3_t* v)
22432254
{
2255+
// Use a customized sign function, so that the support of the box always
2256+
// appears in one of the box vertices.
2257+
// Picking support vertices on the interior of faces/edges can lead to
2258+
// degenerate triangles in the EPA algorithm and are no more correct than just
2259+
// picking box corners.
2260+
auto sign = [](ccd_real_t x) -> ccd_real_t {
2261+
return x >= 0 ? ccd_real_t(1.0) : ccd_real_t(-1.0);
2262+
};
22442263
const ccd_box_t* o = static_cast<const ccd_box_t*>(obj);
22452264
ccd_vec3_t dir;
22462265
ccdVec3Copy(&dir, dir_);
22472266
ccdQuatRotVec(&dir, &o->rot_inv);
2248-
ccdVec3Set(v, ccdSign(ccdVec3X(&dir)) * o->dim[0],
2249-
ccdSign(ccdVec3Y(&dir)) * o->dim[1],
2250-
ccdSign(ccdVec3Z(&dir)) * o->dim[2]);
2267+
ccdVec3Set(v, sign(ccdVec3X(&dir)) * o->dim[0],
2268+
sign(ccdVec3Y(&dir)) * o->dim[1],
2269+
sign(ccdVec3Z(&dir)) * o->dim[2]);
22512270
ccdQuatRotVec(v, &o->rot);
22522271
ccdVec3Add(v, &o->pos);
22532272
}

test/narrowphase/detail/convexity_based_algorithm/test_gjk_libccd-inl_epa.cpp

+7-7
Original file line numberDiff line numberDiff line change
@@ -1289,7 +1289,7 @@ void SetUpBoxToBox(const Transform3<S>& X_WF, void** o1, void** o2, ccd_t* ccd,
12891289
fcl::Box<S> box1(box1_size);
12901290
fcl::Box<S> box2(box2_size);
12911291
*o1 = GJKInitializer<S, fcl::Box<S>>::createGJKObject(box1, X_WB1);
1292-
*o2 = GJKInitializer<S, fcl::Box<S>>::createGJKObject(box1, X_WB2);
1292+
*o2 = GJKInitializer<S, fcl::Box<S>>::createGJKObject(box2, X_WB2);
12931293

12941294
// Set up ccd solver.
12951295
CCD_INIT(ccd);
@@ -1329,20 +1329,20 @@ void TestSimplexToPolytope3InGivenFrame(const Transform3<S>& X_WF) {
13291329
// We find three points Pa1, Pb1, Pc1 on box 1, and three points Pa2, Pb2, Pc2
13301330
// on box 2, such that the 2-simplex with vertices (Pa1 - Pa2, Pb1 - Pb2,
13311331
// Pc1 - Pc2) contains the origin.
1332-
const Vector3<S> p_FPa1(-1, -1, -1);
1333-
const Vector3<S> p_FPa2(-0.1, 0.5, -1);
1332+
const Vector3<S> p_FPa1(-1, -1, 0.1);
1333+
const Vector3<S> p_FPa2(-0.1, 0.5, 0.1);
13341334
pts[0].v = ToCcdVec3<S>(p_FPa1 - p_FPa2);
13351335
pts[0].v1 = ToCcdVec3<S>(p_FPa1);
13361336
pts[0].v2 = ToCcdVec3<S>(p_FPa2);
13371337

1338-
const Vector3<S> p_FPb1(-1, 1, -1);
1339-
const Vector3<S> p_FPb2(-0.1, 0.5, -1);
1338+
const Vector3<S> p_FPb1(-1, 1, 0.1);
1339+
const Vector3<S> p_FPb2(-0.1, 0.5, 0.1);
13401340
pts[1].v = ToCcdVec3<S>(p_FPb1 - p_FPb2);
13411341
pts[1].v1 = ToCcdVec3<S>(p_FPb1);
13421342
pts[1].v2 = ToCcdVec3<S>(p_FPb2);
13431343

1344-
const Vector3<S> p_FPc1(1, 1, -1);
1345-
const Vector3<S> p_FPc2(-0.1, 0.5, -1);
1344+
const Vector3<S> p_FPc1(1, 1, 0.1);
1345+
const Vector3<S> p_FPc2(-0.1, 0.5, 0.1);
13461346
pts[2].v = ToCcdVec3<S>(p_FPc1 - p_FPc2);
13471347
pts[2].v1 = ToCcdVec3<S>(p_FPc1);
13481348
pts[2].v2 = ToCcdVec3<S>(p_FPc2);

test/test_fcl_capsule_box_1.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ void test_distance_capsule_box(fcl::GJKSolverType solver_type, S solver_toleranc
117117

118118
GTEST_TEST(FCL_GEOMETRIC_SHAPES, distance_capsule_box_ccd)
119119
{
120-
test_distance_capsule_box<double>(fcl::GJKSolverType::GST_LIBCCD, 1e-6, 1e-4);
120+
test_distance_capsule_box<double>(fcl::GJKSolverType::GST_LIBCCD, 1e-8, 4e-4);
121121
}
122122

123123
GTEST_TEST(FCL_GEOMETRIC_SHAPES, distance_capsule_box_indep)

test/test_fcl_signed_distance.cpp

+53-20
Original file line numberDiff line numberDiff line change
@@ -296,34 +296,18 @@ void test_distance_cylinder_box() {
296296
box_size, X_WB);
297297
}
298298

299-
// This is a *specific* case that has cropped up in the wild that reaches the
300-
// unexpected `validateNearestFeatureOfPolytopeBeingEdge` error. This error was
301-
// reported in https://github.com/flexible-collision-library/fcl/issues/388
302299
template <typename S>
303-
void test_distance_box_box1() {
300+
void test_distance_box_box_helper(const Vector3<S>& box1_size,
301+
const Transform3<S>& X_WB1,
302+
const Vector3<S>& box2_size,
303+
const Transform3<S>& X_WB2) {
304304
using CollisionGeometryPtr_t = std::shared_ptr<fcl::CollisionGeometryd>;
305-
const Vector3<S> box1_size(0.03, 0.12, 0.1);
306305
CollisionGeometryPtr_t box1_geo(
307306
new fcl::Box<S>(box1_size(0), box1_size(1), box1_size(2)));
308-
Transform3<S> X_WB1 = Transform3<S>::Identity();
309-
X_WB1.matrix() << -3.0627937852578681533e-08, -0.99999999999999888978,
310-
-2.8893865161583314238e-08, 0.63499979627350811029, 0.9999999999999980016,
311-
-3.0627939739957803544e-08, 6.4729926918527511769e-08,
312-
-0.48500002215636439651, -6.4729927722963847085e-08,
313-
-2.8893863029448751323e-08, 0.99999999999999711342, 1.0778146458339641356,
314-
0, 0, 0, 1;
315307
fcl::CollisionObject<S> box1(box1_geo, X_WB1);
316308

317-
const Vector3<S> box2_size(0.025, 0.35, 1.845);
318309
CollisionGeometryPtr_t box2_geo(
319310
new fcl::Box<S>(box2_size(0), box2_size(1), box2_size(2)));
320-
Transform3<S> X_WB2 = Transform3<S>::Identity();
321-
// clang-format off
322-
X_WB2.matrix() << 0, -1, 0, 0.8,
323-
1, 0, 0, -0.4575,
324-
0, 0, 1, 1.0225,
325-
0, 0, 0, 1;
326-
// clang-format on
327311
fcl::CollisionObject<S> box2(box2_geo, X_WB2);
328312

329313
fcl::DistanceRequest<S> request;
@@ -347,6 +331,54 @@ void test_distance_box_box1() {
347331
EXPECT_TRUE((p_B2P2.array().abs() <= (box2_size / 2).array() + tol).all());
348332
}
349333

334+
// This is a *specific* case that has cropped up in the wild that reaches the
335+
// unexpected `validateNearestFeatureOfPolytopeBeingEdge` error. This error was
336+
// reported in https://github.com/flexible-collision-library/fcl/issues/388
337+
template <typename S>
338+
void test_distance_box_box1() {
339+
const Vector3<S> box1_size(0.03, 0.12, 0.1);
340+
Transform3<S> X_WB1 = Transform3<S>::Identity();
341+
X_WB1.matrix() << -3.0627937852578681533e-08, -0.99999999999999888978,
342+
-2.8893865161583314238e-08, 0.63499979627350811029, 0.9999999999999980016,
343+
-3.0627939739957803544e-08, 6.4729926918527511769e-08,
344+
-0.48500002215636439651, -6.4729927722963847085e-08,
345+
-2.8893863029448751323e-08, 0.99999999999999711342, 1.0778146458339641356,
346+
0, 0, 0, 1;
347+
348+
const Vector3<S> box2_size(0.025, 0.35, 1.845);
349+
Transform3<S> X_WB2 = Transform3<S>::Identity();
350+
// clang-format off
351+
X_WB2.matrix() << 0, -1, 0, 0.8,
352+
1, 0, 0, -0.4575,
353+
0, 0, 1, 1.0225,
354+
0, 0, 0, 1;
355+
// clang-format on
356+
test_distance_box_box_helper(box1_size, X_WB1, box2_size, X_WB2);
357+
}
358+
359+
// This is a *specific* case that has cropped up in the wild that reaches the
360+
// unexpected `triangle_size_is_zero` error. This error was
361+
// reported in https://github.com/flexible-collision-library/fcl/issues/395
362+
template <typename S>
363+
void test_distance_box_box2() {
364+
const Vector3<S> box1_size(0.46, 0.48, 0.01);
365+
Transform3<S> X_WB1 = Transform3<S>::Identity();
366+
X_WB1.matrix() << 1,0,0, -0.72099999999999997424,
367+
0,1,0, -0.77200000000000001954,
368+
0,0,1, 0.81000000000000005329,
369+
0,0,0,1;
370+
371+
const Vector3<S> box2_size(0.049521, 0.146, 0.0725);
372+
Transform3<S> X_WB2 = Transform3<S>::Identity();
373+
// clang-format off
374+
X_WB2.matrix() << 0.10758262492983036718, -0.6624881850015212903, -0.74130653817877356637, -0.42677133002999478872,
375+
0.22682184885125472595, -0.709614040775253474, 0.6670830248314786326, -0.76596851247746788882,
376+
-0.96797615037608542021, -0.23991106241273435495, 0.07392465377049164954, 0.80746731400091054098,
377+
0, 0, 0, 1;
378+
// clang-format on
379+
test_distance_box_box_helper(box1_size, X_WB1, box2_size, X_WB2);
380+
}
381+
350382
//==============================================================================
351383

352384
GTEST_TEST(FCL_NEGATIVE_DISTANCE, sphere_sphere_ccd)
@@ -380,6 +412,7 @@ GTEST_TEST(FCL_SIGNED_DISTANCE, cylinder_box_ccd) {
380412

381413
GTEST_TEST(FCL_SIGNED_DISTANCE, box_box1_ccd) {
382414
test_distance_box_box1<double>();
415+
test_distance_box_box2<double>();
383416
}
384417

385418
//==============================================================================

0 commit comments

Comments
 (0)