Commit 9cbd349b authored by isucan's avatar isucan
Browse files

Merge pull request #10 from martinfelis/master

Added sphere-capsule routines
parents 00829132 95a27ab4
......@@ -195,6 +195,12 @@ struct GJKSolver_libccd
};
/// @brief Fast implementation for sphere-capsule collision
template<>
bool GJKSolver_libccd::shapeIntersect<Sphere, Capsule>(const Sphere& s1, const Transform3f& tf1,
const Capsule& s2, const Transform3f& tf2,
Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
/// @brief Fast implementation for sphere-sphere collision
template<>
bool GJKSolver_libccd::shapeIntersect<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1,
......@@ -296,6 +302,12 @@ template<>
bool GJKSolver_libccd::shapeTriangleIntersect(const Plane& s, const Transform3f& tf1,
const Vec3f& P1, const Vec3f& P2, const Vec3f& P3, const Transform3f& tf2, Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const;
/// @brief Fast implementation for sphere-capsule distance
template<>
bool GJKSolver_libccd::shapeDistance<Sphere, Capsule>(const Sphere& s1, const Transform3f& tf1,
const Capsule& s2, const Transform3f& tf2,
FCL_REAL* dist) const;
/// @brief Fast implementation for sphere-sphere distance
template<>
bool GJKSolver_libccd::shapeDistance<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1,
......
......@@ -45,6 +45,91 @@ namespace fcl
namespace details
{
// Compute the point on a line segment that is the closest point on the
// segment to to another point. The code is inspired by the explanation
// given by Dan Sunday's page:
// http://geomalgorithms.com/a02-_lines.html
static inline void lineSegmentPointClosestToPoint (const Vec3f &p, const Vec3f &s1, const Vec3f &s2, Vec3f &sp) {
Vec3f v = s2 - s1;
Vec3f w = p - s1;
FCL_REAL c1 = w.dot(v);
FCL_REAL c2 = v.dot(v);
if (c1 <= 0) {
sp = s1;
} else if (c2 <= c1) {
sp = s2;
} else {
FCL_REAL b = c1/c2;
Vec3f Pb = s1 + v * b;
sp = Pb;
}
}
bool sphereCapsuleIntersect(const Sphere& s1, const Transform3f& tf1,
const Capsule& s2, const Transform3f& tf2,
Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal_)
{
Transform3f tf2_inv (tf2);
tf2_inv.inverse();
Vec3f pos1 (0., 0., 0.5 * s2.lz);
Vec3f pos2 (0., 0., -0.5 * s2.lz);
Vec3f s_c = tf2_inv.transform(tf1.transform(Vec3f()));
Vec3f segment_point;
lineSegmentPointClosestToPoint (s_c, pos1, pos2, segment_point);
Vec3f diff = s_c - segment_point;
FCL_REAL distance = diff.length() - s1.radius - s2.radius;
if (distance > 0)
return false;
Vec3f normal = diff.normalize() * - FCL_REAL(1);
if (distance < 0 && penetration_depth)
*penetration_depth = -distance;
if (normal_)
*normal_ = tf2.getQuatRotation().transform(normal);
if (contact_points) {
*contact_points = tf2.transform(segment_point + normal * distance);
}
return true;
}
bool sphereCapsuleDistance(const Sphere& s1, const Transform3f& tf1,
const Capsule& s2, const Transform3f& tf2,
FCL_REAL* dist)
{
Transform3f tf2_inv (tf2);
tf2_inv.inverse();
Vec3f pos1 (0., 0., 0.5 * s2.lz);
Vec3f pos2 (0., 0., -0.5 * s2.lz);
Vec3f s_c = tf2_inv.transform(tf1.transform(Vec3f()));
Vec3f segment_point;
lineSegmentPointClosestToPoint (s_c, pos1, pos2, segment_point);
Vec3f diff = s_c - segment_point;
FCL_REAL distance = diff.length() - s1.radius - s2.radius;
if (distance <= 0)
return false;
if (dist)
*dist = distance;
return true;
}
bool sphereSphereIntersect(const Sphere& s1, const Transform3f& tf1,
const Sphere& s2, const Transform3f& tf2,
Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal)
......@@ -2290,6 +2375,13 @@ bool planeIntersect(const Plane& s1, const Transform3f& tf1,
} // details
template<>
bool GJKSolver_libccd::shapeIntersect<Sphere, Capsule>(const Sphere &s1, const Transform3f& tf1,
const Capsule &s2, const Transform3f& tf2,
Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
{
return details::sphereCapsuleIntersect (s1, tf1, s2, tf2, contact_points, penetration_depth, normal);
}
template<>
bool GJKSolver_libccd::shapeIntersect<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1,
......@@ -2464,6 +2556,14 @@ bool GJKSolver_libccd::shapeTriangleIntersect(const Plane& s, const Transform3f&
template<>
bool GJKSolver_libccd::shapeDistance<Sphere, Capsule>(const Sphere& s1, const Transform3f& tf1,
const Capsule& s2, const Transform3f& tf2,
FCL_REAL* dist) const
{
return details::sphereCapsuleDistance(s1, tf1, s2, tf2, dist);
}
template<>
bool GJKSolver_libccd::shapeDistance<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1,
const Sphere& s2, const Transform3f& tf2,
......@@ -2492,7 +2592,13 @@ bool GJKSolver_libccd::shapeTriangleDistance<Sphere>(const Sphere& s, const Tran
template<>
bool GJKSolver_indep::shapeIntersect<Sphere, Capsule>(const Sphere &s1, const Transform3f& tf1,
const Capsule &s2, const Transform3f& tf2,
Vec3f* contact_points, FCL_REAL* penetration_depth, Vec3f* normal) const
{
return details::sphereCapsuleIntersect (s1, tf1, s2, tf2, contact_points, penetration_depth, normal);
}
template<>
bool GJKSolver_indep::shapeIntersect<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1,
......@@ -2665,6 +2771,14 @@ bool GJKSolver_indep::shapeTriangleIntersect(const Plane& s, const Transform3f&
}
template<>
bool GJKSolver_indep::shapeDistance<Sphere, Capsule>(const Sphere& s1, const Transform3f& tf1,
const Capsule& s2, const Transform3f& tf2,
FCL_REAL* dist) const
{
return details::sphereCapsuleDistance(s1, tf1, s2, tf2, dist);
}
template<>
bool GJKSolver_indep::shapeDistance<Sphere, Sphere>(const Sphere& s1, const Transform3f& tf1,
const Sphere& s2, const Transform3f& tf2,
......
......@@ -27,6 +27,8 @@ add_fcl_test(test_fcl_shape_mesh_consistency test_fcl_shape_mesh_consistency.cpp
add_fcl_test(test_fcl_frontlist test_fcl_frontlist.cpp test_fcl_utility.cpp)
add_fcl_test(test_fcl_math test_fcl_math.cpp test_fcl_utility.cpp)
add_fcl_test(test_fcl_sphere_capsule test_fcl_sphere_capsule.cpp)
if (FCL_HAVE_OCTOMAP)
add_fcl_test(test_fcl_octomap test_fcl_octomap.cpp test_fcl_utility.cpp)
endif()
/*
* Software License Agreement (BSD License)
*
* Copyright (c) 2011, Willow Garage, Inc.
* 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 Willow Garage, Inc. 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 Martin Felis <martin.felis@iwr.uni-heidelberg.de> */
#define BOOST_TEST_MODULE "FCL_SPHERE_CAPSULE"
#include <boost/test/unit_test.hpp>
#include "fcl/collision.h"
#include "fcl/shape/geometric_shapes.h"
#include "fcl/narrowphase/narrowphase.h"
using namespace fcl;
BOOST_AUTO_TEST_CASE(Sphere_Capsule_Intersect_test_separated_z)
{
GJKSolver_libccd solver;
Sphere sphere1 (50);
Transform3f sphere1_transform;
sphere1_transform.setTranslation (Vec3f (0., 0., -50));
Capsule capsule (50, 200.);
Transform3f capsule_transform (Vec3f (0., 0., 200));
BOOST_CHECK (!solver.shapeIntersect(sphere1, sphere1_transform, capsule, capsule_transform, NULL, NULL, NULL));
}
BOOST_AUTO_TEST_CASE(Sphere_Capsule_Intersect_test_separated_z_negative)
{
GJKSolver_libccd solver;
Sphere sphere1 (50);
Transform3f sphere1_transform;
sphere1_transform.setTranslation (Vec3f (0., 0., 50));
Capsule capsule (50, 200.);
Transform3f capsule_transform (Vec3f (0., 0., -200));
BOOST_CHECK (!solver.shapeIntersect(sphere1, sphere1_transform, capsule, capsule_transform, NULL, NULL, NULL));
}
BOOST_AUTO_TEST_CASE(Sphere_Capsule_Intersect_test_separated_x)
{
GJKSolver_libccd solver;
Sphere sphere1 (50);
Transform3f sphere1_transform;
sphere1_transform.setTranslation (Vec3f (0., 0., -50));
Capsule capsule (50, 200.);
Transform3f capsule_transform (Vec3f (150., 0., 0.));
BOOST_CHECK (!solver.shapeIntersect(sphere1, sphere1_transform, capsule, capsule_transform, NULL, NULL, NULL));
}
BOOST_AUTO_TEST_CASE(Sphere_Capsule_Intersect_test_separated_capsule_rotated)
{
GJKSolver_libccd solver;
Sphere sphere1 (50);
Transform3f sphere1_transform;
sphere1_transform.setTranslation (Vec3f (0., 0., -50));
Capsule capsule (50, 200.);
Matrix3f rotation;
rotation.setEulerZYX (M_PI * 0.5, 0., 0.);
Transform3f capsule_transform (rotation, Vec3f (150., 0., 0.));
BOOST_CHECK (!solver.shapeIntersect(sphere1, sphere1_transform, capsule, capsule_transform, NULL, NULL, NULL));
}
BOOST_AUTO_TEST_CASE(Sphere_Capsule_Intersect_test_penetration_z)
{
GJKSolver_libccd solver;
Sphere sphere1 (50);
Transform3f sphere1_transform;
sphere1_transform.setTranslation (Vec3f (0., 0., -50));
Capsule capsule (50, 200.);
Transform3f capsule_transform (Vec3f (0., 0., 125));
FCL_REAL penetration = 0.;
Vec3f contact_point;
Vec3f normal;
bool is_intersecting = solver.shapeIntersect(sphere1, sphere1_transform, capsule, capsule_transform, &contact_point, &penetration, &normal);
BOOST_CHECK (is_intersecting);
BOOST_CHECK (penetration == 25.);
BOOST_CHECK (Vec3f (0., 0., 1.).equal(normal));
BOOST_CHECK (Vec3f (0., 0., 0.).equal(contact_point));
}
BOOST_AUTO_TEST_CASE(Sphere_Capsule_Intersect_test_penetration_z_rotated)
{
GJKSolver_libccd solver;
Sphere sphere1 (50);
Transform3f sphere1_transform;
sphere1_transform.setTranslation (Vec3f (0., 0., 0));
Capsule capsule (50, 200.);
Matrix3f rotation;
rotation.setEulerZYX (M_PI * 0.5, 0., 0.);
Transform3f capsule_transform (rotation, Vec3f (0., 50., 75));
FCL_REAL penetration = 0.;
Vec3f contact_point;
Vec3f normal;
bool is_intersecting = solver.shapeIntersect(sphere1, sphere1_transform, capsule, capsule_transform, &contact_point, &penetration, &normal);
BOOST_CHECK (is_intersecting);
BOOST_CHECK_CLOSE (25, penetration, solver.collision_tolerance);
BOOST_CHECK (Vec3f (0., 0., 1.).equal(normal));
BOOST_CHECK (Vec3f (0., 0., 50.).equal(contact_point, solver.collision_tolerance));
}
BOOST_AUTO_TEST_CASE(Sphere_Capsule_Distance_test_collision)
{
GJKSolver_libccd solver;
Sphere sphere1 (50);
Transform3f sphere1_transform;
sphere1_transform.setTranslation (Vec3f (0., 0., -50));
Capsule capsule (50, 200.);
Transform3f capsule_transform (Vec3f (0., 0., 100));
FCL_REAL distance;
BOOST_CHECK (!solver.shapeDistance(sphere1, sphere1_transform, capsule, capsule_transform, &distance));
}
BOOST_AUTO_TEST_CASE(Sphere_Capsule_Distance_test_separated)
{
GJKSolver_libccd solver;
Sphere sphere1 (50);
Transform3f sphere1_transform;
sphere1_transform.setTranslation (Vec3f (0., 0., -50));
Capsule capsule (50, 200.);
Transform3f capsule_transform (Vec3f (0., 0., 175));
FCL_REAL distance = 0.;
bool is_separated = solver.shapeDistance(sphere1, sphere1_transform, capsule, capsule_transform, &distance);
BOOST_CHECK (is_separated);
BOOST_CHECK (distance == 25.);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment