From da114ef853e732e6ef1e31a4a14cdbe73a59160a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 26 Sep 2013 16:42:23 +0200 Subject: [PATCH] Shapes: collision of InvertedSphere and Sphere. --- .../Implementation/CollisionDispatch.cpp | 2 ++ src/Shapes/Sphere.cpp | 24 +++++++++++++++++++ src/Shapes/Sphere.h | 12 ++++++++++ src/Shapes/Test/SphereTest.cpp | 23 +++++++++++++++++- 4 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/Shapes/Implementation/CollisionDispatch.cpp b/src/Shapes/Implementation/CollisionDispatch.cpp index 8bb0485fc..81eae99f2 100644 --- a/src/Shapes/Implementation/CollisionDispatch.cpp +++ b/src/Shapes/Implementation/CollisionDispatch.cpp @@ -49,6 +49,7 @@ template<> bool collides(const AbstractShape<2>& a, const AbstractShape<2>& b) { _c(Sphere, Sphere2D, Sphere, Sphere2D) _c(InvertedSphere, InvertedSphere2D, Point, Point2D) + _c(InvertedSphere, InvertedSphere2D, Sphere, Sphere2D) _c(Cylinder, Cylinder2D, Point, Point2D) _c(Cylinder, Cylinder2D, Sphere, Sphere2D) @@ -76,6 +77,7 @@ template<> bool collides(const AbstractShape<3>& a, const AbstractShape<3>& b) { _c(Sphere, Sphere3D, Sphere, Sphere3D) _c(InvertedSphere, InvertedSphere3D, Point, Point3D) + _c(InvertedSphere, InvertedSphere3D, Sphere, Sphere3D) _c(Cylinder, Cylinder3D, Point, Point3D) _c(Cylinder, Cylinder3D, Sphere, Sphere3D) diff --git a/src/Shapes/Sphere.cpp b/src/Shapes/Sphere.cpp index 70c27347d..8b86fa3ad 100644 --- a/src/Shapes/Sphere.cpp +++ b/src/Shapes/Sphere.cpp @@ -98,6 +98,10 @@ template bool Sphere::operator%(const Sphere return (_position - other._position).dot() < Math::pow<2>(_radius + other._radius); } +template bool InvertedSphere::operator%(const Sphere& other) const { + return (position() - other.position()).dot() > Math::pow<2>(radius() - other.radius()); +} + template Collision Sphere::operator/(const Sphere& other) const { const Float minDistance = _radius + other._radius; const typename DimensionTraits::VectorType separating = _position - other._position; @@ -120,6 +124,26 @@ template Collision Sphere::opera return Collision(other._position + separatingNormal*other._radius, separatingNormal, minDistance - distance); } +template Collision InvertedSphere::operator/(const Sphere& other) const { + const Float maxDistance = radius() - other.radius(); + /** @todo How to handle inseparable shapes or shapes which can't be separated by movement only (i.e. two half-spaces)? */ + CORRADE_INTERNAL_ASSERT(maxDistance > 0.0f); + const typename DimensionTraits::VectorType separating = other.position() - position(); + const Float dot = separating.dot(); + + /* No collision occured */ + if(dot < Math::pow<2>(maxDistance)) return {}; + + /* Actual distance */ + const Float distance = Math::sqrt(dot); + + /* Separating normal */ + const typename DimensionTraits::VectorType separatingNormal = separating/distance; + + /* Contact position is on the surface of `other`, distance > maxDistance */ + return Collision(other.position() + separatingNormal*other.radius(), separatingNormal, distance - maxDistance); +} + #ifndef DOXYGEN_GENERATING_OUTPUT template class MAGNUM_SHAPES_EXPORT Sphere<2>; template class MAGNUM_SHAPES_EXPORT Sphere<3>; diff --git a/src/Shapes/Sphere.h b/src/Shapes/Sphere.h index 6f85fe2fd..64ec6e2c6 100644 --- a/src/Shapes/Sphere.h +++ b/src/Shapes/Sphere.h @@ -152,6 +152,12 @@ template class MAGNUM_SHAPES_EXPORT InvertedSphere: /** @brief %Collision with point */ Collision operator/(const Point& other) const; + /** @brief %Collision occurence with sphere */ + bool operator%(const Sphere& other) const; + + /** @brief %Collision with sphere */ + Collision operator/(const Sphere& other) const; + private: constexpr /*implicit*/ InvertedSphere(const Sphere& other): Sphere(other) {} }; @@ -180,6 +186,12 @@ template inline bool operator%(const Line& a /** @collisionoccurenceoperator{LineSegment,Sphere} */ template inline bool operator%(const LineSegment& a, const Sphere& b) { return b % a; } +/** @collisionoccurenceoperator{Sphere,InvertedSphere} */ +template inline bool operator%(const Sphere& a, const InvertedSphere& b) { return b % a; } + +/** @collisionoperator{Sphere,InvertedSphere} */ +template inline Collision operator/(const Sphere& a, const InvertedSphere& b) { return (b/a).flipped(); } + }} #endif diff --git a/src/Shapes/Test/SphereTest.cpp b/src/Shapes/Test/SphereTest.cpp index b2d923d23..5a32c4721 100644 --- a/src/Shapes/Test/SphereTest.cpp +++ b/src/Shapes/Test/SphereTest.cpp @@ -43,6 +43,7 @@ class SphereTest: public TestSuite::Tester { void collisionLine(); void collisionLineSegment(); void collisionSphere(); + void collisionSphereInverted(); }; SphereTest::SphereTest() { @@ -51,7 +52,8 @@ SphereTest::SphereTest() { &SphereTest::collisionPointInverted, &SphereTest::collisionLine, &SphereTest::collisionLineSegment, - &SphereTest::collisionSphere}); + &SphereTest::collisionSphere, + &SphereTest::collisionSphereInverted}); } void SphereTest::transformed() { @@ -151,6 +153,25 @@ void SphereTest::collisionSphere() { CORRADE_VERIFY(!(sphere%sphere3) && !(sphere/sphere3)); } +void SphereTest::collisionSphereInverted() { + const Shapes::InvertedSphere3D sphere({1.0f, 2.0f, 3.0f}, 2.0f); + + /* Collision */ + const Shapes::Sphere3D sphere1({-0.5f, 2.0f, 3.0f}, 1.0f); + const Shapes::Collision3D collision = sphere/sphere1; + CORRADE_VERIFY(sphere%sphere1 && sphere1%sphere); + CORRADE_COMPARE(collision.position(), sphere1.position() - Vector3::xAxis(sphere1.radius())); + CORRADE_COMPARE(collision.separationNormal(), -Vector3::xAxis()); + CORRADE_COMPARE(collision.separationDistance(), 0.5f); + + /* Collision, flipped */ + CORRADE_COMPARE(collision.separationNormal(), -(sphere1/sphere).separationNormal()); + + /* No collision */ + const Shapes::Sphere3D sphere3({1.5f, 2.0f, 3.0f}, 1.0f); + CORRADE_VERIFY(!(sphere%sphere3) && !(sphere/sphere3)); +} + }}} CORRADE_TEST_MAIN(Magnum::Shapes::Test::SphereTest)