Browse Source

Shapes: collision of InvertedSphere and Sphere.

pull/23/head
Vladimír Vondruš 13 years ago
parent
commit
da114ef853
  1. 2
      src/Shapes/Implementation/CollisionDispatch.cpp
  2. 24
      src/Shapes/Sphere.cpp
  3. 12
      src/Shapes/Sphere.h
  4. 23
      src/Shapes/Test/SphereTest.cpp

2
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)

24
src/Shapes/Sphere.cpp

@ -98,6 +98,10 @@ template<UnsignedInt dimensions> bool Sphere<dimensions>::operator%(const Sphere
return (_position - other._position).dot() < Math::pow<2>(_radius + other._radius);
}
template<UnsignedInt dimensions> bool InvertedSphere<dimensions>::operator%(const Sphere<dimensions>& other) const {
return (position() - other.position()).dot() > Math::pow<2>(radius() - other.radius());
}
template<UnsignedInt dimensions> Collision<dimensions> Sphere<dimensions>::operator/(const Sphere<dimensions>& other) const {
const Float minDistance = _radius + other._radius;
const typename DimensionTraits<dimensions, Float>::VectorType separating = _position - other._position;
@ -120,6 +124,26 @@ template<UnsignedInt dimensions> Collision<dimensions> Sphere<dimensions>::opera
return Collision<dimensions>(other._position + separatingNormal*other._radius, separatingNormal, minDistance - distance);
}
template<UnsignedInt dimensions> Collision<dimensions> InvertedSphere<dimensions>::operator/(const Sphere<dimensions>& 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<dimensions, Float>::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<dimensions, Float>::VectorType separatingNormal = separating/distance;
/* Contact position is on the surface of `other`, distance > maxDistance */
return Collision<dimensions>(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>;

12
src/Shapes/Sphere.h

@ -152,6 +152,12 @@ template<UnsignedInt dimensions> class MAGNUM_SHAPES_EXPORT InvertedSphere:
/** @brief %Collision with point */
Collision<dimensions> operator/(const Point<dimensions>& other) const;
/** @brief %Collision occurence with sphere */
bool operator%(const Sphere<dimensions>& other) const;
/** @brief %Collision with sphere */
Collision<dimensions> operator/(const Sphere<dimensions>& other) const;
private:
constexpr /*implicit*/ InvertedSphere(const Sphere<dimensions>& other): Sphere<dimensions>(other) {}
};
@ -180,6 +186,12 @@ template<UnsignedInt dimensions> inline bool operator%(const Line<dimensions>& a
/** @collisionoccurenceoperator{LineSegment,Sphere} */
template<UnsignedInt dimensions> inline bool operator%(const LineSegment<dimensions>& a, const Sphere<dimensions>& b) { return b % a; }
/** @collisionoccurenceoperator{Sphere,InvertedSphere} */
template<UnsignedInt dimensions> inline bool operator%(const Sphere<dimensions>& a, const InvertedSphere<dimensions>& b) { return b % a; }
/** @collisionoperator{Sphere,InvertedSphere} */
template<UnsignedInt dimensions> inline Collision<dimensions> operator/(const Sphere<dimensions>& a, const InvertedSphere<dimensions>& b) { return (b/a).flipped(); }
}}
#endif

23
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)

Loading…
Cancel
Save