diff --git a/src/distance_box_sphere.cpp b/src/distance_box_sphere.cpp index a1720ca9326dac3f3ad1cffd0499ca9085ab4a71..7d56b9902ed5402e1c787bdedea255943f2d3721 100644 --- a/src/distance_box_sphere.cpp +++ b/src/distance_box_sphere.cpp @@ -57,7 +57,7 @@ namespace fcl { { const Box& s1 = static_cast <const Box&> (*o1); const Sphere& s2 = static_cast <const Sphere&> (*o2); - details::boxSphereIntersect + details::boxSphereDistance (s1, tf1, s2, tf2, result.min_distance, result.nearest_points [0], result.nearest_points [1], result.normal); result.o1 = o1; result.o2 = o2; result.b1 = -1; result.b2 = -1; @@ -73,7 +73,7 @@ namespace fcl { { const Sphere& s1 = static_cast <const Sphere&> (*o1); const Box& s2 = static_cast <const Box&> (*o2); - details::boxSphereIntersect + details::boxSphereDistance (s2, tf2, s1, tf1, result.min_distance, result.nearest_points [1], result.nearest_points [0], result.normal); result.o1 = o1; result.o2 = o2; result.b1 = -1; result.b2 = -1; diff --git a/src/narrowphase/details.h b/src/narrowphase/details.h index a8198af75b85e0d7cd9853d7501830b6abc58915..612588920f9ee8bcdaf379ec0fe5971d888835ea 100644 --- a/src/narrowphase/details.h +++ b/src/narrowphase/details.h @@ -2158,58 +2158,49 @@ namespace fcl { return true; } - inline bool boxSphereIntersect - (const Box& s1, const Transform3f& tf1, - const Sphere& s2, const Transform3f& tf2, - FCL_REAL& distance, Vec3f& p1, Vec3f& p2, - Vec3f& normal) + /// Taken from book Real Time Collision Detection, from Christer Ericson + /// \param pb the closest point to the sphere center on the box surface + /// \param ps when colliding, matches pb, which is inside the sphere. + /// when not colliding, the closest point on the sphere + /// \param normal direction of motion of the box + /// \return true if the distance is negative (the shape overlaps). + inline bool boxSphereDistance(const Box & b, const Transform3f& tfb, + const Sphere& s, const Transform3f& tfs, + FCL_REAL& dist, Vec3f& pb, Vec3f& ps, + Vec3f& normal) { - // C: center of the sphere in the frame of the box - const Vec3f& Cglobal (tf2.getTranslation ()); - const Vec3f CinBox (inverse (tf1).transform (Cglobal)); - bool CinsideBox (true); - FCL_REAL depth = std::numeric_limits <FCL_REAL>::max (); - // Compute closest point on box in frame of box - for (Vec3f::Index i=0; i<3; ++i) { - if (CinBox [i] >= .5* s1.side [i]) { - p1 [i] = .5* s1.side [i]; - CinsideBox = false; - } - else if (CinBox [i] < -.5* s1.side [i]) { - p1 [i] = -.5* s1.side [i]; - CinsideBox = false; - } - else { - p1 [i] = CinBox [i]; - if (.5*s1.side [i] - CinBox [i] < depth) { - depth = .5*s1.side [i] - CinBox [i]; - normal.setZero (); normal [i] = 1; - } - else if (CinBox[i] + .5*s1.side [i] < depth) - depth = .5*s1.side [i] - CinBox [i]; - normal.setZero (); normal [i] = -1; - } + const Vec3f& os = tfs.getTranslation(); + const Vec3f& ob = tfb.getTranslation(); + const Matrix3f& Rb = tfb.getRotation(); + + const Vec3f d (os - ob); + pb = ob; + + bool inside = true; + for (int i = 0; i < 3; ++i) { + bool iinside = false; + FCL_REAL dist = Rb.col(i).dot(d), side_2 = b.side(i) / 2; + if (dist < -side_2) dist = -side_2; // outside + else if (dist > side_2) dist = side_2; // outside + else iinside = true; // inside + inside = inside && iinside; + + pb.noalias() += dist * Rb.col(i); } - if (CinsideBox) { - // Center of sphere is inside box - p1 = p2 = Cglobal; - // Express normal in global frame - normal = tf1.transform (normal); - distance = -depth; - return true; + normal.noalias() = pb - os; + FCL_REAL pdist = normal.norm(); + if (inside) { + dist = - pdist - s.radius; + normal /= pdist; + } else { + dist = pdist - s.radius; + normal /= - pdist; } - // Center of sphere is outside box - // express p1 in global frame - p1 = tf1.transform (p1); - Vec3f diff (Cglobal - p1); - FCL_REAL dist (diff.norm ()); - normal = diff/dist; - distance = dist - s2.radius; - if (distance <= 0) { - p2 = p1; + if (inside || dist <= 0) { + ps = pb; return true; } else { - p2 = p1 + distance * normal; + ps = os + s.radius * normal; return false; } } diff --git a/test/test_fcl_geometric_shapes.cpp b/test/test_fcl_geometric_shapes.cpp index d675521986943bb56bb3db4b5faea7ddc5133ea7..ce6c7e6f8a809c85131c4351e8dedf1feccabc01 100644 --- a/test/test_fcl_geometric_shapes.cpp +++ b/test/test_fcl_geometric_shapes.cpp @@ -1121,7 +1121,7 @@ BOOST_AUTO_TEST_CASE(shapeIntersection_planesphere) contact = transform.transform(Vec3f(0, 0, 0)); depth = 10; normal = transform.getRotation() * Vec3f(1, 0, 0); // (1, 0, 0) or (-1, 0, 0) - testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal); + testShapeIntersection(s, tf1, hs, tf2, GST_INDEP, true, &contact, &depth, &normal, true); tf1 = Transform3f(); tf2 = Transform3f(Vec3f(5, 0, 0));