Browse Source

Shapes: added Shape::collision().

Much like Shape::collides() is equivalent to the more low-level
collision detection using operator%, the Shape::collision() returns
collision details similarly to operator/. Currently only Sphere/Sphere
and Sphere/Point collision is done, thus the dispatch is nearly empty.
pull/51/head
Vladimír Vondruš 12 years ago
parent
commit
218b950aed
  1. 5
      src/Magnum/Shapes/AbstractShape.cpp
  2. 7
      src/Magnum/Shapes/AbstractShape.h
  3. 30
      src/Magnum/Shapes/Implementation/CollisionDispatch.cpp
  4. 4
      src/Magnum/Shapes/Implementation/CollisionDispatch.h
  5. 45
      src/Magnum/Shapes/Test/ShapeTest.cpp

5
src/Magnum/Shapes/AbstractShape.cpp

@ -27,6 +27,7 @@
#include <Corrade/Utility/Debug.h> #include <Corrade/Utility/Debug.h>
#include "Magnum/Shapes/Collision.h"
#include "Magnum/Shapes/ShapeGroup.h" #include "Magnum/Shapes/ShapeGroup.h"
#include "Magnum/Shapes/Implementation/CollisionDispatch.h" #include "Magnum/Shapes/Implementation/CollisionDispatch.h"
@ -52,6 +53,10 @@ template<UnsignedInt dimensions> bool AbstractShape<dimensions>::collides(const
return Implementation::collides(abstractTransformedShape(), other.abstractTransformedShape()); return Implementation::collides(abstractTransformedShape(), other.abstractTransformedShape());
} }
template<UnsignedInt dimensions> Collision<dimensions> AbstractShape<dimensions>::collision(const AbstractShape<dimensions>& other) const {
return Implementation::collision(abstractTransformedShape(), other.abstractTransformedShape());
}
template<UnsignedInt dimensions> void AbstractShape<dimensions>::markDirty() { template<UnsignedInt dimensions> void AbstractShape<dimensions>::markDirty() {
if(group()) group()->setDirty(); if(group()) group()->setDirty();
} }

7
src/Magnum/Shapes/AbstractShape.h

@ -102,6 +102,13 @@ template<UnsignedInt dimensions> class MAGNUM_SHAPES_EXPORT AbstractShape: publi
*/ */
bool collides(const AbstractShape<dimensions>& other) const; bool collides(const AbstractShape<dimensions>& other) const;
/**
* @brief Collision with other shape
*
* Default implementation returns empty collision.
*/
Collision<dimensions> collision(const AbstractShape<dimensions>& other) const;
protected: protected:
/** Marks also the group as dirty */ /** Marks also the group as dirty */
void markDirty() override; void markDirty() override;

30
src/Magnum/Shapes/Implementation/CollisionDispatch.cpp

@ -65,6 +65,21 @@ template<> bool collides(const AbstractShape<2>& a, const AbstractShape<2>& b) {
return false; return false;
} }
template<> Collision<2> collision(const AbstractShape<2>& a, const AbstractShape<2>& b) {
if(a.type() < b.type()) return collision(b, a);
switch(UnsignedInt(a.type())*UnsignedInt(b.type())) {
#define _c(aType, aClass, bType, bClass) \
case UnsignedInt(ShapeDimensionTraits<2>::Type::aType)*UnsignedInt(ShapeDimensionTraits<2>::Type::bType): \
return static_cast<const Shape<aClass>&>(a).shape / static_cast<const Shape<bClass>&>(b).shape;
_c(Sphere, Sphere2D, Point, Point2D)
_c(Sphere, Sphere2D, Sphere, Sphere2D)
#undef _c
}
return {};
}
template<> bool collides(const AbstractShape<3>& a, const AbstractShape<3>& b) { template<> bool collides(const AbstractShape<3>& a, const AbstractShape<3>& b) {
if(a.type() < b.type()) return collides(b, a); if(a.type() < b.type()) return collides(b, a);
@ -96,4 +111,19 @@ template<> bool collides(const AbstractShape<3>& a, const AbstractShape<3>& b) {
return false; return false;
} }
template<> Collision<3> collision(const AbstractShape<3>& a, const AbstractShape<3>& b) {
if(a.type() < b.type()) return collision(b, a);
switch(UnsignedInt(a.type())*UnsignedInt(b.type())) {
#define _c(aType, aClass, bType, bClass) \
case UnsignedInt(ShapeDimensionTraits<3>::Type::aType)*UnsignedInt(ShapeDimensionTraits<3>::Type::bType): \
return static_cast<const Shape<aClass>&>(a).shape / static_cast<const Shape<bClass>&>(b).shape;
_c(Sphere, Sphere3D, Point, Point3D)
_c(Sphere, Sphere3D, Sphere, Sphere3D)
#undef _c
}
return {};
}
}}} }}}

4
src/Magnum/Shapes/Implementation/CollisionDispatch.h

@ -26,6 +26,7 @@
*/ */
#include "Magnum/Types.h" #include "Magnum/Types.h"
#include "Magnum/Shapes/Shapes.h"
namespace Magnum { namespace Shapes { namespace Implementation { namespace Magnum { namespace Shapes { namespace Implementation {
@ -40,8 +41,11 @@ multiply the two numbers together and switch() on the result. Because of
multiplying two prime numbers, there is no ambiguity (the result is unique for multiplying two prime numbers, there is no ambiguity (the result is unique for
each combination). each combination).
*/ */
template<UnsignedInt dimensions> bool collides(const AbstractShape<dimensions>& a, const AbstractShape<dimensions>& b); template<UnsignedInt dimensions> bool collides(const AbstractShape<dimensions>& a, const AbstractShape<dimensions>& b);
template<UnsignedInt dimensions> Collision<dimensions> collision(const AbstractShape<dimensions>& a, const AbstractShape<dimensions>& b);
}}} }}}
#endif #endif

45
src/Magnum/Shapes/Test/ShapeTest.cpp

@ -42,6 +42,7 @@ class ShapeTest: public TestSuite::Tester {
void clean(); void clean();
void collides(); void collides();
void collision();
void firstCollision(); void firstCollision();
void shapeGroup(); void shapeGroup();
}; };
@ -54,6 +55,7 @@ typedef SceneGraph::Object<SceneGraph::MatrixTransformation3D> Object3D;
ShapeTest::ShapeTest() { ShapeTest::ShapeTest() {
addTests({&ShapeTest::clean, addTests({&ShapeTest::clean,
&ShapeTest::collides, &ShapeTest::collides,
&ShapeTest::collision,
&ShapeTest::firstCollision, &ShapeTest::firstCollision,
&ShapeTest::shapeGroup}); &ShapeTest::shapeGroup});
} }
@ -137,6 +139,49 @@ void ShapeTest::collides() {
} }
} }
void ShapeTest::collision() {
Scene3D scene;
ShapeGroup3D shapes;
Object3D a(&scene);
Shape<Shapes::Sphere3D> aShape(a, {{1.0f, -2.0f, 3.0f}, 1.5f}, &shapes);
{
/* Collision with point inside the sphere */
Shape<Shapes::Point3D> aShape2(a, {{1.0f, -2.0f, 3.0f}}, &shapes);
shapes.setClean();
const Collision3D collision = aShape.collision(aShape2);
CORRADE_VERIFY(collision);
CORRADE_COMPARE(collision.position(), Vector3(1.0f, -2.0f, 3.0f));
} {
/* No collision with point inside the sphere, but not in the same group */
ShapeGroup3D shapes2;
Shape<Shapes::Point3D> aShape3(a, {{1.0f, -2.0f, 3.0f}}, &shapes2);
shapes2.setClean();
CORRADE_VERIFY(!aShape.collision(aShape3));
} {
CORRADE_EXPECT_FAIL("Should cross-scene collision work or not?");
/* No collision with point inside the sphere, but not in the same scene */
Scene3D scene2;
Object3D c(&scene2);
Shape<Shapes::Point3D> cShape(c, {{1.0f, -2.0f, 3.0f}}, &shapes);
shapes.setClean();
CORRADE_VERIFY(!aShape.collision(cShape));
} {
/* No collision with point outside of the sphere */
Object3D b(&scene);
Shape<Shapes::Point3D> bShape(b, {{3.0f, -2.0f, 3.0f}}, &shapes);
shapes.setClean();
CORRADE_VERIFY(!aShape.collision(bShape));
/* Move point inside the sphere -- collision */
b.translate(Vector3::xAxis(-1.0f));
shapes.setClean();
const Collision3D collision = aShape.collision(bShape);
CORRADE_VERIFY(collision);
CORRADE_COMPARE(collision.position(), Vector3(2.0f, -2.0f, 3.0f));
}
}
void ShapeTest::firstCollision() { void ShapeTest::firstCollision() {
Scene3D scene; Scene3D scene;
ShapeGroup3D shapes; ShapeGroup3D shapes;

Loading…
Cancel
Save