Browse Source

Shapes: (detailed) collision of two spheres.

pull/23/head
Vladimír Vondruš 13 years ago
parent
commit
103875ea9d
  1. 24
      src/Shapes/Sphere.cpp
  2. 3
      src/Shapes/Sphere.h
  3. 27
      src/Shapes/Test/SphereTest.cpp

24
src/Shapes/Sphere.cpp

@ -74,7 +74,29 @@ template<UnsignedInt dimensions> bool Sphere<dimensions>::operator%(const LineSe
}
template<UnsignedInt dimensions> bool Sphere<dimensions>::operator%(const Sphere<dimensions>& other) const {
return (other._position-_position).dot() < Math::pow<2>(_radius+other._radius);
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;
const Float dot = separating.dot();
/* No collision occured */
if(dot > Math::pow<2>(minDistance)) return {};
/* Actual distance */
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<dimensions, Float>::VectorType separatingNormal =
Math::TypeTraits<Float>::equals(dot, 0.0f) ?
DimensionTraits<dimensions, Float>::VectorType::yAxis() :
separating/distance;
/* Contact position is on the surface of `other`, minDistace > distance */
return Collision<dimensions>(other._position + separatingNormal*other._radius, separatingNormal, minDistance - distance);
}
#ifndef DOXYGEN_GENERATING_OUTPUT

3
src/Shapes/Sphere.h

@ -95,6 +95,9 @@ template<UnsignedInt dimensions> class MAGNUM_SHAPES_EXPORT Sphere {
/** @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:
typename DimensionTraits<dimensions, Float>::VectorType _position;
Float _radius;

27
src/Shapes/Test/SphereTest.cpp

@ -105,12 +105,29 @@ void SphereTest::collisionLineSegment() {
}
void SphereTest::collisionSphere() {
Shapes::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 2.0f);
Shapes::Sphere3D sphere1({1.0f, 3.0f, 5.0f}, 1.0f);
Shapes::Sphere3D sphere2({1.0f, 3.0f, 0.0f}, 1.0f);
const Shapes::Sphere3D sphere({1.0f, 2.0f, 3.0f}, 2.0f);
/* Collision */
const Shapes::Sphere3D sphere1({3.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);
VERIFY_COLLIDES(sphere, sphere1);
VERIFY_NOT_COLLIDES(sphere, sphere2);
/* Collision, flipped */
CORRADE_COMPARE(collision.separationNormal(), -(sphere1/sphere).separationNormal());
/* Collision with ambiguous separation vector */
const Shapes::Sphere3D sphere2(sphere.position(), 0.5f);
const Shapes::Collision3D collision2 = sphere/sphere2;
CORRADE_COMPARE(collision2.position(), sphere2.position() + Vector3::yAxis(sphere2.radius()));
CORRADE_COMPARE(collision2.separationNormal(), Vector3::yAxis());
CORRADE_COMPARE(collision2.separationDistance(), 2.5f);
/* No collision */
const Shapes::Sphere3D sphere3({-2.5f, 2.0f, 3.0f}, 1.0f);
CORRADE_VERIFY(!(sphere%sphere3) && !(sphere/sphere3));
}
}}}

Loading…
Cancel
Save