@@ -1576,6 +1576,9 @@ EPA::SimplexFace* EPA::findClosestFace() {
1576
1576
EPA::Status EPA::evaluate (GJK& gjk, const Vec3f& guess) {
1577
1577
GJK::Simplex& simplex = *gjk.getSimplex ();
1578
1578
support_func_guess_t hint (gjk.support_hint );
1579
+
1580
+ // TODO(louis): we might want to start with a hexahedron if the
1581
+ // simplex given by GJK is of rank <= 3.
1579
1582
bool enclosed_origin = gjk.encloseOrigin ();
1580
1583
if ((simplex.rank > 1 ) && enclosed_origin) {
1581
1584
assert (simplex.rank == 4 &&
@@ -1633,27 +1636,55 @@ EPA::Status EPA::evaluate(GJK& gjk, const Vec3f& guess) {
1633
1636
break ;
1634
1637
}
1635
1638
1639
+ // Step 1: find the support point in the direction of the closest_face
1640
+ // normal.
1641
+ // --------------------------------------------------------------------------
1636
1642
SimplexHorizon horizon;
1637
1643
SimplexVertex& w = sv_store[num_vertices++];
1638
1644
bool valid = true ;
1639
1645
closest_face->pass = ++pass;
1640
1646
// At the moment, SimplexF.n is always normalized. This could be revised
1641
1647
// in the future...
1642
1648
gjk.getSupport (closest_face->n , true , w, hint);
1643
- FCL_REAL wdist = closest_face->n .dot (w.w ) - closest_face->d ;
1644
- if (wdist <= tolerance) {
1649
+
1650
+ // Step 2: check for convergence.
1651
+ // ------------------------------
1652
+ // Preambule to understand the convergence criterion of EPA:
1653
+ // the support we just added is in the direction of the normal of
1654
+ // the closest_face. Therefore, the support point will **always**
1655
+ // lie "after" the closest_face, i.e closest_face.n.dot(w.w) > 0.
1656
+ assert (closest_face->n .dot (w.w ) > 0 &&
1657
+ " The support is not in the right direction." );
1658
+ //
1659
+ // 1) First check: `fdist` (see below) is an upper bound of how much
1660
+ // more penetration depth we can expect to "gain" by adding `w` to EPA's
1661
+ // polytope. This first check, as any convergence check, should be both
1662
+ // absolute and relative. This allows to adapt the tolerance to the
1663
+ // scale of the objects.
1664
+ const SimplexVertex& vf1 = sv_store[closest_face->vertex_id [0 ]];
1665
+ const SimplexVertex& vf2 = sv_store[closest_face->vertex_id [1 ]];
1666
+ const SimplexVertex& vf3 = sv_store[closest_face->vertex_id [2 ]];
1667
+ FCL_REAL fdist = closest_face->n .dot (w.w - vf1.w );
1668
+ FCL_REAL wnorm = w.w .norm ();
1669
+ // TODO(louis): we might want to use tol_abs and tol_rel; this might
1670
+ // obfuscate the code for the user though.
1671
+ if (fdist <= tolerance + tolerance * wnorm) {
1672
+ status = AccuracyReached;
1673
+ break ;
1674
+ }
1675
+ // 2) Second check: the expand function **assumes** that the support we
1676
+ // just computed is not a vertex of the face. We make sure that this
1677
+ // is the case:
1678
+ // TODO(louis): should we use squaredNorm everywhere instead of norm?
1679
+ if ((w.w - vf1.w ).norm () <= tolerance + tolerance * wnorm ||
1680
+ (w.w - vf2.w ).norm () <= tolerance + tolerance * wnorm ||
1681
+ (w.w - vf3.w ).norm () <= tolerance + tolerance * wnorm) {
1645
1682
status = AccuracyReached;
1646
1683
break ;
1647
1684
}
1648
- // The computed support cannot be a vertex of the `closest_face`,
1649
- // otherwise EPA should have exited with `wdist <= tolerance`.
1650
- assert ((w.w - sv_store[closest_face->vertex_id [0 ]].w ).norm () >
1651
- std::numeric_limits<FCL_REAL>::epsilon ());
1652
- assert ((w.w - sv_store[closest_face->vertex_id [1 ]].w ).norm () >
1653
- std::numeric_limits<FCL_REAL>::epsilon ());
1654
- assert ((w.w - sv_store[closest_face->vertex_id [2 ]].w ).norm () >
1655
- std::numeric_limits<FCL_REAL>::epsilon ());
1656
1685
1686
+ // Step 3: expand the polytope
1687
+ // ---------------------------
1657
1688
for (size_t j = 0 ; (j < 3 ) && valid; ++j)
1658
1689
valid &= expand (pass, w, closest_face->adjacent_faces [j],
1659
1690
closest_face->adjacent_edge [j], horizon);
@@ -1702,6 +1733,48 @@ EPA::Status EPA::evaluate(GJK& gjk, const Vec3f& guess) {
1702
1733
return status;
1703
1734
}
1704
1735
1736
+ // Use this function to debug `EPA::expand` if needed.
1737
+ // void EPA::PrintExpandLooping(const SimplexFace* f, const SimplexVertex& w) {
1738
+ // std::cout << "Vertices:\n";
1739
+ // for (size_t i = 0; i < num_vertices; ++i) {
1740
+ // std::cout << "[";
1741
+ // std::cout << sv_store[i].w(0) << ", ";
1742
+ // std::cout << sv_store[i].w(1) << ", ";
1743
+ // std::cout << sv_store[i].w(2) << "]\n";
1744
+ // }
1745
+ // //
1746
+ // std::cout << "\nTriangles:\n";
1747
+ // SimplexFace* face = hull.root;
1748
+ // for (size_t i = 0; i < hull.count; ++i) {
1749
+ // std::cout << "[";
1750
+ // std::cout << face->vertex_id[0] << ", ";
1751
+ // std::cout << face->vertex_id[1] << ", ";
1752
+ // std::cout << face->vertex_id[2] << "]\n";
1753
+ // face = face->next_face;
1754
+ // }
1755
+ // //
1756
+ // std::cout << "\nNormals:\n";
1757
+ // face = hull.root;
1758
+ // for (size_t i = 0; i < hull.count; ++i) {
1759
+ // std::cout << "[";
1760
+ // std::cout << face->n(0) << ", ";
1761
+ // std::cout << face->n(1) << ", ";
1762
+ // std::cout << face->n(2) << "]\n";
1763
+ // face = face->next_face;
1764
+ // }
1765
+ // //
1766
+ // std::cout << "\nClosest face:\n";
1767
+ // face = hull.root;
1768
+ // for (size_t i = 0; i < hull.count; ++i) {
1769
+ // if (face == closest_face) {
1770
+ // std::cout << i << "\n";
1771
+ // }
1772
+ // face = face->next_face;
1773
+ // }
1774
+ // std::cout << "\nSupport point:\n";
1775
+ // std::cout << "[" << w.w(0) << ", " << w.w(1) << ", " << w.w(2) << "]\n";
1776
+ // }
1777
+
1705
1778
/* * @brief the goal is to add a face connecting vertex w and face edge f[e] */
1706
1779
bool EPA::expand (size_t pass, const SimplexVertex& w, SimplexFace* f, size_t e,
1707
1780
SimplexHorizon& horizon) {
@@ -1712,6 +1785,12 @@ bool EPA::expand(size_t pass, const SimplexVertex& w, SimplexFace* f, size_t e,
1712
1785
1713
1786
// Check if we loop through expand indefinitely.
1714
1787
if (f->pass == pass) {
1788
+ // Uncomment the following line and the associated EPA method
1789
+ // to debug the infinite loop if needed.
1790
+ // EPAPrintExpandLooping(this, f);
1791
+ if (f == closest_face) {
1792
+ assert (false && " EPA is looping indefinitely." );
1793
+ }
1715
1794
status = InvalidHull;
1716
1795
return false ;
1717
1796
}
0 commit comments