From cf11f7e8fbbe2c03a082c8b16dfddf761e050114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 23 Sep 2013 01:23:19 +0200 Subject: [PATCH] Shapes: (detailed) collision of sphere vs. point. --- src/Shapes/Sphere.cpp | 23 ++++++++++++++++++++++- src/Shapes/Sphere.h | 7 +++++++ src/Shapes/Test/SphereTest.cpp | 29 +++++++++++++++++++++++------ 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/Shapes/Sphere.cpp b/src/Shapes/Sphere.cpp index 295a9ab0a..f07bcb247 100644 --- a/src/Shapes/Sphere.cpp +++ b/src/Shapes/Sphere.cpp @@ -41,7 +41,28 @@ template Sphere Sphere::transfor } template bool Sphere::operator%(const Point& other) const { - return (other.position()-_position).dot() < Math::pow<2>(_radius); + return (_position - other.position()).dot() < Math::pow<2>(_radius); +} + +template Collision Sphere::operator/(const Point& other) const { + const typename DimensionTraits::VectorType separating = _position - other.position(); + const Float dot = separating.dot(); + + /* No collision occured */ + if(dot > Math::pow<2>(_radius)) return {}; + + /* Actual distance from the center */ + const Float distance = Math::sqrt(dot); + + /* Separating normal. If can't decide on direction, just move up. */ + /** @todo How to handle this in a configurable way? */ + const typename DimensionTraits::VectorType separatingNormal = + Math::TypeTraits::equals(dot, 0.0f) ? + DimensionTraits::VectorType::yAxis() : + separating/distance; + + /* Collision position is on the point */ + return Collision(other.position(), separatingNormal, _radius - distance); } template bool Sphere::operator%(const Line& other) const { diff --git a/src/Shapes/Sphere.h b/src/Shapes/Sphere.h index e402f9c9e..6580efa8e 100644 --- a/src/Shapes/Sphere.h +++ b/src/Shapes/Sphere.h @@ -30,6 +30,7 @@ #include "Math/Vector3.h" #include "DimensionTraits.h" +#include "Shapes/Collision.h" #include "Shapes/Shapes.h" #include "Shapes/magnumShapesVisibility.h" @@ -82,6 +83,9 @@ template class MAGNUM_SHAPES_EXPORT Sphere { /** @brief %Collision occurence with point */ bool operator%(const Point& other) const; + /** @brief %Collision with point */ + Collision operator/(const Point& other) const; + /** @brief %Collision occurence with line */ bool operator%(const Line& other) const; @@ -105,6 +109,9 @@ typedef Sphere<3> Sphere3D; /** @collisionoccurenceoperator{Point,Sphere} */ template inline bool operator%(const Point& a, const Sphere& b) { return b % a; } +/** @collisionoperator{Point,Sphere} */ +template inline Collision operator/(const Point& a, const Sphere& b) { return (b/a).flipped(); } + /** @collisionoccurenceoperator{Line,Sphere} */ template inline bool operator%(const Line& a, const Sphere& b) { return b % a; } diff --git a/src/Shapes/Test/SphereTest.cpp b/src/Shapes/Test/SphereTest.cpp index b66e86e50..877176130 100644 --- a/src/Shapes/Test/SphereTest.cpp +++ b/src/Shapes/Test/SphereTest.cpp @@ -61,12 +61,29 @@ void SphereTest::transformed() { } void SphereTest::collisionPoint() { - Shapes::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 2.0f); - Shapes::Point3D point({1.0f, 3.0f, 3.0f}); - Shapes::Point3D point2({1.0f, 3.0f, 1.0f}); - - VERIFY_COLLIDES(sphere, point); - VERIFY_NOT_COLLIDES(sphere, point2); + const Shapes::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 2.0f); + + /* Collision */ + const Shapes::Point3D point({2.5f, 2.0f, 3.0f}); + const Shapes::Collision3D collision = sphere/point; + CORRADE_VERIFY(sphere%point && point%sphere); + CORRADE_COMPARE(collision.position(), point.position()); + CORRADE_COMPARE(collision.separationNormal(), -Vector3::xAxis()); + CORRADE_COMPARE(collision.separationDistance(), 0.5f); + + /* Collision, flipped */ + CORRADE_COMPARE(collision.separationNormal(), -(point/sphere).separationNormal()); + + /* Collision with ambiguous separation vector */ + const Shapes::Point3D point2(sphere.position()); + const Shapes::Collision3D collision2 = sphere/point2; + CORRADE_COMPARE(collision2.position(), point2.position()); + CORRADE_COMPARE(collision2.separationNormal(), Vector3::yAxis()); + CORRADE_COMPARE(collision2.separationDistance(), 2.0f); + + /* No collision */ + const Shapes::Point3D point3({-1.5f, 2.0f, 3.0f}); + CORRADE_VERIFY(!(sphere%point3) && !(sphere/point3)); } void SphereTest::collisionLine() {