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 "Magnum/Shapes/Collision.h"
#include "Magnum/Shapes/ShapeGroup.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());
}
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() {
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;
/**
* @brief Collision with other shape
*
* Default implementation returns empty collision.
*/
Collision<dimensions> collision(const AbstractShape<dimensions>& other) const;
protected:
/** Marks also the group as dirty */
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;
}
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) {
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;
}
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/Shapes/Shapes.h"
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
each combination).
*/
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

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

@ -42,6 +42,7 @@ class ShapeTest: public TestSuite::Tester {
void clean();
void collides();
void collision();
void firstCollision();
void shapeGroup();
};
@ -54,6 +55,7 @@ typedef SceneGraph::Object<SceneGraph::MatrixTransformation3D> Object3D;
ShapeTest::ShapeTest() {
addTests({&ShapeTest::clean,
&ShapeTest::collides,
&ShapeTest::collision,
&ShapeTest::firstCollision,
&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() {
Scene3D scene;
ShapeGroup3D shapes;

Loading…
Cancel
Save