/* * Software License Agreement (BSD License) * * Copyright (c) 2011-2014, Willow Garage, Inc. * Copyright (c) 2014-2016, Open Source Robotics Foundation * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of Open Source Robotics Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** @author Jia Pan */ #include #include #include #include #include "fcl/common/unused.h" #include "fcl/math/motion/translation_motion.h" #include "fcl/geometry/shape/cone.h" #include "fcl/geometry/shape/capsule.h" #include "fcl/geometry/shape/ellipsoid.h" #include "fcl/geometry/shape/halfspace.h" #include "fcl/geometry/shape/plane.h" #include "fcl/narrowphase/detail/gjk_solver_indep.h" #include "fcl/narrowphase/detail/gjk_solver_libccd.h" #include "fcl/narrowphase/collision.h" #include "test_fcl_utility.h" using namespace fcl; template std::array& extents() { static std::array static_extents{ {0, 0, 0, 10, 10, 10} }; return static_extents; } template detail::GJKSolver_libccd& solver1() { static detail::GJKSolver_libccd static_solver1; return static_solver1; } template detail::GJKSolver_indep& solver2() { static detail::GJKSolver_indep static_solver2; return static_solver2; } template S tolerance(); template <> float tolerance() { return 1e-4; } template <> double tolerance() { return 1e-12; } template void test_sphere_shape() { const S radius = 5.0; const S pi = constants::pi(); Sphere s(radius); const auto volume = 4.0 / 3.0 * pi * radius * radius * radius; EXPECT_NEAR(volume, s.computeVolume(), tolerance()); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, sphere_shape) { // test_sphere_shape(); test_sphere_shape(); } template void test_gjkcache() { Cylinder s1(5, 10); Cone s2(5, 10); CollisionRequest request; request.enable_cached_gjk_guess = true; request.gjk_solver_type = GST_INDEP; TranslationMotion motion(Transform3(Translation3(Vector3(-20.0, -20.0, -20.0))), Transform3(Translation3(Vector3(20.0, 20.0, 20.0)))); int N = 1000; S dt = 1.0 / (N - 1); /// test exploiting spatial coherence test::Timer timer1; timer1.start(); std::vector result1(N); for(int i = 0; i < N; ++i) { motion.integrate(dt * i); Transform3 tf; motion.getCurrentTransform(tf); CollisionResult result; collide(&s1, Transform3::Identity(), &s2, tf, request, result); result1[i] = result.isCollision(); request.cached_gjk_guess = result.cached_gjk_guess; // use cached guess } timer1.stop(); /// test without exploiting spatial coherence test::Timer timer2; timer2.start(); std::vector result2(N); request.enable_cached_gjk_guess = false; for(int i = 0; i < N; ++i) { motion.integrate(dt * i); Transform3 tf; motion.getCurrentTransform(tf); CollisionResult result; collide(&s1, Transform3::Identity(), &s2, tf, request, result); result2[i] = result.isCollision(); } timer2.stop(); std::cout << timer1.getElapsedTime() << " " << timer2.getElapsedTime() << std::endl; for(std::size_t i = 0; i < result1.size(); ++i) { EXPECT_TRUE(result1[i] == result2[i]); } } GTEST_TEST(FCL_GEOMETRIC_SHAPES, gjkcache) { // test_gjkcache(); test_gjkcache(); } template void printComparisonError(const std::string& comparison_type, const Shape1& s1, const Transform3& tf1, const Shape2& s2, const Transform3& tf2, GJKSolverType solver_type, const Vector3& expected_contact_or_normal, const Vector3& actual_contact_or_normal, bool check_opposite_normal, typename Shape1::S tol) { std::cout << "Disagreement between " << comparison_type << " and expected_" << comparison_type << " for " << test::getNodeTypeName(s1.getNodeType()) << " and " << test::getNodeTypeName(s2.getNodeType()) << " with '" << test::getGJKSolverName(solver_type) << "' solver." << std::endl << "tf1.linear: \n" << tf1.linear() << std::endl << "tf1.translation: " << tf1.translation().transpose() << std::endl << "tf2.linear: \n" << tf2.linear() << std::endl << "tf2.translation: " << tf2.translation().transpose() << std::endl << "expected_" << comparison_type << ": " << expected_contact_or_normal << "actual_" << comparison_type << " : " << actual_contact_or_normal << std::endl; if (check_opposite_normal) std::cout << " or " << -expected_contact_or_normal; std::cout << std::endl << "difference: " << (actual_contact_or_normal - expected_contact_or_normal).norm() << std::endl << "tolerance: " << tol << std::endl; } template void printComparisonError(const std::string& comparison_type, const Shape1& s1, const Transform3& tf1, const Shape2& s2, const Transform3& tf2, GJKSolverType solver_type, typename Shape1::S expected_depth, typename Shape1::S actual_depth, typename Shape1::S tol) { std::cout << "Disagreement between " << comparison_type << " and expected_" << comparison_type << " for " << test::getNodeTypeName(s1.getNodeType()) << " and " << test::getNodeTypeName(s2.getNodeType()) << " with '" << test::getGJKSolverName(solver_type) << "' solver." << std::endl << "tf1.linear: \n" << tf1.linear() << std::endl << "tf1.translation: " << tf1.translation().transpose() << std::endl << "tf2.linear: \n" << tf2.linear() << std::endl << "tf2.translation: " << tf2.translation().transpose() << std::endl << "expected_depth: " << expected_depth << std::endl << "actual_depth : " << actual_depth << std::endl << "difference: " << std::abs(actual_depth - expected_depth) << std::endl << "tolerance: " << tol << std::endl; } template bool checkContactPointds(const Shape1& s1, const Transform3& tf1, const Shape2& s2, const Transform3& tf2, GJKSolverType solver_type, const ContactPoint& expected, const ContactPoint& actual, bool check_position = false, bool check_depth = false, bool check_normal = false, bool check_opposite_normal = false, typename Shape1::S tol = 1e-9) { FCL_UNUSED(s1); FCL_UNUSED(tf1); FCL_UNUSED(s2); FCL_UNUSED(tf2); FCL_UNUSED(solver_type); if (check_position) { bool contact_equal = actual.pos.isApprox(expected.pos, tol); if (!contact_equal) return false; } if (check_depth) { bool depth_equal = std::abs(actual.penetration_depth - expected.penetration_depth) < tol; if (!depth_equal) return false; } if (check_normal) { bool normal_equal = actual.normal.isApprox(expected.normal, tol); if (!normal_equal && check_opposite_normal) normal_equal = actual.normal.isApprox(-expected.normal, tol); if (!normal_equal) return false; } return true; } template bool inspectContactPointds(const Shape1& s1, const Transform3& tf1, const Shape2& s2, const Transform3& tf2, GJKSolverType solver_type, const std::vector>& expected_contacts, const std::vector>& actual_contacts, bool check_position = false, bool check_depth = false, bool check_normal = false, bool check_opposite_normal = false, typename Shape1::S tol = 1e-9) { using S = typename Shape1::S; // Check number of contact points bool sameNumContacts = (actual_contacts.size() == expected_contacts.size()); EXPECT_TRUE(sameNumContacts); if (!sameNumContacts) { std::cout << "\n" << "===== [ geometric shape collision test failure report ] ======\n" << "\n" << "Solver type: " << test::getGJKSolverName(solver_type) << "\n" << "\n" << "[ Shape 1 ]\n" << "Shape type : " << test::getNodeTypeName(s1.getNodeType()) << "\n" << "tf1.linear : \n" << tf1.linear() << "\n" << "tf1.translation: " << tf1.translation().transpose() << "\n" << "\n" << "[ Shape 2 ]\n" << "Shape type : " << test::getNodeTypeName(s2.getNodeType()) << "\n" << "tf2.linear : \n" << tf2.linear() << "\n" << "tf2.translation: " << tf2.translation().transpose() << "\n" << "\n" << "The numbers of expected contacts '" << expected_contacts.size() << "' and the number of actual contacts '" << actual_contacts.size() << "' are not equal.\n" << "\n"; return false; } // Check if actual contacts and expected contacts are matched const size_t numContacts = actual_contacts.size(); std::vector index_to_actual_contacts(numContacts, -1); std::vector index_to_expected_contacts(numContacts, -1); bool foundAll = true; for (size_t i = 0; i < numContacts; ++i) { const ContactPoint& expected = expected_contacts[i]; // Check if expected contact is in the list of actual contacts for (size_t j = 0; j < numContacts; ++j) { if (index_to_expected_contacts[j] != -1) continue; const ContactPoint& actual = actual_contacts[j]; bool found = checkContactPointds( s1, tf1, s2, tf2, solver_type, expected, actual, check_position, check_depth, check_normal, check_opposite_normal, tol); if (found) { index_to_actual_contacts[i] = j; index_to_expected_contacts[j] = i; break; } } if (index_to_actual_contacts[i] == -1) foundAll = false; } if (!foundAll) { std::cout << "\n" << "===== [ geometric shape collision test failure report ] ======\n" << "\n" << "Solver type: " << test::getGJKSolverName(solver_type) << "\n" << "\n" << "[ Shape 1 ]\n" << "Shape type : " << test::getNodeTypeName(s1.getNodeType()) << "\n" << "tf1.linear : \n" << tf1.linear() << "\n" << "tf1.translation: " << tf1.translation().transpose() << "\n" << "\n" << "[ Shape 2 ]\n" << "Shape type : " << test::getNodeTypeName(s2.getNodeType()) << "\n" << "tf2.linear : \n" << tf2.linear() << "\n" << "tf2.translation: " << tf2.translation().transpose() << "\n" << "\n" << "[ Expected Contacts: " << numContacts << " ]\n"; for (size_t i = 0; i < numContacts; ++i) { const ContactPoint& expected = expected_contacts[i]; std::cout << "(" << i << ") pos: " << expected.pos.transpose() << ", " << "normal: " << expected.normal.transpose() << ", " << "depth: " << expected.penetration_depth << " ---- "; if (index_to_actual_contacts[i] != -1) std::cout << "found, actual (" << index_to_actual_contacts[i] << ")\n"; else std::cout << "not found!\n"; } std::cout << "\n" << "[ Actual Contacts: " << numContacts << " ]\n"; for (size_t i = 0; i < numContacts; ++i) { const ContactPoint& actual = actual_contacts[i]; std::cout << "(" << i << ") pos: " << actual.pos.transpose() << ", " << "normal: " << actual.normal.transpose() << ", " << "depth: " << actual.penetration_depth << " ---- "; if (index_to_expected_contacts[i] != -1) std::cout << "found, expected (" << index_to_expected_contacts[i] << ")\n"; else std::cout << "not found!\n"; } std::cout << "\n"; } return foundAll; } template void getContactPointdsFromResult(std::vector>& contacts, const CollisionResult& result) { const size_t numContacts = result.numContacts(); contacts.resize(numContacts); for (size_t i = 0; i < numContacts; ++i) { const auto& cnt = result.getContact(i); contacts[i].pos = cnt.pos; contacts[i].normal = cnt.normal; contacts[i].penetration_depth = cnt.penetration_depth; } } template void testShapeIntersection( const Shape1& s1, const Transform3& tf1, const Shape2& s2, const Transform3& tf2, GJKSolverType solver_type, bool expected_res, const std::vector>& expected_contacts = std::vector>(), bool check_position = true, bool check_depth = true, bool check_normal = true, bool check_opposite_normal = false, typename Shape1::S tol = 1e-9) { using S = typename Shape1::S; CollisionRequest request; request.gjk_solver_type = solver_type; request.num_max_contacts = std::numeric_limits::max(); CollisionResult result; std::vector> actual_contacts; bool res; // Part A: Check collisions using shapeIntersect() // Check only whether they are colliding or not. if (solver_type == GST_LIBCCD) { res = solver1().shapeIntersect(s1, tf1, s2, tf2, nullptr); } else if (solver_type == GST_INDEP) { res = solver2().shapeIntersect(s1, tf1, s2, tf2, nullptr); } else { std::cerr << "Invalid GJK solver. Test aborted." << std::endl; return; } EXPECT_EQ(expected_res, res); // Check contact information as well if (solver_type == GST_LIBCCD) { res = solver1().shapeIntersect(s1, tf1, s2, tf2, &actual_contacts); } else if (solver_type == GST_INDEP) { res = solver2().shapeIntersect(s1, tf1, s2, tf2, &actual_contacts); } else { std::cerr << "Invalid GJK solver. Test aborted." << std::endl; return; } EXPECT_EQ(expected_res, res); if (expected_res) { EXPECT_TRUE(inspectContactPointds(s1, tf1, s2, tf2, solver_type, expected_contacts, actual_contacts, check_position, check_depth, check_normal, check_opposite_normal, tol)); } // Part B: Check collisions using collide() // Check only whether they are colliding or not. request.enable_contact = false; result.clear(); res = (collide(&s1, tf1, &s2, tf2, request, result) > 0); EXPECT_EQ(expected_res, res); // Check contact information as well request.enable_contact = true; result.clear(); res = (collide(&s1, tf1, &s2, tf2, request, result) > 0); EXPECT_EQ(expected_res, res); if (expected_res) { getContactPointdsFromResult(actual_contacts, result); EXPECT_TRUE(inspectContactPointds(s1, tf1, s2, tf2, solver_type, expected_contacts, actual_contacts, check_position, check_depth, check_normal, check_opposite_normal, tol)); } } // Shape intersection test coverage (libccd) // // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | | box | sphere | ellipsoid | capsule | cone | cylinder | plane | half-space | triangle | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | box | O | O | | | | | O | O | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | sphere |/////| O | | | | | O | O | O | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | ellipsoid |/////|////////| O | | | | O | O | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | capsule |/////|////////|///////////| | | | O | O | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | cone |/////|////////|///////////|/////////| O | O | O | O | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | cylinder |/////|////////|///////////|/////////|//////| O | O | O | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | plane |/////|////////|///////////|/////////|//////|//////////| | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | half-space |/////|////////|///////////|/////////|//////|//////////|///////| | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | triangle |/////|////////|///////////|/////////|//////|//////////|///////|////////////| | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ template void test_shapeIntersection_spheresphere() { Sphere s1(20); Sphere s2(10); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(40, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(40, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(30, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; contacts[0].pos << 20, 0, 0; contacts[0].penetration_depth = 0.0; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(30.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(30.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(29.9, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; contacts[0].pos << 20.0 - 0.1 * 20.0/(20.0 + 10.0), 0, 0; contacts[0].penetration_depth = 0.1; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(29.9, 0, 0))); contacts.resize(1); contacts[0].normal = transform.linear() * Vector3(1, 0, 0); contacts[0].pos = transform * Vector3(20.0 - 0.1 * 20.0/(20.0 + 10.0), 0, 0); contacts[0].penetration_depth = 0.1; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].normal.setZero(); // If the centers of two sphere are at the same position, the normal is (0, 0, 0) contacts[0].pos.setZero(); contacts[0].penetration_depth = 20.0 + 10.0; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].normal.setZero(); // If the centers of two sphere are at the same position, the normal is (0, 0, 0) contacts[0].pos = transform * Vector3::Zero(); contacts[0].penetration_depth = 20.0 + 10.0; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-29.9, 0, 0))); contacts.resize(1); contacts[0].normal << -1, 0, 0; contacts[0].pos << -20.0 + 0.1 * 20.0/(20.0 + 10.0), 0, 0; contacts[0].penetration_depth = 0.1; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-29.9, 0, 0))); contacts.resize(1); contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); contacts[0].pos = transform * Vector3(-20.0 + 0.1 * 20.0/(20.0 + 10.0), 0, 0); contacts[0].penetration_depth = 0.1; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-30.0, 0, 0))); contacts.resize(1); contacts[0].normal << -1, 0, 0; contacts[0].pos << -20, 0, 0; contacts[0].penetration_depth = 0.0; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-30.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-30.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_spheresphere) { // test_shapeIntersection_spheresphere(); test_shapeIntersection_spheresphere(); } template bool compareContactPointds1(const Vector3& c1,const Vector3& c2) { return c1[2] < c2[2]; } // Ascending order template bool compareContactPointds2(const ContactPoint& cp1,const ContactPoint& cp2) { return cp1.pos[2] < cp2.pos[2]; } // Ascending order // Simple aligned boxes intersecting each other // // s2 ┌───┐ // │ │ // ┏━━━━━━━━━┿━━━┿━━━━━━━━━┓┄┄┄┄┄ z = 0 // ┃ │┄┄┄│┄┄┄┄┄┄┄┄┄┃┄┄┄ Reported contact depth // ┃ └───┘ ┃ // ┃ ┃ // ┃ ┃ // ┃ s1 ┃ // ┃ ┃ // ┃ ┃ // ┃ ┃ // ┗━━━━━━━━━━━━━━━━━━━━━━━┛ // // s1 is a cube, 100 units to a side. Shifted downward 50 units so that it's // top face is at z = 0. // s2 is a box with dimensions 10, 20, 30 in the x-, y-, and z-directions, // respectively. It is centered on the origin and oriented according to the // provided rotation matrix `R`. // The total penetration depth is the |z_max| where z_max is the z-position of // the most deeply penetrating vertex on s2. The contact position will be // located at -z_max / 2 (with the assumption that all penetration happens // *below* the z = 0 axis. template void testBoxBoxContactPointds(const Eigen::MatrixBase& R) { using S = typename Derived::RealScalar; Box s1(100, 100, 100); Box s2(10, 20, 30); // Vertices of s2 std::vector> vertices(8); vertices[0] << 1, 1, 1; vertices[1] << 1, 1, -1; vertices[2] << 1, -1, 1; vertices[3] << 1, -1, -1; vertices[4] << -1, 1, 1; vertices[5] << -1, 1, -1; vertices[6] << -1, -1, 1; vertices[7] << -1, -1, -1; for (int i = 0; i < 8; ++i) { vertices[i][0] *= 0.5 * s2.side[0]; vertices[i][1] *= 0.5 * s2.side[1]; vertices[i][2] *= 0.5 * s2.side[2]; } Transform3 tf1 = Transform3(Translation3(Vector3(0, 0, -50))); Transform3 tf2 = Transform3(R); std::vector> contacts; // Make sure the two boxes are colliding bool res = solver1().shapeIntersect(s1, tf1, s2, tf2, &contacts); EXPECT_TRUE(res); // Compute global vertices for (int i = 0; i < 8; ++i) vertices[i] = tf2 * vertices[i]; // Sort the vertices so that the lowest vertex along z-axis comes first std::sort(vertices.begin(), vertices.end(), compareContactPointds1); std::sort(contacts.begin(), contacts.end(), compareContactPointds2); // The lowest n vertex along z-axis should be the contact point size_t numContacts = contacts.size(); numContacts = std::min(static_cast(1), numContacts); // TODO: BoxBox algorithm seems not able to find all the colliding vertices. // We just check the deepest one as workaround. for (size_t i = 0; i < numContacts; ++i) { // The reported contact position will lie mid-way between the deepest // penetrating vertex on s2 and the z = 0 plane. Vector3 contact_pos(vertices[i]); contact_pos(2) /= 2; EXPECT_TRUE(contact_pos.isApprox(contacts[i].pos)) << "\n\tExpected: " << contact_pos << "\n\tFound: " << contacts[i].pos; EXPECT_TRUE(Vector3(0, 0, 1).isApprox(contacts[i].normal)); } } template void test_shapeIntersection_boxbox() { Box s1(20, 40, 50); Box s2(10, 10, 10); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; Quaternion q(AngleAxis((S)3.140 / 6, Vector3(0, 0, 1))); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); // TODO: Need convention for normal when the centers of two objects are at same position. The current result is (1, 0, 0). contacts.resize(4); contacts[0].normal << 1, 0, 0; contacts[1].normal << 1, 0, 0; contacts[2].normal << 1, 0, 0; contacts[3].normal << 1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true); tf1 = transform; tf2 = transform; // TODO: Need convention for normal when the centers of two objects are at same position. The current result is (1, 0, 0). contacts.resize(4); contacts[0].normal = transform.linear() * Vector3(1, 0, 0); contacts[1].normal = transform.linear() * Vector3(1, 0, 0); contacts[2].normal = transform.linear() * Vector3(1, 0, 0); contacts[3].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(15, 0, 0))); contacts.resize(4); contacts[0].normal = Vector3(1, 0, 0); contacts[1].normal = Vector3(1, 0, 0); contacts[2].normal = Vector3(1, 0, 0); contacts[3].normal = Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(15.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(q); contacts.resize(4); contacts[0].normal = Vector3(1, 0, 0); contacts[1].normal = Vector3(1, 0, 0); contacts[2].normal = Vector3(1, 0, 0); contacts[3].normal = Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true); tf1 = transform; tf2 = transform * Transform3(q); contacts.resize(4); contacts[0].normal = transform.linear() * Vector3(1, 0, 0); contacts[1].normal = transform.linear() * Vector3(1, 0, 0); contacts[2].normal = transform.linear() * Vector3(1, 0, 0); contacts[3].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true); // Disabled for particular configurations: macOS + release + double (see #202) #if !defined(FCL_OS_MACOS) || !defined(NDEBUG) uint32 numTests = 1e+2; for (uint32 i = 0; i < numTests; ++i) { Transform3 tf; test::generateRandomTransform(extents(), tf); testBoxBoxContactPointds(tf.linear()); } #endif } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_boxbox) { // test_shapeIntersection_boxbox(); test_shapeIntersection_boxbox(); } template void test_shapeIntersection_spherebox() { // A collection of bool constants to make reading lists of bool easier. const bool collides = true; const bool check_position = true; const bool check_depth = true; const bool check_normal = true; const bool check_opposite_normal = false; Sphere s1(20); Box s2(5, 5, 5); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); // NOTE: The centers of the box and sphere are coincident. The documented // convention is that the normal is aligned with the smallest dimension of // the box, pointing in the negative direction of that axis. *This* test is // the driving basis for that definition. contacts.resize(1); contacts[0].normal << -1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, collides, contacts, !check_position, !check_depth, check_normal); tf1 = transform; tf2 = transform; contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, collides, contacts, !check_position, !check_depth, !check_normal); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(22.5, 0, 0))); // As documented in sphere_box.h, touching is considered collision, so this // should produce a collision. testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, collides, contacts, !check_position, !check_depth, !check_normal); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(22.501, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, !collides); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(22.4, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, collides, contacts, !check_position, !check_depth, check_normal); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(22.4, 0, 0))); contacts.resize(1); contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, collides, contacts, !check_position, !check_depth, check_normal, !check_opposite_normal, 1e-4); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_spherebox) { // test_shapeIntersection_spherebox(); test_shapeIntersection_spherebox(); } template void test_shapeIntersection_spherecapsule() { Sphere s1(20); Capsule s2(5, 10); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, false); tf1 = transform; tf2 = transform; // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(24.9, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(24.9, 0, 0))); contacts.resize(1); contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(25, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true); tf1 = transform; //tf2 = transform * Transform3(Translation3(Vector3(25, 0, 0))); tf2 = transform * Transform3(Translation3(Vector3(25 - 1e-6, 0, 0))); contacts.resize(1); contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(25.1, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(25.1, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_spherecapsule) { // test_shapeIntersection_spherecapsule(); test_shapeIntersection_spherecapsule(); } template void test_shapeIntersection_cylindercylinder() { Cylinder s1(5, 10); Cylinder s2(5, 10); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, false); tf1 = transform; tf2 = transform; // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(9.9, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true); // Disabled for particular configurations: macOS + release + double (see #202) #if !defined(FCL_OS_MACOS) || !defined(NDEBUG) tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(9.9, 0, 0))); contacts.resize(1); contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true, false, 1e-5); #endif tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(10.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(10.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_cylindercylinder) { // test_shapeIntersection_cylindercylinder(); test_shapeIntersection_cylindercylinder(); } template void test_shapeIntersection_conecone() { Cone s1(5, 10); Cone s2(5, 10); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, false); tf1 = transform; tf2 = transform; // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(9.9, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(9.9, 0, 0))); contacts.resize(1); contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true, false, 5e-5); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(10.001, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(10.001, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 9.9))); contacts.resize(1); contacts[0].normal << 0, 0, 1; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 9.9))); contacts.resize(1); contacts[0].normal = transform.linear() * Vector3(0, 0, 1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true, false, 1e-5); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_conecone) { // test_shapeIntersection_conecone(); test_shapeIntersection_conecone(); } template void test_shapeIntersection_cylindercone() { Cylinder s1(5, 10); Cone s2(5, 10); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, false); tf1 = transform; tf2 = transform; // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(9.9, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true, false, 0.061); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(9.9, 0, 0))); contacts.resize(1); contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true, false, 0.46); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(10.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(10.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 9.9))); contacts.resize(1); contacts[0].normal << 0, 0, 1; testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 9.9))); contacts.resize(1); contacts[0].normal = transform.linear() * Vector3(0, 0, 1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, true, false, 1e-4); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 10.01))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 10.01))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_cylindercone) { // test_shapeIntersection_cylindercone(); test_shapeIntersection_cylindercone(); } template void test_shapeIntersection_ellipsoidellipsoid() { Ellipsoid s1(20, 40, 50); Ellipsoid s2(10, 10, 10); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); Transform3 identity; std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(40, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(40, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(30, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(30.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(29.99, 0, 0))); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(29.9, 0, 0))); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, false); tf1 = transform; tf2 = transform; contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-29.99, 0, 0))); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-29.99, 0, 0))); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-30, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-30.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_LIBCCD, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_ellipsoidellipsoid) { // test_shapeIntersection_ellipsoidellipsoid(); test_shapeIntersection_ellipsoidellipsoid(); } template void test_shapeIntersection_spheretriangle() { Sphere s(10); Vector3 t[3]; t[0] << 20, 0, 0; t[1] << -20, 0, 0; t[2] << 0, 20, 0; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); Vector3 normal; bool res; res = solver1().shapeTriangleIntersect(s, Transform3::Identity(), t[0], t[1], t[2], nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver1().shapeTriangleIntersect(s, transform, t[0], t[1], t[2], transform, nullptr, nullptr, nullptr); EXPECT_TRUE(res); t[0] << 30, 0, 0; t[1] << 9.9, -20, 0; t[2] << 9.9, 20, 0; res = solver1().shapeTriangleIntersect(s, Transform3::Identity(), t[0], t[1], t[2], nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver1().shapeTriangleIntersect(s, transform, t[0], t[1], t[2], transform, nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver1().shapeTriangleIntersect(s, Transform3::Identity(), t[0], t[1], t[2], nullptr, nullptr, &normal); EXPECT_TRUE(res); EXPECT_TRUE(normal.isApprox(Vector3(1, 0, 0), 1e-9)); res = solver1().shapeTriangleIntersect(s, transform, t[0], t[1], t[2], transform, nullptr, nullptr, &normal); EXPECT_TRUE(res); EXPECT_TRUE(normal.isApprox(transform.linear() * Vector3(1, 0, 0), 1e-9)); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_spheretriangle) { // test_shapeIntersection_spheretriangle(); test_shapeIntersection_spheretriangle(); } template void test_shapeIntersection_halfspacetriangle() { Halfspace hs(Vector3(1, 0, 0), 0); Vector3 t[3]; t[0] << 20, 0, 0; t[1] << -20, 0, 0; t[2] << 0, 20, 0; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); // Vector3 point; // S depth; Vector3 normal; bool res; res = solver1().shapeTriangleIntersect(hs, Transform3::Identity(), t[0], t[1], t[2], Transform3::Identity(), nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver1().shapeTriangleIntersect(hs, transform, t[0], t[1], t[2], transform, nullptr, nullptr, nullptr); EXPECT_TRUE(res); t[0] << 20, 0, 0; t[1] << 0, -20, 0; t[2] << 0, 20, 0; res = solver1().shapeTriangleIntersect(hs, Transform3::Identity(), t[0], t[1], t[2], Transform3::Identity(), nullptr, nullptr, nullptr); EXPECT_TRUE(res); // Disabled for particular configurations: macOS + release + double (see #202) #if !defined(FCL_OS_MACOS) || !defined(NDEBUG) res = solver1().shapeTriangleIntersect(hs, transform, t[0], t[1], t[2], transform, nullptr, nullptr, nullptr); EXPECT_TRUE(res); #endif res = solver1().shapeTriangleIntersect(hs, Transform3::Identity(), t[0], t[1], t[2], Transform3::Identity(), nullptr, nullptr, &normal); EXPECT_TRUE(res); EXPECT_TRUE(normal.isApprox(Vector3(1, 0, 0), 1e-9)); // Disabled for particular configurations: macOS + release + double (see #202) #if !defined(FCL_OS_MACOS) || !defined(NDEBUG) res = solver1().shapeTriangleIntersect(hs, transform, t[0], t[1], t[2], transform, nullptr, nullptr, &normal); EXPECT_TRUE(res); EXPECT_TRUE(normal.isApprox(transform.linear() * Vector3(1, 0, 0), 1e-9)); #endif } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_halfspacetriangle) { // test_shapeIntersection_halfspacetriangle(); test_shapeIntersection_halfspacetriangle(); } template void test_shapeIntersection_planetriangle() { Plane hs(Vector3(1, 0, 0), 0); Vector3 t[3]; t[0] << 20, 0, 0; t[1] << -20, 0, 0; t[2] << 0, 20, 0; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); // Vector3 point; // S depth; Vector3 normal; bool res; res = solver1().shapeTriangleIntersect(hs, Transform3::Identity(), t[0], t[1], t[2], Transform3::Identity(), nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver1().shapeTriangleIntersect(hs, transform, t[0], t[1], t[2], transform, nullptr, nullptr, nullptr); EXPECT_TRUE(res); t[0] << 20, 0, 0; t[1] << -0.1, -20, 0; t[2] << -0.1, 20, 0; res = solver1().shapeTriangleIntersect(hs, Transform3::Identity(), t[0], t[1], t[2], Transform3::Identity(), nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver1().shapeTriangleIntersect(hs, transform, t[0], t[1], t[2], transform, nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver1().shapeTriangleIntersect(hs, Transform3::Identity(), t[0], t[1], t[2], Transform3::Identity(), nullptr, nullptr, &normal); EXPECT_TRUE(res); EXPECT_TRUE(normal.isApprox(Vector3(1, 0, 0), 1e-9)); res = solver1().shapeTriangleIntersect(hs, transform, t[0], t[1], t[2], transform, nullptr, nullptr, &normal); EXPECT_TRUE(res); EXPECT_TRUE(normal.isApprox(transform.linear() * Vector3(1, 0, 0), 1e-9)); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_planetriangle) { // test_shapeIntersection_planetriangle(); test_shapeIntersection_planetriangle(); } template void test_shapeIntersection_halfspacesphere() { Sphere s(10); Halfspace hs(Vector3(1, 0, 0), 0); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << -5, 0, 0; contacts[0].penetration_depth = 10; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(-5, 0, 0); contacts[0].penetration_depth = 10; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(5, 0, 0))); contacts.resize(1); contacts[0].pos << -2.5, 0, 0; contacts[0].penetration_depth = 15; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-2.5, 0, 0); contacts[0].penetration_depth = 15; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-5, 0, 0))); contacts.resize(1); contacts[0].pos << -7.5, 0, 0; contacts[0].penetration_depth = 5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-7.5, 0, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-10.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-10.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(10.1, 0, 0))); contacts.resize(1); contacts[0].pos << 0.05, 0, 0; contacts[0].penetration_depth = 20.1; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(10.1, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0.05, 0, 0); contacts[0].penetration_depth = 20.1; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_halfspacesphere) { // test_shapeIntersection_halfspacesphere(); test_shapeIntersection_halfspacesphere(); } template void test_shapeIntersection_planesphere() { Sphere s(10); Plane hs(Vector3(1, 0, 0), 0); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos.setZero(); contacts[0].penetration_depth = 10; contacts[0].normal << 1, 0, 0; // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0); contacts[0].penetration_depth = 10; contacts[0].normal = transform.linear() * Vector3(1, 0, 0); // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(5, 0, 0))); contacts.resize(1); contacts[0].pos << 5, 0, 0; contacts[0].penetration_depth = 5; contacts[0].normal << 1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(5, 0, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-5, 0, 0))); contacts.resize(1); contacts[0].pos << -5, 0, 0; contacts[0].penetration_depth = 5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-5, 0, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-10.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-10.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(10.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(10.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_planesphere) { // test_shapeIntersection_planesphere(); test_shapeIntersection_planesphere(); } template void test_shapeIntersection_halfspacebox() { Box s(5, 10, 20); Halfspace hs(Vector3(1, 0, 0), 0); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << -1.25, 0, 0; contacts[0].penetration_depth = 2.5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(-1.25, 0, 0); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(1.25, 0, 0))); contacts.resize(1); contacts[0].pos << -0.625, 0, 0; contacts[0].penetration_depth = 3.75; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(1.25, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-0.625, 0, 0); contacts[0].penetration_depth = 3.75; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-1.25, 0, 0))); contacts.resize(1); contacts[0].pos << -1.875, 0, 0; contacts[0].penetration_depth = 1.25; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-1.25, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-1.875, 0, 0); contacts[0].penetration_depth = 1.25; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(2.51, 0, 0))); contacts.resize(1); contacts[0].pos << 0.005, 0, 0; contacts[0].penetration_depth = 5.01; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(2.51, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0.005, 0, 0); contacts[0].penetration_depth = 5.01; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-2.51, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-2.51, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3(transform.linear()); tf2 = Transform3::Identity(); contacts.resize(1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, false, false, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_halfspacebox) { // test_shapeIntersection_halfspacebox(); test_shapeIntersection_halfspacebox(); } template void test_shapeIntersection_planebox() { Box s(5, 10, 20); Plane hs(Vector3(1, 0, 0), 0); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, 0; contacts[0].penetration_depth = 2.5; contacts[0].normal << 1, 0, 0; // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(1, 0, 0); // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(1.25, 0, 0))); contacts.resize(1); contacts[0].pos << 1.25, 0, 0; contacts[0].penetration_depth = 1.25; contacts[0].normal << 1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(1.25, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(1.25, 0, 0); contacts[0].penetration_depth = 1.25; contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-1.25, 0, 0))); contacts.resize(1); contacts[0].pos << -1.25, 0, 0; contacts[0].penetration_depth = 1.25; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-1.25, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-1.25, 0, 0); contacts[0].penetration_depth = 1.25; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(2.51, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(2.51, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-2.51, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-2.51, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3(transform.linear()); tf2 = Transform3::Identity(); contacts.resize(1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, false, false, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_planebox) { // test_shapeIntersection_planebox(); test_shapeIntersection_planebox(); } template void test_shapeIntersection_halfspaceellipsoid() { Ellipsoid s(5, 10, 20); Halfspace hs(Vector3(1, 0, 0), 0); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << -2.5, 0, 0; contacts[0].penetration_depth = 5.0; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(-2.5, 0, 0); contacts[0].penetration_depth = 5.0; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(1.25, 0, 0))); contacts.resize(1); contacts[0].pos << -1.875, 0, 0; contacts[0].penetration_depth = 6.25; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(1.25, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-1.875, 0, 0); contacts[0].penetration_depth = 6.25; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-1.25, 0, 0))); contacts.resize(1); contacts[0].pos << -3.125, 0, 0; contacts[0].penetration_depth = 3.75; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-1.25, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-3.125, 0, 0); contacts[0].penetration_depth = 3.75; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(5.01, 0, 0))); contacts.resize(1); contacts[0].pos << 0.005, 0, 0; contacts[0].penetration_depth = 10.01; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(5.01, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0.005, 0, 0); contacts[0].penetration_depth = 10.01; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-5.01, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-5.01, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Halfspace(Vector3(0, 1, 0), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, -5.0, 0; contacts[0].penetration_depth = 10.0; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, -5.0, 0); contacts[0].penetration_depth = 10.0; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 1.25, 0))); contacts.resize(1); contacts[0].pos << 0, -4.375, 0; contacts[0].penetration_depth = 11.25; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 1.25, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, -4.375, 0); contacts[0].penetration_depth = 11.25; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -1.25, 0))); contacts.resize(1); contacts[0].pos << 0, -5.625, 0; contacts[0].penetration_depth = 8.75; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -1.25, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, -5.625, 0); contacts[0].penetration_depth = 8.75; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 10.01, 0))); contacts.resize(1); contacts[0].pos << 0, 0.005, 0; contacts[0].penetration_depth = 20.01; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 10.01, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0.005, 0); contacts[0].penetration_depth = 20.01; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -10.01, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -10.01, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Halfspace(Vector3(0, 0, 1), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, -10.0; contacts[0].penetration_depth = 20.0; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -10.0); contacts[0].penetration_depth = 20.0; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 1.25))); contacts.resize(1); contacts[0].pos << 0, 0, -9.375; contacts[0].penetration_depth = 21.25; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 1.25))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -9.375); contacts[0].penetration_depth = 21.25; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -1.25))); contacts.resize(1); contacts[0].pos << 0, 0, -10.625; contacts[0].penetration_depth = 18.75; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -1.25))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -10.625); contacts[0].penetration_depth = 18.75; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 20.01))); contacts.resize(1); contacts[0].pos << 0, 0, 0.005; contacts[0].penetration_depth = 40.01; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 20.01))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0.005); contacts[0].penetration_depth = 40.01; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -20.01))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -20.01))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_halfspaceellipsoid) { // test_shapeIntersection_halfspaceellipsoid(); test_shapeIntersection_halfspaceellipsoid(); } template void test_shapeIntersection_planeellipsoid() { Ellipsoid s(5, 10, 20); Plane hs(Vector3(1, 0, 0), 0); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, 0; contacts[0].penetration_depth = 5.0; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0); contacts[0].penetration_depth = 5.0; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(1.25, 0, 0))); contacts.resize(1); contacts[0].pos << 1.25, 0, 0; contacts[0].penetration_depth = 3.75; contacts[0].normal << 1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(1.25, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(1.25, 0, 0); contacts[0].penetration_depth = 3.75; contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-1.25, 0, 0))); contacts.resize(1); contacts[0].pos << -1.25, 0, 0; contacts[0].penetration_depth = 3.75; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-1.25, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-1.25, 0, 0); contacts[0].penetration_depth = 3.75; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(5.01, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(5.01, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-5.01, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-5.01, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Plane(Vector3(0, 1, 0), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0.0, 0; contacts[0].penetration_depth = 10.0; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0); contacts[0].penetration_depth = 10.0; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 1.25, 0))); contacts.resize(1); contacts[0].pos << 0, 1.25, 0; contacts[0].penetration_depth = 8.75; contacts[0].normal << 0, 1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 1.25, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 1.25, 0); contacts[0].penetration_depth = 8.75; contacts[0].normal = transform.linear() * Vector3(0, 1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -1.25, 0))); contacts.resize(1); contacts[0].pos << 0, -1.25, 0; contacts[0].penetration_depth = 8.75; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -1.25, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, -1.25, 0); contacts[0].penetration_depth = 8.75; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 10.01, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 10.01, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -10.01, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -10.01, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Plane(Vector3(0, 0, 1), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, 0; contacts[0].penetration_depth = 20.0; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0); contacts[0].penetration_depth = 20.0; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 1.25))); contacts.resize(1); contacts[0].pos << 0, 0, 1.25; contacts[0].penetration_depth = 18.75; contacts[0].normal << 0, 0, 1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 1.25))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 1.25); contacts[0].penetration_depth = 18.75; contacts[0].normal = transform.linear() * Vector3(0, 0, 1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -1.25))); contacts.resize(1); contacts[0].pos << 0, 0, -1.25; contacts[0].penetration_depth = 18.75; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -1.25))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -1.25); contacts[0].penetration_depth = 18.75; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 20.01))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 20.01))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -20.01))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -20.01))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_planeellipsoid) { // test_shapeIntersection_planeellipsoid(); test_shapeIntersection_planeellipsoid(); } template void test_shapeIntersection_halfspacecapsule() { Capsule s(5, 10); Halfspace hs(Vector3(1, 0, 0), 0); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << -2.5, 0, 0; contacts[0].penetration_depth = 5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(-2.5, 0, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(2.5, 0, 0))); contacts.resize(1); contacts[0].pos << -1.25, 0, 0; contacts[0].penetration_depth = 7.5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(2.5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-1.25, 0, 0); contacts[0].penetration_depth = 7.5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-2.5, 0, 0))); contacts.resize(1); contacts[0].pos << -3.75, 0, 0; contacts[0].penetration_depth = 2.5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-2.5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-3.75, 0, 0); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(5.1, 0, 0))); contacts.resize(1); contacts[0].pos << 0.05, 0, 0; contacts[0].penetration_depth = 10.1; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(5.1, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0.05, 0, 0); contacts[0].penetration_depth = 10.1; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Halfspace(Vector3(0, 1, 0), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, -2.5, 0; contacts[0].penetration_depth = 5; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, -2.5, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 2.5, 0))); contacts.resize(1); contacts[0].pos << 0, -1.25, 0; contacts[0].penetration_depth = 7.5; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 2.5, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, -1.25, 0); contacts[0].penetration_depth = 7.5; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -2.5, 0))); contacts.resize(1); contacts[0].pos << 0, -3.75, 0; contacts[0].penetration_depth = 2.5; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -2.5, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, -3.75, 0); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 5.1, 0))); contacts.resize(1); contacts[0].pos << 0, 0.05, 0; contacts[0].penetration_depth = 10.1; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 5.1, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0.05, 0); contacts[0].penetration_depth = 10.1; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Halfspace(Vector3(0, 0, 1), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, -5; contacts[0].penetration_depth = 10; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -5); contacts[0].penetration_depth = 10; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 2.5))); contacts.resize(1); contacts[0].pos << 0, 0, -3.75; contacts[0].penetration_depth = 12.5; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 2.5))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -3.75); contacts[0].penetration_depth = 12.5; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -2.5))); contacts.resize(1); contacts[0].pos << 0, 0, -6.25; contacts[0].penetration_depth = 7.5; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -2.5))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -6.25); contacts[0].penetration_depth = 7.5; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 10.1))); contacts.resize(1); contacts[0].pos << 0, 0, 0.05; contacts[0].penetration_depth = 20.1; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 10.1))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0.05); contacts[0].penetration_depth = 20.1; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -10.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -10.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_halfspacecapsule) { // test_shapeIntersection_halfspacecapsule(); test_shapeIntersection_halfspacecapsule(); } template void test_shapeIntersection_planecapsule() { Capsule s(5, 10); Plane hs(Vector3(1, 0, 0), 0); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, 0; contacts[0].penetration_depth = 5; contacts[0].normal << 1, 0, 0; // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(1, 0, 0); // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(2.5, 0, 0))); contacts.resize(1); contacts[0].pos << 2.5, 0, 0; contacts[0].penetration_depth = 2.5; contacts[0].normal << 1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(2.5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(2.5, 0, 0); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-2.5, 0, 0))); contacts.resize(1); contacts[0].pos << -2.5, 0, 0; contacts[0].penetration_depth = 2.5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-2.5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-2.5, 0, 0); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Plane(Vector3(0, 1, 0), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, 0; contacts[0].penetration_depth = 5; contacts[0].normal << 0, 1, 0; // (0, 1, 0) or (0, -1, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(0, 1, 0); // (0, 1, 0) or (0, -1, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 2.5, 0))); contacts.resize(1); contacts[0].pos << 0, 2.5, 0; contacts[0].penetration_depth = 2.5; contacts[0].normal << 0, 1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 2.5, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 2.5, 0); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, 1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -2.5, 0))); contacts.resize(1); contacts[0].pos << 0, -2.5, 0; contacts[0].penetration_depth = 2.5; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -2.5, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, -2.5, 0); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Plane(Vector3(0, 0, 1), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, 0; contacts[0].penetration_depth = 10; contacts[0].normal << 0, 0, 1; // (0, 0, 1) or (0, 0, -1) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0); contacts[0].penetration_depth = 10; contacts[0].normal = transform.linear() * Vector3(0, 0, 1); // (0, 0, 1) or (0, 0, -1) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 2.5))); contacts.resize(1); contacts[0].pos << 0, 0, 2.5; contacts[0].penetration_depth = 7.5; contacts[0].normal << 0, 0, 1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 2.5))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 2.5); contacts[0].penetration_depth = 7.5; contacts[0].normal = transform.linear() * Vector3(0, 0, 1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -2.5))); contacts.resize(1); contacts[0].pos << 0, 0, -2.5; contacts[0].penetration_depth = 7.5; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -2.5))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -2.5); contacts[0].penetration_depth = 7.5; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 10.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 10.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -10.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -10.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_planecapsule) { // test_shapeIntersection_planecapsule(); test_shapeIntersection_planecapsule(); } template void test_shapeIntersection_halfspacecylinder() { Cylinder s(5, 10); Halfspace hs(Vector3(1, 0, 0), 0); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << -2.5, 0, 0; contacts[0].penetration_depth = 5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(-2.5, 0, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(2.5, 0, 0))); contacts.resize(1); contacts[0].pos << -1.25, 0, 0; contacts[0].penetration_depth = 7.5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(2.5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-1.25, 0, 0); contacts[0].penetration_depth = 7.5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-2.5, 0, 0))); contacts.resize(1); contacts[0].pos << -3.75, 0, 0; contacts[0].penetration_depth = 2.5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-2.5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-3.75, 0, 0); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(5.1, 0, 0))); contacts.resize(1); contacts[0].pos << 0.05, 0, 0; contacts[0].penetration_depth = 10.1; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(5.1, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0.05, 0, 0); contacts[0].penetration_depth = 10.1; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Halfspace(Vector3(0, 1, 0), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, -2.5, 0; contacts[0].penetration_depth = 5; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, -2.5, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 2.5, 0))); contacts.resize(1); contacts[0].pos << 0, -1.25, 0; contacts[0].penetration_depth = 7.5; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 2.5, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, -1.25, 0); contacts[0].penetration_depth = 7.5; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -2.5, 0))); contacts.resize(1); contacts[0].pos << 0, -3.75, 0; contacts[0].penetration_depth = 2.5; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -2.5, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, -3.75, 0); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 5.1, 0))); contacts.resize(1); contacts[0].pos << 0, 0.05, 0; contacts[0].penetration_depth = 10.1; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 5.1, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0.05, 0); contacts[0].penetration_depth = 10.1; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Halfspace(Vector3(0, 0, 1), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, -2.5; contacts[0].penetration_depth = 5; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -2.5); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 2.5))); contacts.resize(1); contacts[0].pos << 0, 0, -1.25; contacts[0].penetration_depth = 7.5; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 2.5))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -1.25); contacts[0].penetration_depth = 7.5; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -2.5))); contacts.resize(1); contacts[0].pos << 0, 0, -3.75; contacts[0].penetration_depth = 2.5; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -2.5))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -3.75); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 5.1))); contacts.resize(1); contacts[0].pos << 0, 0, 0.05; contacts[0].penetration_depth = 10.1; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 5.1))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0.05); contacts[0].penetration_depth = 10.1; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -5.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -5.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_halfspacecylinder) { // test_shapeIntersection_halfspacecylinder(); test_shapeIntersection_halfspacecylinder(); } template void test_shapeIntersection_planecylinder() { Cylinder s(5, 10); Plane hs(Vector3(1, 0, 0), 0); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, 0; contacts[0].penetration_depth = 5; contacts[0].normal << 1, 0, 0; // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(1, 0, 0); // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(2.5, 0, 0))); contacts.resize(1); contacts[0].pos << 2.5, 0, 0; contacts[0].penetration_depth = 2.5; contacts[0].normal << 1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(2.5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(2.5, 0, 0); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-2.5, 0, 0))); contacts.resize(1); contacts[0].pos << -2.5, 0, 0; contacts[0].penetration_depth = 2.5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-2.5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-2.5, 0, 0); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Plane(Vector3(0, 1, 0), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, 0; contacts[0].penetration_depth = 5; contacts[0].normal << 0, 1, 0; // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(0, 1, 0); // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 2.5, 0))); contacts.resize(1); contacts[0].pos << 0, 2.5, 0; contacts[0].penetration_depth = 2.5; contacts[0].normal << 0, 1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 2.5, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 2.5, 0); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, 1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -2.5, 0))); contacts.resize(1); contacts[0].pos << 0, -2.5, 0; contacts[0].penetration_depth = 2.5; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -2.5, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, -2.5, 0); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Plane(Vector3(0, 0, 1), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, 0; contacts[0].penetration_depth = 5; contacts[0].normal << 0, 0, 1; // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(0, 0, 1); // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 2.5))); contacts.resize(1); contacts[0].pos << 0, 0, 2.5; contacts[0].penetration_depth = 2.5; contacts[0].normal << 0, 0, 1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 2.5))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 2.5); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, 0, 1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -2.5))); contacts.resize(1); contacts[0].pos << 0, 0, -2.5; contacts[0].penetration_depth = 2.5; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -2.5))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -2.5); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 10.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 10.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -10.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -10.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_planecylinder) { // test_shapeIntersection_planecylinder(); test_shapeIntersection_planecylinder(); } template void test_shapeIntersection_halfspacecone() { Cone s(5, 10); Halfspace hs(Vector3(1, 0, 0), 0); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << -2.5, 0, -5; contacts[0].penetration_depth = 5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(-2.5, 0, -5); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(2.5, 0, 0))); contacts.resize(1); contacts[0].pos << -1.25, 0, -5; contacts[0].penetration_depth = 7.5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(2.5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-1.25, 0, -5); contacts[0].penetration_depth = 7.5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-2.5, 0, 0))); contacts.resize(1); contacts[0].pos << -3.75, 0, -5; contacts[0].penetration_depth = 2.5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-2.5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-3.75, 0, -5); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(5.1, 0, 0))); contacts.resize(1); contacts[0].pos << 0.05, 0, -5; contacts[0].penetration_depth = 10.1; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(5.1, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0.05, 0, -5); contacts[0].penetration_depth = 10.1; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Halfspace(Vector3(0, 1, 0), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, -2.5, -5; contacts[0].penetration_depth = 5; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, -2.5, -5); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 2.5, 0))); contacts.resize(1); contacts[0].pos << 0, -1.25, -5; contacts[0].penetration_depth = 7.5; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 2.5, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, -1.25, -5); contacts[0].penetration_depth = 7.5; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -2.5, 0))); contacts.resize(1); contacts[0].pos << 0, -3.75, -5; contacts[0].penetration_depth = 2.5; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -2.5, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, -3.75, -5); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 5.1, 0))); contacts.resize(1); contacts[0].pos << 0, 0.05, -5; contacts[0].penetration_depth = 10.1; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 5.1, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0.05, -5); contacts[0].penetration_depth = 10.1; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Halfspace(Vector3(0, 0, 1), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, -2.5; contacts[0].penetration_depth = 5; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -2.5); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 2.5))); contacts.resize(1); contacts[0].pos << 0, 0, -1.25; contacts[0].penetration_depth = 7.5; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 2.5))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -1.25); contacts[0].penetration_depth = 7.5; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -2.5))); contacts.resize(1); contacts[0].pos << 0, 0, -3.75; contacts[0].penetration_depth= 2.5; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -2.5))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -3.75); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 5.1))); contacts.resize(1); contacts[0].pos << 0, 0, 0.05; contacts[0].penetration_depth = 10.1; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 5.1))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0.05); contacts[0].penetration_depth = 10.1; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -5.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -5.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_halfspacecone) { // test_shapeIntersection_halfspacecone(); test_shapeIntersection_halfspacecone(); } template void test_shapeIntersection_planecone() { Cone s(5, 10); Plane hs(Vector3(1, 0, 0), 0); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, 0; contacts[0].penetration_depth = 5; contacts[0].normal << 1, 0, 0; // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(2.5, 0, 0))); contacts.resize(1); contacts[0].pos << 2.5, 0, -2.5; contacts[0].penetration_depth = 2.5; contacts[0].normal << 1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(2.5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(2.5, 0, -2.5); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-2.5, 0, 0))); contacts.resize(1); contacts[0].pos << -2.5, 0, -2.5; contacts[0].penetration_depth = 2.5; contacts[0].normal << -1, 0, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-2.5, 0, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(-2.5, 0, -2.5); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-5.1, 0, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Plane(Vector3(0, 1, 0), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, 0; contacts[0].penetration_depth = 5; contacts[0].normal << 0, 1, 0; // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(0, 1, 0); // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 2.5, 0))); contacts.resize(1); contacts[0].pos << 0, 2.5, -2.5; contacts[0].penetration_depth = 2.5; contacts[0].normal << 0, 1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 2.5, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 2.5, -2.5); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, 1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -2.5, 0))); contacts.resize(1); contacts[0].pos << 0, -2.5, -2.5; contacts[0].penetration_depth = 2.5; contacts[0].normal << 0, -1, 0; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -2.5, 0))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, -2.5, -2.5); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, -1, 0); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, -5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, -5.1, 0))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); hs = Plane(Vector3(0, 0, 1), 0); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].pos << 0, 0, 0; contacts[0].penetration_depth = 5; contacts[0].normal << 0, 0, 1; // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 0); contacts[0].penetration_depth = 5; contacts[0].normal = transform.linear() * Vector3(0, 0, 1); // (1, 0, 0) or (-1, 0, 0) testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts, true, true, true, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 2.5))); contacts.resize(1); contacts[0].pos << 0, 0, 2.5; contacts[0].penetration_depth = 2.5; contacts[0].normal << 0, 0, 1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 2.5))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, 2.5); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, 0, 1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -2.5))); contacts.resize(1); contacts[0].pos << 0, 0, -2.5; contacts[0].penetration_depth = 2.5; contacts[0].normal << 0, 0, -1; testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -2.5))); contacts.resize(1); contacts[0].pos = transform * Vector3(0, 0, -2.5); contacts[0].penetration_depth = 2.5; contacts[0].normal = transform.linear() * Vector3(0, 0, -1); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 10.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 10.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, -10.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, -10.1))); testShapeIntersection(s, tf1, hs, tf2, GST_LIBCCD, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersection_planecone) { // test_shapeIntersection_planecone(); test_shapeIntersection_planecone(); } // Shape distance test coverage (libccd) // // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | | box | sphere | ellipsoid | capsule | cone | cylinder | plane | half-space | triangle | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | box | O | O | | | | | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | sphere |/////| O | | | | | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | ellipsoid |/////|////////| O | | | | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | capsule |/////|////////|///////////| | | | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | cone |/////|////////|///////////|/////////| O | O | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | cylinder |/////|////////|///////////|/////////|//////| O | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | plane |/////|////////|///////////|/////////|//////|//////////| | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | half-space |/////|////////|///////////|/////////|//////|//////////|///////| | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | triangle |/////|////////|///////////|/////////|//////|//////////|///////|////////////| | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ template void test_shapeDistance_spheresphere() { Sphere s1(20); Sphere s2(10); Transform3 transform = Transform3::Identity(); //test::generateRandomTransform(extents(), transform); bool res; S dist = -1; Vector3 closest_p1, closest_p2; res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(0, 40, 0))), &dist, &closest_p1, &closest_p2); EXPECT_TRUE(fabs(dist - 10) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(30.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(29.9, 0, 0))), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, Transform3(Translation3(Vector3(40, 0, 0))), s2, Transform3::Identity(), &dist); EXPECT_TRUE(fabs(dist - 10) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, Transform3(Translation3(Vector3(30.1, 0, 0))), s2, Transform3::Identity(), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, Transform3(Translation3(Vector3(29.9, 0, 0))), s2, Transform3::Identity(), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(40, 0, 0))), &dist); // this is one problem: the precise is low sometimes EXPECT_TRUE(fabs(dist - 10) < 0.1); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(30.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.06); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(29.9, 0, 0))), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, transform * Transform3(Translation3(Vector3(40, 0, 0))), s2, transform, &dist); EXPECT_TRUE(fabs(dist - 10) < 0.1); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform * Transform3(Translation3(Vector3(30.1, 0, 0))), s2, transform, &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.1); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform * Transform3(Translation3(Vector3(29.9, 0, 0))), s2, transform, &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeDistance_spheresphere) { // test_shapeDistance_spheresphere(); test_shapeDistance_spheresphere(); } template void test_shapeDistance_boxbox() { Box s1(20, 40, 50); Box s2(10, 10, 10); Vector3 closest_p1, closest_p2; Transform3 transform = Transform3::Identity(); //test::generateRandomTransform(extents(), transform); bool res; S dist; res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3::Identity(), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, transform, s2, transform, &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s2, Transform3::Identity(), s2, Transform3(Translation3(Vector3(10.1, 0, 0))), &dist, &closest_p1, &closest_p2); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s2, Transform3::Identity(), s2, Transform3(Translation3(Vector3(20.1, 0, 0))), &dist, &closest_p1, &closest_p2); EXPECT_TRUE(fabs(dist - 10.1) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s2, Transform3::Identity(), s2, Transform3(Translation3(Vector3(0, 20.2, 0))), &dist, &closest_p1, &closest_p2); EXPECT_TRUE(fabs(dist - 10.2) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s2, Transform3::Identity(), s2, Transform3(Translation3(Vector3(10.1, 10.1, 0))), &dist, &closest_p1, &closest_p2); EXPECT_TRUE(fabs(dist - 0.1 * 1.414) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s2, Transform3::Identity(), s2, Transform3(Translation3(Vector3(10.1, 0, 0))), &dist, &closest_p1, &closest_p2); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s2, Transform3::Identity(), s2, Transform3(Translation3(Vector3(20.1, 0, 0))), &dist, &closest_p1, &closest_p2); EXPECT_TRUE(fabs(dist - 10.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s2, Transform3::Identity(), s2, Transform3(Translation3(Vector3(0, 20.1, 0))), &dist, &closest_p1, &closest_p2); EXPECT_TRUE(fabs(dist - 10.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s2, Transform3::Identity(), s2, Transform3(Translation3(Vector3(10.1, 10.1, 0))), &dist, &closest_p1, &closest_p2); EXPECT_TRUE(fabs(dist - 0.1 * 1.414) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(15.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(20, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 5) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(20, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 5) < 0.001); EXPECT_TRUE(res); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeDistance_boxbox) { // test_shapeDistance_boxbox(); test_shapeDistance_boxbox(); } template void test_shapeDistance_boxsphere() { Sphere s1(20); Box s2(5, 5, 5); Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); bool res; S dist; res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3::Identity(), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, transform, s2, transform, &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(22.6, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(22.6, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.05); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 17.5) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 17.5) < 0.001); EXPECT_TRUE(res); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeDistance_boxsphere) { // test_shapeDistance_boxsphere(); test_shapeDistance_boxsphere(); } template void test_shapeDistance_cylindercylinder() { Cylinder s1(5, 10); Cylinder s2(5, 10); Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); bool res; S dist; res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3::Identity(), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, transform, s2, transform, &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(10.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(10.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 30) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 30) < 0.001); EXPECT_TRUE(res); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeDistance_cylindercylinder) { // test_shapeDistance_cylindercylinder(); test_shapeDistance_cylindercylinder(); } template void test_shapeDistance_conecone() { Cone s1(5, 10); Cone s2(5, 10); Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); bool res; S dist; res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3::Identity(), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, transform, s2, transform, &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(10.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(10.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(0, 0, 40))), &dist); EXPECT_TRUE(fabs(dist - 30) < 1); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(0, 0, 40))), &dist); EXPECT_TRUE(fabs(dist - 30) < 1); EXPECT_TRUE(res); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeDistance_conecone) { // test_shapeDistance_conecone(); test_shapeDistance_conecone(); } template void test_shapeDistance_conecylinder() { Cylinder s1(5, 10); Cone s2(5, 10); Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); bool res; S dist; res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3::Identity(), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, transform, s2, transform, &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(10.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.01); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(10.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.02); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 30) < 0.01); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 30) < 0.1); EXPECT_TRUE(res); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeDistance_conecylinder) { // test_shapeDistance_conecylinder(); test_shapeDistance_conecylinder(); } template void test_shapeDistance_ellipsoidellipsoid() { Ellipsoid s1(20, 40, 50); Ellipsoid s2(10, 10, 10); Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); bool res; S dist = -1; Vector3 closest_p1, closest_p2; res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(40, 0, 0))), &dist, &closest_p1, &closest_p2); EXPECT_TRUE(fabs(dist - 10) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(30.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(29.9, 0, 0))), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, Transform3(Translation3(Vector3(40, 0, 0))), s2, Transform3::Identity(), &dist); EXPECT_TRUE(fabs(dist - 10) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, Transform3(Translation3(Vector3(30.1, 0, 0))), s2, Transform3::Identity(), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, Transform3(Translation3(Vector3(29.9, 0, 0))), s2, Transform3::Identity(), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 10) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(30.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(29.9, 0, 0))), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver1().shapeDistance(s1, transform * Transform3(Translation3(Vector3(40, 0, 0))), s2, transform, &dist); EXPECT_TRUE(fabs(dist - 10) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform * Transform3(Translation3(Vector3(30.1, 0, 0))), s2, transform, &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver1().shapeDistance(s1, transform * Transform3(Translation3(Vector3(29.9, 0, 0))), s2, transform, &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeDistance_ellipsoidellipsoid) { // test_shapeDistance_ellipsoidellipsoid(); test_shapeDistance_ellipsoidellipsoid(); } // Shape intersection test coverage (built-in GJK) // // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | | box | sphere | ellipsoid | capsule | cone | cylinder | plane | half-space | triangle | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | box | O | O | | | | | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | sphere |/////| O | | | | | | | O | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | ellipsoid |/////|////////| O | | | | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | capsule |/////|////////|///////////| | | | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | cone |/////|////////|///////////|/////////| O | O | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | cylinder |/////|////////|///////////|/////////|//////| O | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | plane |/////|////////|///////////|/////////|//////|//////////| | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | half-space |/////|////////|///////////|/////////|//////|//////////|///////| | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | triangle |/////|////////|///////////|/////////|//////|//////////|///////|////////////| | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ template void test_shapeIntersectionGJK_spheresphere() { Sphere s1(20); Sphere s2(10); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(40, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(40, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(30, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; contacts[0].pos << 20, 0, 0; contacts[0].penetration_depth = 0.0; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(30.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(30.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(29.9, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; contacts[0].pos << 20.0 - 0.1 * 20.0/(20.0 + 10.0), 0, 0; contacts[0].penetration_depth = 0.1; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(29.9, 0, 0))); contacts.resize(1); contacts[0].normal = transform.linear() * Vector3(1, 0, 0); contacts[0].pos = transform * Vector3(20.0 - 0.1 * 20.0/(20.0 + 10.0), 0, 0); contacts[0].penetration_depth = 0.1; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); contacts[0].normal.setZero(); // If the centers of two sphere are at the same position, the normal is (0, 0, 0) contacts[0].pos.setZero(); contacts[0].penetration_depth = 20.0 + 10.0; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts); tf1 = transform; tf2 = transform; contacts.resize(1); contacts[0].normal.setZero(); // If the centers of two sphere are at the same position, the normal is (0, 0, 0) contacts[0].pos = transform * Vector3::Zero(); contacts[0].penetration_depth = 20.0 + 10.0; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-29.9, 0, 0))); contacts.resize(1); contacts[0].normal << -1, 0, 0; contacts[0].pos << -20.0 + 0.1 * 20.0/(20.0 + 10.0), 0, 0; contacts[0].penetration_depth = 0.1; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-29.9, 0, 0))); contacts.resize(1); contacts[0].normal = transform.linear() * Vector3(-1, 0, 0); contacts[0].pos = transform * Vector3(-20.0 + 0.1 * 20.0/(20.0 + 10.0), 0, 0); contacts[0].penetration_depth = 0.1; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-30.0, 0, 0))); contacts.resize(1); contacts[0].normal << -1, 0, 0; contacts[0].pos << -20, 0, 0; contacts[0].penetration_depth = 0.0; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-30.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-30.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersectionGJK_spheresphere) { // test_shapeIntersectionGJK_spheresphere(); test_shapeIntersectionGJK_spheresphere(); } template void test_shapeIntersectionGJK_boxbox() { Box s1(20, 40, 50); Box s2(10, 10, 10); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; Quaternion q(AngleAxis((S)3.140 / 6, Vector3(0, 0, 1))); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); // TODO: Need convention for normal when the centers of two objects are at same position. The current result is (1, 0, 0). contacts.resize(4); contacts[0].normal << 1, 0, 0; contacts[1].normal << 1, 0, 0; contacts[2].normal << 1, 0, 0; contacts[3].normal << 1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true); tf1 = transform; tf2 = transform; // TODO: Need convention for normal when the centers of two objects are at same position. The current result is (1, 0, 0). contacts.resize(4); contacts[0].normal = transform.linear() * Vector3(1, 0, 0); contacts[1].normal = transform.linear() * Vector3(1, 0, 0); contacts[2].normal = transform.linear() * Vector3(1, 0, 0); contacts[3].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(15, 0, 0))); contacts.resize(4); contacts[0].normal = Vector3(1, 0, 0); contacts[1].normal = Vector3(1, 0, 0); contacts[2].normal = Vector3(1, 0, 0); contacts[3].normal = Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(15.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); tf1 = Transform3::Identity(); tf2 = Transform3(q); contacts.resize(4); contacts[0].normal = Vector3(1, 0, 0); contacts[1].normal = Vector3(1, 0, 0); contacts[2].normal = Vector3(1, 0, 0); contacts[3].normal = Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true); tf1 = transform; tf2 = transform * Transform3(q); contacts.resize(4); contacts[0].normal = transform.linear() * Vector3(1, 0, 0); contacts[1].normal = transform.linear() * Vector3(1, 0, 0); contacts[2].normal = transform.linear() * Vector3(1, 0, 0); contacts[3].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersectionGJK_boxbox) { // test_shapeIntersectionGJK_boxbox(); test_shapeIntersectionGJK_boxbox(); } template void test_shapeIntersectionGJK_spherebox() { Sphere s1(20); Box s2(5, 5, 5); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = transform; tf2 = transform; // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(22.5, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; // TODO(SeanCurtis-TRI): This osculating contact is considered a collision // only for a relatively "loose" gjk tolerance. So, for this test to pass, we // set and restore the default gjk tolerances. We need to determine if this is // the correct/desired behavior and, if so, fix the defect that smaller // tolerances prevent this from reporting as a contact. NOTE: this is *not* // the same tolerance that is passed into the `testShapeIntersection` function // -- which isn't actually *used*. { detail::GJKSolver_indep& solver = solver2(); const S old_gjk_tolerance = solver.gjk_tolerance; const S old_epa_tolerance = solver.epa_tolerance; // The historical tolerances for which this test passes. solver.gjk_tolerance = 1e-6; solver.epa_tolerance = 1e-6; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true, false, 1e-7 // built-in GJK solver requires larger tolerance than libccd ); // TODO(SeanCurtis-TRI): If testShapeIntersection fails an *assert* this // code will not get fired off and the static solvers will not get reset. solver.gjk_tolerance = old_gjk_tolerance; solver.epa_tolerance = old_epa_tolerance; } tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(22.51, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(22.4, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true, false, 1e-2); // built-in GJK solver requires larger tolerance than libccd tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(22.4, 0, 0))); contacts.resize(1); // contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); // built-in GJK solver returns incorrect normal. } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersectionGJK_spherebox) { // test_shapeIntersectionGJK_spherebox(); test_shapeIntersectionGJK_spherebox(); } template void test_shapeIntersectionGJK_spherecapsule() { Sphere s1(20); Capsule s2(5, 10); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = transform; tf2 = transform; // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(24.9, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(24.9, 0, 0))); contacts.resize(1); contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(25, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(25.1, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersectionGJK_spherecapsule) { // test_shapeIntersectionGJK_spherecapsule(); test_shapeIntersectionGJK_spherecapsule(); } template void test_shapeIntersectionGJK_cylindercylinder() { Cylinder s1(5, 10); Cylinder s2(5, 10); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = transform; tf2 = transform; // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(9.9, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true, false, 3e-1); // built-in GJK solver requires larger tolerance than libccd tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(9.9, 0, 0))); contacts.resize(1); // contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); // built-in GJK solver returns incorrect normal. tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(10, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(10.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersectionGJK_cylindercylinder) { // test_shapeIntersectionGJK_cylindercylinder(); test_shapeIntersectionGJK_cylindercylinder(); } template void test_shapeIntersectionGJK_conecone() { Cone s1(5, 10); Cone s2(5, 10); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = transform; tf2 = transform; // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(9.9, 0, 0))); contacts.resize(1); contacts[0].normal << 1, 0, 0; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true, false, 5.7e-1); // built-in GJK solver requires larger tolerance than libccd tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(9.9, 0, 0))); contacts.resize(1); // contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); // built-in GJK solver returns incorrect normal. tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(10.1, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(10.1, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 9.9))); contacts.resize(1); contacts[0].normal << 0, 0, 1; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 9.9))); contacts.resize(1); // contacts[0].normal = transform.linear() * Vector3(0, 0, 1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); // built-in GJK solver returns incorrect normal. } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersectionGJK_conecone) { // test_shapeIntersectionGJK_conecone(); test_shapeIntersectionGJK_conecone(); } template void test_shapeIntersectionGJK_cylindercone() { Cylinder s1(5, 10); Cone s2(5, 10); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = transform; tf2 = transform; // TODO: Need convention for normal when the centers of two objects are at same position. contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(9.9, 0, 0))); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(9.9, 0, 0))); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(10, 0, 0))); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(10, 0, 0))); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 9.9))); contacts.resize(1); contacts[0].normal << 0, 0, 1; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 9.9))); contacts.resize(1); // contacts[0].normal = transform.linear() * Vector3(1, 0, 0); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); // built-in GJK solver returns incorrect normal. tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(0, 0, 10))); contacts.resize(1); contacts[0].normal << 0, 0, 1; testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, true); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(0, 0, 10.1))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersectionGJK_cylindercone) { // test_shapeIntersectionGJK_cylindercone(); test_shapeIntersectionGJK_cylindercone(); } template void test_shapeIntersectionGJK_ellipsoidellipsoid() { Ellipsoid s1(20, 40, 50); Ellipsoid s2(10, 10, 10); Transform3 tf1; Transform3 tf2; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); Transform3 identity; std::vector> contacts; tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(40, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(40, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(30, 0, 0))); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(30.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(29.99, 0, 0))); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(29.9, 0, 0))); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3::Identity(); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = transform; tf2 = transform; contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-29.99, 0, 0))); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-29.99, 0, 0))); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = Transform3::Identity(); tf2 = Transform3(Translation3(Vector3(-30, 0, 0))); contacts.resize(1); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, true, contacts, false, false, false); tf1 = transform; tf2 = transform * Transform3(Translation3(Vector3(-30.01, 0, 0))); testShapeIntersection(s1, tf1, s2, tf2, GST_INDEP, false); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersectionGJK_ellipsoidellipsoid) { // test_shapeIntersectionGJK_ellipsoidellipsoid(); test_shapeIntersectionGJK_ellipsoidellipsoid(); } template void test_shapeIntersectionGJK_spheretriangle() { Sphere s(10); Vector3 t[3]; t[0] << 20, 0, 0; t[1] << -20, 0, 0; t[2] << 0, 20, 0; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); // Vector3 point; // S depth; Vector3 normal; bool res; res = solver2().shapeTriangleIntersect(s, Transform3::Identity(), t[0], t[1], t[2], nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver2().shapeTriangleIntersect(s, transform, t[0], t[1], t[2], transform, nullptr, nullptr, nullptr); EXPECT_TRUE(res); t[0] << 30, 0, 0; t[1] << 9.9, -20, 0; t[2] << 9.9, 20, 0; res = solver2().shapeTriangleIntersect(s, Transform3::Identity(), t[0], t[1], t[2], nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver2().shapeTriangleIntersect(s, transform, t[0], t[1], t[2], transform, nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver2().shapeTriangleIntersect(s, Transform3::Identity(), t[0], t[1], t[2], nullptr, nullptr, &normal); EXPECT_TRUE(res); EXPECT_TRUE(normal.isApprox(Vector3(1, 0, 0), 1e-9)); res = solver2().shapeTriangleIntersect(s, transform, t[0], t[1], t[2], transform, nullptr, nullptr, &normal); EXPECT_TRUE(res); EXPECT_TRUE(normal.isApprox(transform.linear() * Vector3(1, 0, 0), 1e-9)); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersectionGJK_spheretriangle) { // test_shapeIntersectionGJK_spheretriangle(); test_shapeIntersectionGJK_spheretriangle(); } template void test_shapeIntersectionGJK_halfspacetriangle() { Halfspace hs(Vector3(1, 0, 0), 0); Vector3 t[3]; t[0] << 20, 0, 0; t[1] << -20, 0, 0; t[2] << 0, 20, 0; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); // Vector3 point; // S depth; Vector3 normal; bool res; res = solver2().shapeTriangleIntersect(hs, Transform3::Identity(), t[0], t[1], t[2], Transform3::Identity(), nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver2().shapeTriangleIntersect(hs, transform, t[0], t[1], t[2], transform, nullptr, nullptr, nullptr); EXPECT_TRUE(res); t[0] << 20, 0, 0; t[1] << -0.1, -20, 0; t[2] << -0.1, 20, 0; res = solver2().shapeTriangleIntersect(hs, Transform3::Identity(), t[0], t[1], t[2], Transform3::Identity(), nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver2().shapeTriangleIntersect(hs, transform, t[0], t[1], t[2], transform, nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver2().shapeTriangleIntersect(hs, Transform3::Identity(), t[0], t[1], t[2], Transform3::Identity(), nullptr, nullptr, &normal); EXPECT_TRUE(res); EXPECT_TRUE(normal.isApprox(Vector3(1, 0, 0), 1e-9)); res = solver2().shapeTriangleIntersect(hs, transform, t[0], t[1], t[2], transform, nullptr, nullptr, &normal); EXPECT_TRUE(res); EXPECT_TRUE(normal.isApprox(transform.linear() * Vector3(1, 0, 0), 1e-9)); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersectionGJK_halfspacetriangle) { // test_shapeIntersectionGJK_halfspacetriangle(); test_shapeIntersectionGJK_halfspacetriangle(); } template void test_shapeIntersectionGJK_planetriangle() { Plane hs(Vector3(1, 0, 0), 0); Vector3 t[3]; t[0] << 20, 0, 0; t[1] << -20, 0, 0; t[2] << 0, 20, 0; Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); // Vector3 point; // S depth; Vector3 normal; bool res; res = solver1().shapeTriangleIntersect(hs, Transform3::Identity(), t[0], t[1], t[2], Transform3::Identity(), nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver1().shapeTriangleIntersect(hs, transform, t[0], t[1], t[2], transform, nullptr, nullptr, nullptr); EXPECT_TRUE(res); t[0] << 20, 0, 0; t[1] << -0.1, -20, 0; t[2] << -0.1, 20, 0; res = solver2().shapeTriangleIntersect(hs, Transform3::Identity(), t[0], t[1], t[2], Transform3::Identity(), nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver2().shapeTriangleIntersect(hs, transform, t[0], t[1], t[2], transform, nullptr, nullptr, nullptr); EXPECT_TRUE(res); res = solver2().shapeTriangleIntersect(hs, Transform3::Identity(), t[0], t[1], t[2], Transform3::Identity(), nullptr, nullptr, &normal); EXPECT_TRUE(res); EXPECT_TRUE(normal.isApprox(Vector3(1, 0, 0), 1e-9)); res = solver2().shapeTriangleIntersect(hs, transform, t[0], t[1], t[2], transform, nullptr, nullptr, &normal); EXPECT_TRUE(res); EXPECT_TRUE(normal.isApprox(transform.linear() * Vector3(1, 0, 0), 1e-9)); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeIntersectionGJK_planetriangle) { // test_shapeIntersectionGJK_planetriangle(); test_shapeIntersectionGJK_planetriangle(); } // Shape distance test coverage (built-in GJK) // // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | | box | sphere | ellipsoid | capsule | cone | cylinder | plane | half-space | triangle | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | box | O | O | | | | | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | sphere |/////| O | | | | | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | ellipsoid |/////|////////| O | | | | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | capsule |/////|////////|///////////| | | | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | cone |/////|////////|///////////|/////////| O | | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | cylinder |/////|////////|///////////|/////////|//////| O | | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | plane |/////|////////|///////////|/////////|//////|//////////| | | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | half-space |/////|////////|///////////|/////////|//////|//////////|///////| | | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ // | triangle |/////|////////|///////////|/////////|//////|//////////|///////|////////////| | // +------------+-----+--------+-----------+---------+------+----------+-------+------------+----------+ template void test_shapeDistanceGJK_spheresphere() { Sphere s1(20); Sphere s2(10); Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); bool res; S dist = -1; res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 10) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(30.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(29.9, 0, 0))), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver2().shapeDistance(s1, Transform3(Translation3(Vector3(40, 0, 0))), s2, Transform3::Identity(), &dist); EXPECT_TRUE(fabs(dist - 10) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, Transform3(Translation3(Vector3(30.1, 0, 0))), s2, Transform3::Identity(), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, Transform3(Translation3(Vector3(29.9, 0, 0))), s2, Transform3::Identity(), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver2().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 10) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(30.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(29.9, 0, 0))), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver2().shapeDistance(s1, transform * Transform3(Translation3(Vector3(40, 0, 0))), s2, transform, &dist); EXPECT_TRUE(fabs(dist - 10) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform * Transform3(Translation3(Vector3(30.1, 0, 0))), s2, transform, &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform * Transform3(Translation3(Vector3(29.9, 0, 0))), s2, transform, &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeDistanceGJK_spheresphere) { // test_shapeDistanceGJK_spheresphere(); test_shapeDistanceGJK_spheresphere(); } template void test_shapeDistanceGJK_boxbox() { Box s1(20, 40, 50); Box s2(10, 10, 10); Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); bool res; S dist; res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3::Identity(), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver2().shapeDistance(s1, transform, s2, transform, &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(15.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(15.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(20, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 5) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(20, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 5) < 0.001); EXPECT_TRUE(res); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeDistanceGJK_boxbox) { // test_shapeDistanceGJK_boxbox(); test_shapeDistanceGJK_boxbox(); } template void test_shapeDistanceGJK_boxsphere() { Sphere s1(20); Box s2(5, 5, 5); Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); bool res; S dist; res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3::Identity(), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver2().shapeDistance(s1, transform, s2, transform, &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(22.6, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.01); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(22.6, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.01); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 17.5) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 17.5) < 0.001); EXPECT_TRUE(res); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeDistanceGJK_boxsphere) { // test_shapeDistanceGJK_boxsphere(); test_shapeDistanceGJK_boxsphere(); } template void test_shapeDistanceGJK_cylindercylinder() { Cylinder s1(5, 10); Cylinder s2(5, 10); Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); bool res; S dist; res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3::Identity(), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver2().shapeDistance(s1, transform, s2, transform, &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(10.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(10.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 30) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 30) < 0.001); EXPECT_TRUE(res); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeDistanceGJK_cylindercylinder) { // test_shapeDistanceGJK_cylindercylinder(); test_shapeDistanceGJK_cylindercylinder(); } template void test_shapeDistanceGJK_conecone() { Cone s1(5, 10); Cone s2(5, 10); Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); bool res; S dist; res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3::Identity(), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver2().shapeDistance(s1, transform, s2, transform, &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(10.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(10.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(0, 0, 40))), &dist); EXPECT_TRUE(fabs(dist - 30) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(0, 0, 40))), &dist); EXPECT_TRUE(fabs(dist - 30) < 0.001); EXPECT_TRUE(res); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeDistanceGJK_conecone) { // test_shapeDistanceGJK_conecone(); test_shapeDistanceGJK_conecone(); } template void test_shapeDistanceGJK_ellipsoidellipsoid() { Ellipsoid s1(20, 40, 50); Ellipsoid s2(10, 10, 10); Transform3 transform = Transform3::Identity(); test::generateRandomTransform(extents(), transform); bool res; S dist = -1; res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 10) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(30.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, Transform3::Identity(), s2, Transform3(Translation3(Vector3(29.9, 0, 0))), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver2().shapeDistance(s1, Transform3(Translation3(Vector3(40, 0, 0))), s2, Transform3::Identity(), &dist); EXPECT_TRUE(fabs(dist - 10) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, Transform3(Translation3(Vector3(30.1, 0, 0))), s2, Transform3::Identity(), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, Transform3(Translation3(Vector3(29.9, 0, 0))), s2, Transform3::Identity(), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver2().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(40, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 10) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(30.1, 0, 0))), &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform, s2, transform * Transform3(Translation3(Vector3(29.9, 0, 0))), &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); res = solver2().shapeDistance(s1, transform * Transform3(Translation3(Vector3(40, 0, 0))), s2, transform, &dist); EXPECT_TRUE(fabs(dist - 10) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform * Transform3(Translation3(Vector3(30.1, 0, 0))), s2, transform, &dist); EXPECT_TRUE(fabs(dist - 0.1) < 0.001); EXPECT_TRUE(res); res = solver2().shapeDistance(s1, transform * Transform3(Translation3(Vector3(29.9, 0, 0))), s2, transform, &dist); EXPECT_TRUE(dist < 0); EXPECT_FALSE(res); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, shapeDistanceGJK_ellipsoidellipsoid) { // test_shapeDistanceGJK_ellipsoidellipsoid(); test_shapeDistanceGJK_ellipsoidellipsoid(); } template void testReversibleShapeIntersection(const Shape1& s1, const Shape2& s2, typename Shape2::S distance) { using S = typename Shape2::S; Transform3 tf1(Translation3(Vector3(-0.5 * distance, 0.0, 0.0))); Transform3 tf2(Translation3(Vector3(+0.5 * distance, 0.0, 0.0))); std::vector> contactsA; std::vector> contactsB; bool resA; bool resB; const double tol = 1e-6; resA = solver1().shapeIntersect(s1, tf1, s2, tf2, &contactsA); resB = solver1().shapeIntersect(s2, tf2, s1, tf1, &contactsB); // normal should be opposite for (size_t i = 0; i < contactsB.size(); ++i) contactsB[i].normal = -contactsB[i].normal; EXPECT_TRUE(resA); EXPECT_TRUE(resB); EXPECT_TRUE(inspectContactPointds(s1, tf1, s2, tf2, GST_LIBCCD, contactsA, contactsB, true, true, true, false, tol)); resA = solver2().shapeIntersect(s1, tf1, s2, tf2, &contactsA); resB = solver2().shapeIntersect(s2, tf2, s1, tf1, &contactsB); // normal should be opposite for (size_t i = 0; i < contactsB.size(); ++i) contactsB[i].normal = -contactsB[i].normal; EXPECT_TRUE(resA); EXPECT_TRUE(resB); EXPECT_TRUE(inspectContactPointds(s1, tf1, s2, tf2, GST_INDEP, contactsA, contactsB, true, true, true, false, tol)); } template void test_reversibleShapeIntersection_allshapes() { // This test check whether a shape intersection algorithm is called for the // reverse case as well. For example, if FCL has sphere-capsule intersection // algorithm, then this algorithm should be called for capsule-sphere case. // Prepare all kinds of primitive shapes (8) -- box, sphere, ellipsoid, capsule, cone, cylinder, plane, halfspace Box box(10, 10, 10); Sphere sphere(5); Ellipsoid ellipsoid(5, 5, 5); Capsule capsule(5, 10); Cone cone(5, 10); Cylinder cylinder(5, 10); Plane plane(Vector3::Zero(), 0.0); Halfspace halfspace(Vector3::Zero(), 0.0); // Use sufficiently short distance so that all the primitive shapes can intersect S distance = 5.0; // If new shape intersection algorithm is added for two distinct primitive // shapes, uncomment associated lines. For example, box-sphere intersection // algorithm is added, then uncomment box-sphere. // testReversibleShapeIntersection(box, sphere, distance); // testReversibleShapeIntersection(box, ellipsoid, distance); // testReversibleShapeIntersection(box, capsule, distance); // testReversibleShapeIntersection(box, cone, distance); // testReversibleShapeIntersection(box, cylinder, distance); testReversibleShapeIntersection(box, plane, distance); testReversibleShapeIntersection(box, halfspace, distance); // testReversibleShapeIntersection(sphere, ellipsoid, distance); testReversibleShapeIntersection(sphere, capsule, distance); // testReversibleShapeIntersection(sphere, cone, distance); // testReversibleShapeIntersection(sphere, cylinder, distance); testReversibleShapeIntersection(sphere, plane, distance); testReversibleShapeIntersection(sphere, halfspace, distance); // testReversibleShapeIntersection(ellipsoid, capsule, distance); // testReversibleShapeIntersection(ellipsoid, cone, distance); // testReversibleShapeIntersection(ellipsoid, cylinder, distance); // testReversibleShapeIntersection(ellipsoid, plane, distance); // testReversibleShapeIntersection(ellipsoid, halfspace, distance); // testReversibleShapeIntersection(capsule, cone, distance); // testReversibleShapeIntersection(capsule, cylinder, distance); testReversibleShapeIntersection(capsule, plane, distance); testReversibleShapeIntersection(capsule, halfspace, distance); // testReversibleShapeIntersection(cone, cylinder, distance); testReversibleShapeIntersection(cone, plane, distance); testReversibleShapeIntersection(cone, halfspace, distance); testReversibleShapeIntersection(cylinder, plane, distance); testReversibleShapeIntersection(cylinder, halfspace, distance); testReversibleShapeIntersection(plane, halfspace, distance); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, reversibleShapeIntersection_allshapes) { // test_reversibleShapeIntersection_allshapes(); test_reversibleShapeIntersection_allshapes(); } template void testReversibleShapeDistance(const Shape1& s1, const Shape2& s2, typename Shape2::S distance) { using S = typename Shape2::S; Transform3 tf1(Translation3(Vector3(-0.5 * distance, 0.0, 0.0))); Transform3 tf2(Translation3(Vector3(+0.5 * distance, 0.0, 0.0))); S distA; S distB; Vector3 p1A; Vector3 p1B; Vector3 p2A; Vector3 p2B; bool resA; bool resB; const double tol = 1e-6; resA = solver1().shapeDistance(s1, tf1, s2, tf2, &distA, &p1A, &p2A); resB = solver1().shapeDistance(s2, tf2, s1, tf1, &distB, &p1B, &p2B); EXPECT_TRUE(resA); EXPECT_TRUE(resB); EXPECT_NEAR(distA, distB, tol); // distances should be same EXPECT_TRUE(p1A.isApprox(p2B, tol)); // closest points should in reverse order EXPECT_TRUE(p2A.isApprox(p1B, tol)); resA = solver2().shapeDistance(s1, tf1, s2, tf2, &distA, &p1A, &p2A); resB = solver2().shapeDistance(s2, tf2, s1, tf1, &distB, &p1B, &p2B); EXPECT_TRUE(resA); EXPECT_TRUE(resB); EXPECT_NEAR(distA, distB, tol); EXPECT_TRUE(p1A.isApprox(p2B, tol)); EXPECT_TRUE(p2A.isApprox(p1B, tol)); } template void test_reversibleShapeDistance_allshapes() { // This test check whether a shape distance algorithm is called for the // reverse case as well. For example, if FCL has sphere-capsule distance // algorithm, then this algorithm should be called for capsule-sphere case. // Prepare all kinds of primitive shapes (8) -- box, sphere, ellipsoid, capsule, cone, cylinder, plane, halfspace Box box(10, 10, 10); Sphere sphere(5); Ellipsoid ellipsoid(5, 5, 5); Capsule capsule(5, 10); Cone cone(5, 10); Cylinder cylinder(5, 10); Plane plane(Vector3::Zero(), 0.0); Halfspace halfspace(Vector3::Zero(), 0.0); // Use sufficiently long distance so that all the primitive shapes CANNOT intersect S distance = 15.0; // If new shape distance algorithm is added for two distinct primitive // shapes, uncomment associated lines. For example, box-sphere intersection // algorithm is added, then uncomment box-sphere. // testReversibleShapeDistance(box, sphere, distance); // testReversibleShapeDistance(box, ellipsoid, distance); // testReversibleShapeDistance(box, capsule, distance); // testReversibleShapeDistance(box, cone, distance); // testReversibleShapeDistance(box, cylinder, distance); // testReversibleShapeDistance(box, plane, distance); // testReversibleShapeDistance(box, halfspace, distance); // testReversibleShapeDistance(sphere, ellipsoid, distance); testReversibleShapeDistance(sphere, capsule, distance); // testReversibleShapeDistance(sphere, cone, distance); // testReversibleShapeDistance(sphere, cylinder, distance); // testReversibleShapeDistance(sphere, plane, distance); // testReversibleShapeDistance(sphere, halfspace, distance); // testReversibleShapeDistance(ellipsoid, capsule, distance); // testReversibleShapeDistance(ellipsoid, cone, distance); // testReversibleShapeDistance(ellipsoid, cylinder, distance); // testReversibleShapeDistance(ellipsoid, plane, distance); // testReversibleShapeDistance(ellipsoid, halfspace, distance); // testReversibleShapeDistance(capsule, cone, distance); // testReversibleShapeDistance(capsule, cylinder, distance); // testReversibleShapeDistance(capsule, plane, distance); // testReversibleShapeDistance(capsule, halfspace, distance); // testReversibleShapeDistance(cone, cylinder, distance); // testReversibleShapeDistance(cone, plane, distance); // testReversibleShapeDistance(cone, halfspace, distance); // testReversibleShapeDistance(cylinder, plane, distance); // testReversibleShapeDistance(cylinder, halfspace, distance); // testReversibleShapeDistance(plane, halfspace, distance); } GTEST_TEST(FCL_GEOMETRIC_SHAPES, reversibleShapeDistance_allshapes) { // test_reversibleShapeDistance_allshapes(); test_reversibleShapeDistance_allshapes(); } //============================================================================== int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }