diff --git a/src/engine/engine_collision_gjk.c b/src/engine/engine_collision_gjk.c index c61387f6..e5c861a4 100644 --- a/src/engine/engine_collision_gjk.c +++ b/src/engine/engine_collision_gjk.c @@ -141,11 +141,6 @@ static mjtNum gjk(mjCCDStatus* status, mjCCDObj* obj1, mjCCDObj* obj2) { gjkSupport(s1, s2, obj1, obj2, x_k); mju_sub3(s_k, s1, s2); - // return early if geom distance isn't needed - if (!get_dist && mju_dot3(x_k, s_k) > 0) { - return mjMAXVAL; - } - // the stopping criteria relies on the Frank-Wolfe duality gap given by // |f(x_k) - f(x_min)|^2 <= < grad f(x_k), (x_k - s_k) > mjtNum diff[3]; @@ -154,6 +149,12 @@ static mjtNum gjk(mjCCDStatus* status, mjCCDObj* obj1, mjCCDObj* obj2) { break; } + // check if hyperplane is separating the Minkowski difference and the origin; + // if so the objects don't collide, so return early if geom distance isn't needed + if (!get_dist && mju_dot3(x_k, s_k) > 0) { + return mjMAXVAL; + } + // TODO(kylebayes): signedVolume has been written to assume the first vertex is the latest // support to be added. Once the logic has been updated, then this hack should be removed. for (int i = n; i > 0; i--) { @@ -1165,8 +1166,8 @@ mjtNum mjc_ccd(const mjCCDConfig* config, mjCCDStatus* status, mjCCDObj* obj1, m } else { dist = 0; } - mju_free(pt.faces); - mju_free(pt.verts); + free(pt.faces); + free(pt.verts); } return dist; } diff --git a/test/engine/engine_collision_gjk_test.cc b/test/engine/engine_collision_gjk_test.cc index e350ee10..a19059db 100644 --- a/test/engine/engine_collision_gjk_test.cc +++ b/test/engine/engine_collision_gjk_test.cc @@ -101,10 +101,11 @@ int PenetrationWrapper(mjCCDObj* obj1, mjCCDObj* obj2, const ccd_t* ccd, } mjtNum Penetration(mjModel* m, mjData* d, int g1, int g2, - mjtNum dir[3] = nullptr, mjtNum pos[3] = nullptr) { - mjCCDObj obj1 = {m, d, g1, -1, -1, -1, -1, 0, {1, 0, 0, 0}, mjc_center, + mjtNum dir[3] = nullptr, mjtNum pos[3] = nullptr, + mjtNum margin = 0) { + mjCCDObj obj1 = {m, d, g1, -1, -1, -1, -1, margin, {1, 0, 0, 0}, mjc_center, mjc_support}; - mjCCDObj obj2 = {m, d, g2, -1, -1, -1, -1, 0, {1, 0, 0, 0}, mjc_center, + mjCCDObj obj2 = {m, d, g2, -1, -1, -1, -1, margin, {1, 0, 0, 0}, mjc_center, mjc_support}; ccd_t ccd; // CCD_INIT(&ccd); // uncomment to run ccdMPRPenetration @@ -120,7 +121,8 @@ mjtNum Penetration(mjModel* m, mjData* d, int g1, int g2, ccd_vec3_t ccd_dir, ccd_pos; int ret = PenetrationWrapper(&obj1, &obj2, &ccd, &depth, &ccd_dir, &ccd_pos); - if (ret) return 0; // objects not colliding + // objects not colliding, return max value as geom distance was never computed + if (ret) return mjMAXVAL; if (dir) mju_copy3(dir, ccd_dir.v); if (pos) mju_copy3(pos, ccd_pos.v); return -depth; @@ -216,8 +218,8 @@ TEST_F(MjGjkTest, EllipsoidEllipsoidIntersect) { static constexpr char xml[] = R"( - - + + )"; @@ -230,9 +232,9 @@ TEST_F(MjGjkTest, EllipsoidEllipsoidIntersect) { int geom1 = mj_name2id(model, mjOBJ_GEOM, "geom1"); int geom2 = mj_name2id(model, mjOBJ_GEOM, "geom2"); - mjtNum dist = GeomDist(model, data, geom1, geom2, nullptr, nullptr); + mjtNum dist = Penetration(model, data, geom1, geom2, nullptr, nullptr, 15); - EXPECT_NEAR(dist, 0, kTolerance); + EXPECT_LT(dist, 0); mj_deleteData(data); mj_deleteModel(model); }