initial commit
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
# - Try to find UnitTest++
|
||||
#
|
||||
#
|
||||
|
||||
SET (UNITTEST++_FOUND FALSE)
|
||||
|
||||
FIND_PATH (UNITTEST++_INCLUDE_DIR UnitTest++.h /usr/include/unittest++ /usr/local/include/unittest++ $ENV{UNITTESTXX_PATH}/src $ENV{UNITTESTXX_INCLUDE_PATH})
|
||||
|
||||
FIND_LIBRARY (UNITTEST++_LIBRARY NAMES UnitTest++ PATHS /usr/lib /usr/local/lib $ENV{UNITTESTXX_PATH} ENV{UNITTESTXX_LIBRARY_PATH})
|
||||
|
||||
IF (UNITTEST++_INCLUDE_DIR AND UNITTEST++_LIBRARY)
|
||||
SET (UNITTEST++_FOUND TRUE)
|
||||
ENDIF (UNITTEST++_INCLUDE_DIR AND UNITTEST++_LIBRARY)
|
||||
|
||||
IF (UNITTEST++_FOUND)
|
||||
IF (NOT UnitTest++_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Found UnitTest++: ${UNITTEST++_LIBRARY}")
|
||||
ENDIF (NOT UnitTest++_FIND_QUIETLY)
|
||||
ELSE (UNITTEST++_FOUND)
|
||||
IF (UnitTest++_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Could not find UnitTest++")
|
||||
ENDIF (UnitTest++_FIND_REQUIRED)
|
||||
ENDIF (UNITTEST++_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED (
|
||||
UNITTEST++_INCLUDE_DIR
|
||||
UNITTEST++_LIBRARY
|
||||
)
|
||||
@@ -0,0 +1,21 @@
|
||||
PROJECT (COLL2D)
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
|
||||
|
||||
# Needed for UnitTest++
|
||||
LIST( APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake )
|
||||
|
||||
SET ( COLL2D_SRCS
|
||||
src/coll2d.cc
|
||||
)
|
||||
|
||||
INCLUDE_DIRECTORIES ( include ../mathlib/ )
|
||||
|
||||
SET_TARGET_PROPERTIES ( ${PROJECT_EXECUTABLES} PROPERTIES
|
||||
LINKER_LANGUAGE CXX
|
||||
)
|
||||
|
||||
SUBDIRS (tests)
|
||||
|
||||
ADD_LIBRARY ( coll2d ${COLL2D_SRCS} )
|
||||
|
||||
@@ -0,0 +1,346 @@
|
||||
#ifndef _COLL2D_H
|
||||
#define _COLL2D_H
|
||||
|
||||
/** \brief Coll2d - A 2d collision detection library
|
||||
* \author Martin Felis <martin@silef.de>
|
||||
*
|
||||
* This library provides functions to detect collisions between polygons and
|
||||
* spheres.
|
||||
*
|
||||
* Notes:
|
||||
* - vertices of polygons are described in local coordinates
|
||||
* - return values of check_collision are in global coordinates
|
||||
* - all Shapes get copied to a temporary instance which will then get
|
||||
* transferred into global coordinates
|
||||
* - Polygons are assumed to be convex and the vertices are stored
|
||||
* counter clockwise.
|
||||
* - The transformation of the global position and velocities towards
|
||||
* relative position and velocities happens in the
|
||||
* int check_collision_<type>_<type> functions!
|
||||
*/
|
||||
|
||||
#include <mathlib.h>
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
#include <coll2d_errors.h>
|
||||
|
||||
namespace coll2d {
|
||||
|
||||
/** \brief Contains the information of a collision
|
||||
*
|
||||
* \param normal The normal of the reference plane
|
||||
* \param point The actual point where the collision happens in global
|
||||
* cooldinates
|
||||
* \param time If both objects move for this amount of time the contact
|
||||
* will occur.
|
||||
* \param reference_shape
|
||||
* If 0, the first shape passed to he check_collision function
|
||||
* is the reference shape, otherwise the second.
|
||||
*/
|
||||
struct CollisionInfo {
|
||||
vector3d normal;
|
||||
vector3d point;
|
||||
float time;
|
||||
int reference_shape;
|
||||
|
||||
CollisionInfo () : normal (0., 0., 0.), point (0., 0., 0.), time (-1.), reference_shape (-1) {
|
||||
}
|
||||
|
||||
CollisionInfo& operator= (const CollisionInfo& info) {
|
||||
if (this != &info) {
|
||||
normal = info.normal;
|
||||
point = info.point;
|
||||
time = info.time;
|
||||
reference_shape = info.reference_shape;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void doPrint (const char* msg) {
|
||||
std::cout << msg;
|
||||
std::cout << "Time = " << time << std::endl;
|
||||
normal.print ("Normal = ");
|
||||
point.print ( "Point = ");
|
||||
std::cout << "Reference = " << reference_shape << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
/** \brief Base class for all shapes
|
||||
*
|
||||
*/
|
||||
class Shape {
|
||||
protected:
|
||||
vector3d mPosition;
|
||||
vector3d mVelocity;
|
||||
float mAngle;
|
||||
float mAngleVelocity;
|
||||
|
||||
virtual void dummy() {
|
||||
}
|
||||
public:
|
||||
Shape():
|
||||
mPosition (0., 0., 0.),
|
||||
mVelocity (0., 0., 0.),
|
||||
mAngle (0.),
|
||||
mAngleVelocity (0.) {
|
||||
}
|
||||
Shape (const Shape &shape):
|
||||
mPosition (shape.mPosition),
|
||||
mVelocity (shape.mVelocity),
|
||||
mAngle (shape.mAngle),
|
||||
mAngleVelocity (shape.mAngleVelocity)
|
||||
{ }
|
||||
|
||||
virtual ~Shape () {};
|
||||
|
||||
/** \brief Creates and returns a copy of itself */
|
||||
virtual Shape* getCopy () = 0;
|
||||
|
||||
void setPosition(vector3d position) {
|
||||
mPosition = position;
|
||||
}
|
||||
vector3d getPosition() {
|
||||
return mPosition;
|
||||
}
|
||||
void setVelocity(vector3d velocity) {
|
||||
mVelocity = velocity;
|
||||
}
|
||||
vector3d getVelocity() {
|
||||
return mVelocity;
|
||||
}
|
||||
|
||||
void setAngle (const float &angle) {
|
||||
mAngle = angle;
|
||||
}
|
||||
float getAngle () {
|
||||
return mAngle;
|
||||
}
|
||||
void setAngleVelocity (float angle_velocity) {
|
||||
mAngleVelocity = angle_velocity;
|
||||
}
|
||||
float getAngleVelocity () {
|
||||
return mAngleVelocity;
|
||||
}
|
||||
|
||||
virtual void doPrintType() {
|
||||
std::cout << "Shape" << std::endl;
|
||||
}
|
||||
virtual void doPrint (const char* name) {
|
||||
std::cout << name << "<unknown shape>" << std::endl;
|
||||
}
|
||||
friend int check_collision_rel(Shape *shape_a, Shape *shape_b,
|
||||
vector3d *velocity_b, CollisionInfo* info);
|
||||
};
|
||||
|
||||
class Polygon: public Shape {
|
||||
private:
|
||||
unsigned int mVerticeCount;
|
||||
vector3d *mVertices;
|
||||
bool mFreeVertices;
|
||||
public:
|
||||
Polygon() {
|
||||
mVerticeCount = 0;
|
||||
mVertices = NULL;
|
||||
mFreeVertices = false;
|
||||
}
|
||||
Polygon(unsigned int n) {
|
||||
mVerticeCount = n;
|
||||
mVertices = new vector3d[n];
|
||||
mFreeVertices = true;
|
||||
}
|
||||
Polygon(unsigned int n, vector3d *vertices) {
|
||||
mVerticeCount = n;
|
||||
mFreeVertices = false;
|
||||
|
||||
if (vertices == NULL && n > 0) {
|
||||
mVertices = new vector3d [n];
|
||||
mFreeVertices = true;
|
||||
}
|
||||
|
||||
mVertices = vertices;
|
||||
}
|
||||
Polygon (const Polygon &polygon) : Shape (polygon) {
|
||||
mVerticeCount = polygon.mVerticeCount;
|
||||
mFreeVertices = true;
|
||||
|
||||
mVertices = new vector3d[mVerticeCount];
|
||||
memcpy (mVertices, polygon.mVertices, sizeof (vector3d) * mVerticeCount);
|
||||
}
|
||||
virtual ~Polygon () {
|
||||
if (mFreeVertices == true && mVertices)
|
||||
delete[] mVertices;
|
||||
}
|
||||
|
||||
virtual Polygon* getCopy () {
|
||||
Polygon *copy = new Polygon (*this);
|
||||
|
||||
assert (copy);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
virtual void doPrintType() {
|
||||
std::cout << "Polygon" << std::endl;
|
||||
}
|
||||
|
||||
virtual void doPrint (const char* name) {
|
||||
std::cout << name << " (Polygon)" << std::endl;
|
||||
|
||||
std::cout << "mVerticeCount = " << mVerticeCount << std::endl;
|
||||
unsigned int i;
|
||||
for (i = 0; i < mVerticeCount; i ++) {
|
||||
std::cout << i << " = " << mVertices[i][0] << ", " <<
|
||||
mVertices[i][1] << ", " <<
|
||||
mVertices[i][2] << std::endl;
|
||||
}
|
||||
std::cout << "mPosition = " << mPosition[0] <<", " <<
|
||||
mPosition[1] << ", " <<
|
||||
mPosition[2] << std::endl;
|
||||
|
||||
std::cout << "mVelocity = " << mVelocity[0] <<", " <<
|
||||
mVelocity[1] << ", " <<
|
||||
mVelocity[2] << std::endl;
|
||||
|
||||
std::cout << "mAngle = " << mAngle << std::endl;
|
||||
std::cout << "mAngleVelocity = " << mAngleVelocity << std::endl;
|
||||
}
|
||||
|
||||
unsigned int getVerticeCount () {
|
||||
return mVerticeCount;
|
||||
}
|
||||
|
||||
vector3d& getVertice (unsigned int i) {
|
||||
assert (i >= 0 && i < mVerticeCount);
|
||||
return mVertices [i];
|
||||
}
|
||||
|
||||
void setVertice (unsigned int i, const vector3d &vertice) {
|
||||
assert (i >= 0 && i < mVerticeCount);
|
||||
mVertices[i] = vertice;
|
||||
}
|
||||
|
||||
friend int check_collision_polygon_sphere(Shape *polygon_a,
|
||||
Shape *sphere_b, CollisionInfo* info);
|
||||
};
|
||||
|
||||
class Sphere: public Shape {
|
||||
private:
|
||||
float mRadius;
|
||||
public:
|
||||
Sphere (float radius) {
|
||||
mRadius = radius;
|
||||
Shape::setPosition (vector3d (0., 0., 0.));
|
||||
}
|
||||
|
||||
Sphere(float radius, const vector3d &position) {
|
||||
mRadius = radius;
|
||||
Shape::setPosition(position);
|
||||
}
|
||||
|
||||
Sphere (const Sphere &sphere):
|
||||
Shape (sphere),
|
||||
mRadius (sphere.mRadius) { }
|
||||
|
||||
virtual Sphere* getCopy() {
|
||||
Sphere* copy = new Sphere (*this);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
virtual void doPrintType() {
|
||||
std::cout << "Sphere" << std::endl;
|
||||
}
|
||||
|
||||
virtual void doPrint (const char* name) {
|
||||
std::cout << name << " (Sphere)" << std::endl;
|
||||
|
||||
std::cout << "mRadius = " << mRadius << std::endl;
|
||||
std::cout << "mPosition = " << mPosition[0] <<", " <<
|
||||
mPosition[1] << ", " <<
|
||||
mPosition[2] << std::endl;
|
||||
|
||||
std::cout << "mVelocity = " << mVelocity[0] <<", " <<
|
||||
mVelocity[1] << ", " <<
|
||||
mVelocity[2] << std::endl;
|
||||
|
||||
std::cout << "mAngle = " << mAngle << std::endl;
|
||||
std::cout << "mAngleVelocity = " << mAngleVelocity << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void setRadius (float radius) {
|
||||
mRadius = radius;
|
||||
}
|
||||
|
||||
float getRadius () {
|
||||
return mRadius;
|
||||
}
|
||||
|
||||
friend int check_collision_polygon_sphere(Shape *polygon_a,
|
||||
Shape *sphere_b, CollisionInfo* info);
|
||||
};
|
||||
|
||||
/** \brief The higher level function to call for collision detection
|
||||
*
|
||||
* \param stepsize the timestep within we want to check for the collision
|
||||
* \param shape_a first shape
|
||||
* \param shape_b second shape
|
||||
* \param info information about the collision will be to info
|
||||
*
|
||||
* \returns 0 - no collision, negative on error, positive on collision
|
||||
*/
|
||||
int check_collision(float timestep, Shape *shape_a, Shape *shape_b, CollisionInfo* info);
|
||||
|
||||
/** \brief The higher level function to call for collision detection
|
||||
*
|
||||
* \param shape_a first shape
|
||||
* \param shape_b second shape
|
||||
* \param velocity_b relative velocity of b to a
|
||||
* \param info information about the collision will be to info
|
||||
*
|
||||
* \returns 0 - no collision, negative on error, positive on collision
|
||||
*/
|
||||
int check_collision_rel(float timestep, Shape *shape_a, Shape *shape_b, vector3d *velocity_b,
|
||||
CollisionInfo* info);
|
||||
|
||||
/** \brief Callback signature for the check functions */
|
||||
typedef int (*check_cb)(float timestep, Shape *shape_a, Shape *shape_b, CollisionInfo* info);
|
||||
|
||||
/** \brief Returns the check functions which performs the checks depending
|
||||
* on their types. */
|
||||
check_cb get_check(Shape *shape_a, Shape *shape_b);
|
||||
|
||||
/** \brief Performs a check between a polygon and a sphere
|
||||
*/
|
||||
int check_collision_polygon_sphere(float timestep, Shape *shape_a, Shape *shape_b,
|
||||
CollisionInfo* info);
|
||||
|
||||
/** \brief Performs a check between a sphere and a sphere
|
||||
*/
|
||||
int check_collision_sphere_sphere(float timestep, Shape *shape_a, Shape *shape_b,
|
||||
CollisionInfo* info);
|
||||
|
||||
|
||||
/** \brief Calculates the time it takes for a point to touch a plane
|
||||
*
|
||||
* \param normal normal vector of the plane
|
||||
* \param plane_point point on the vector
|
||||
* \param point point that is moving
|
||||
* \param velocity velocity of the point
|
||||
*
|
||||
* \returns -1 if point is moving away from the plane (or is below and
|
||||
* moves even further below
|
||||
* >= 0 if point is moving along the plane or towards the plane
|
||||
*
|
||||
* This function depends on the scale of velocity. It is assumed
|
||||
* that velocity represents the displacement in one frame. In this
|
||||
* case a return value > 1 means there will not be a contact
|
||||
* within this frame.
|
||||
*/
|
||||
float calculate_contact_plane_point(vector3d &normal, vector3d &plane_point, vector3d &point, vector3d &velocity);
|
||||
|
||||
}
|
||||
|
||||
#endif /* _COLL2D_H */
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef _COLL2D_ERRORS
|
||||
#define _COLL2D_ERRORS
|
||||
|
||||
#define CHECK_ERROR_UNKNOWN -9999
|
||||
#define CHECK_ERROR_NOT_IMPLEMENTED -1
|
||||
#define CHECK_ERROR_INVALID_TYPES -2
|
||||
#define CHECK_ERROR_OVERLAP -3
|
||||
|
||||
#endif /* _COLL2D_ERRORS */
|
||||
@@ -0,0 +1,572 @@
|
||||
#include <cstring>
|
||||
#include<coll2d.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace coll2d {
|
||||
|
||||
int check_collision (float timestep, Shape *shape_a, Shape *shape_b, CollisionInfo *info) {
|
||||
check_cb check = NULL;
|
||||
|
||||
check = get_check (shape_a, shape_b);
|
||||
|
||||
if ( check == NULL ) {
|
||||
return CHECK_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
return check (timestep, shape_a, shape_b, info);
|
||||
};
|
||||
|
||||
check_cb get_check (Shape *shape_a, Shape *shape_b) {
|
||||
if ( (dynamic_cast<Polygon*> (shape_a) != NULL)
|
||||
&& (dynamic_cast<Sphere*> (shape_b) != NULL) ) {
|
||||
return check_collision_polygon_sphere;
|
||||
}
|
||||
else if ( (dynamic_cast<Polygon*> (shape_b) != NULL)
|
||||
&& (dynamic_cast<Sphere*> (shape_a) != NULL) ) {
|
||||
return check_collision_polygon_sphere;
|
||||
} else if ( (dynamic_cast<Sphere*> (shape_b) != NULL)
|
||||
&& (dynamic_cast<Sphere*> (shape_a) != NULL) ) {
|
||||
return check_collision_sphere_sphere;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int check_collision_rel (float timestep, Shape *shape_a, Shape *shape_b, vector3d *velocity_b, CollisionInfo *info) {
|
||||
check_cb check = NULL;
|
||||
|
||||
shape_b->setVelocity (*velocity_b);
|
||||
check = get_check (shape_a, shape_b);
|
||||
|
||||
if ( check == NULL ) {
|
||||
return CHECK_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
return check (timestep, shape_a, shape_b, info);
|
||||
};
|
||||
|
||||
/** \brief calculates the time for a moving point to touch a plane
|
||||
*
|
||||
* \param normal The normal of the plane
|
||||
* \param plane_point a point on the plane
|
||||
* \param point the moving point
|
||||
* \param velocity the velocity of the point
|
||||
*
|
||||
* \returns If the return value is negative, the point is moving away from the
|
||||
* plane or is below the plane and thus does not touch it. Otherwise
|
||||
* point + (return value) * velocity
|
||||
* is on the plane.
|
||||
*/
|
||||
float calculate_contact_plane_point (vector3d &normal, vector3d &plane_point, vector3d &point, vector3d &velocity) {
|
||||
vector3d temp_vector (point);
|
||||
temp_vector -= plane_point;
|
||||
|
||||
// If the following is < 0 then the point is "below" the plane
|
||||
if (normal * temp_vector < 0) {
|
||||
// If the following is < 0 then we move even deeper
|
||||
if ( normal * velocity < 0 )
|
||||
return -999;
|
||||
// Or towards the upper side of the plane.
|
||||
else
|
||||
return -111;
|
||||
}
|
||||
|
||||
int i,imax = -1;
|
||||
float vmax = 0.;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if ( normal[i] * velocity[i] < vmax) {
|
||||
vmax = normal[i] * velocity[i];
|
||||
imax = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (imax == -1) {
|
||||
return -1.;
|
||||
}
|
||||
|
||||
return (normal[imax] * plane_point[imax] - normal[imax] * point[imax]) / vmax;
|
||||
}
|
||||
|
||||
// #define VERBOSE_PHASE
|
||||
|
||||
/** \brief Checks whether a sphere penetrates one of the polygones edges
|
||||
*
|
||||
* This check only finds intersections of the sphere with one of the sides in
|
||||
* other words it will not find intersections with the vertices. As for convex
|
||||
* polygons a sphere will either touch one of the edges or one of the
|
||||
* vertices.
|
||||
*
|
||||
* First thing we do is calculate the normals pointing out of the polygon.
|
||||
* Then for each edge e of the polygon (is being done by the function
|
||||
* calculate_contatc_plane_point (...):
|
||||
* - Calculate the point that would be the first to touch edge e if a contact
|
||||
* occurs
|
||||
* - Calculate the time it would take for this point to touch the edge with
|
||||
* the relative velocity of the sphere
|
||||
*
|
||||
* Next we calculatefor each edge the point on the sphere which would be the first to touch
|
||||
* the polygon, if it was moving towards the current edge.
|
||||
*/
|
||||
int check_collision_polygon_sphere_sides (Shape *shape_a, Shape *shape_b, CollisionInfo *info) {
|
||||
Polygon* polygon = dynamic_cast<Polygon*> (shape_a);
|
||||
Sphere* sphere = dynamic_cast<Sphere*> (shape_b);
|
||||
|
||||
if ( polygon == NULL && sphere == NULL) {
|
||||
polygon = dynamic_cast<Polygon*> (shape_b);
|
||||
sphere = dynamic_cast<Sphere*> (shape_a);
|
||||
}
|
||||
|
||||
if (!polygon || !sphere) {
|
||||
return CHECK_ERROR_INVALID_TYPES;
|
||||
}
|
||||
|
||||
vector3d velocity_sphere = sphere->getVelocity();
|
||||
|
||||
vector3d temp_vector (velocity_sphere);
|
||||
if (temp_vector.length2() == 0.)
|
||||
return 0;
|
||||
|
||||
// Calculate the normals pointing OUT of the polygon
|
||||
float *t = NULL, t_min = 10000.;
|
||||
unsigned int i,j,vertices,count = 0;
|
||||
vertices = polygon->getVerticeCount();
|
||||
vector3d *normals = NULL;
|
||||
vector3d side (0., 0., 0.);
|
||||
vector3d up (0., 1., 0.);
|
||||
/*
|
||||
if (polygon->getPosition().length() > 0.) {
|
||||
for (i = 0; i < vertices; i++) {
|
||||
polygon->getVertice(i) += polygon->getPosition();
|
||||
}
|
||||
}
|
||||
*/
|
||||
// normals contains all the normal vectors out of
|
||||
// the polygon
|
||||
normals = new vector3d[vertices];
|
||||
// The array t contains the time it takes until the sphere
|
||||
// would touch the plane with the given velocity
|
||||
t = new float[vertices];
|
||||
|
||||
for (i = 0; i < vertices; i++) {
|
||||
j = (i + 1) % vertices;
|
||||
side = polygon->getVertice(j);
|
||||
side -= polygon->getVertice(i);
|
||||
normals[i] = cross_product (side, up);
|
||||
normals[i] /= normals[i].length ();
|
||||
|
||||
// temp_vector is the point on the sphere that would touch the plane first
|
||||
// if it was directly moving towards it
|
||||
temp_vector = normals[i];
|
||||
temp_vector *= - sphere->getRadius();
|
||||
temp_vector += sphere->getPosition();
|
||||
|
||||
t[i] = calculate_contact_plane_point (normals[i], polygon->getVertice(i), temp_vector, velocity_sphere);
|
||||
|
||||
#ifdef VERBOSE_PHASE
|
||||
cout << "= next =" << endl;
|
||||
cout << "t[" << i << "] = " << t[i] << " normal = "; normals[i].print ();
|
||||
cout << "point = "; temp_vector.print();
|
||||
cout << "plane point = "; polygon->getVertice(i).print();
|
||||
#endif
|
||||
if (t[i] < 0)
|
||||
normals[i].setValues (0., 0., 0.);
|
||||
else {
|
||||
if (t[i] < t_min)
|
||||
t_min = t[i];
|
||||
count ++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
delete[] t;
|
||||
delete[] normals;
|
||||
return 0;
|
||||
}
|
||||
|
||||
vector3d contact_point, cp_near;
|
||||
|
||||
/// \ToDo: Instead of checking all planes, remember which ones to check
|
||||
for (i = 0; i < vertices; i++) {
|
||||
if ( t[i] >= 0) {
|
||||
// So there seems to occur an collision. Now we have to check,
|
||||
// whether this is actually between the points that define the
|
||||
// plane.
|
||||
unsigned int min_distance_vertex_index = i, other_vertice = (i + 1) % vertices;
|
||||
float min_distance;
|
||||
j = (i + 1) % vertices;
|
||||
// First we calculate the actual contact point:
|
||||
temp_vector = normals[i];
|
||||
temp_vector *= - sphere->getRadius();
|
||||
temp_vector *= t[i];
|
||||
temp_vector += sphere->getPosition();
|
||||
|
||||
contact_point = normals[i];
|
||||
contact_point *= -sphere->getRadius();
|
||||
contact_point += temp_vector;
|
||||
|
||||
// Now we calculate to which vertice this point is closer:
|
||||
temp_vector = contact_point;
|
||||
temp_vector -= polygon->getVertice(i);
|
||||
min_distance = temp_vector.length2 ();
|
||||
|
||||
temp_vector = contact_point;
|
||||
temp_vector -= polygon->getVertice(j);
|
||||
|
||||
if (min_distance > temp_vector.length2 ()) {
|
||||
min_distance_vertex_index = j;
|
||||
other_vertice = i;
|
||||
}
|
||||
|
||||
// Then we want to see, whether the contact point actually lies
|
||||
// on the vector that goes from one vertice to the other. For
|
||||
// this we calculate (cp - near) * (far - near). The value
|
||||
// cannot be greater than 1. (otherwise we would have picked
|
||||
// the other vector as near. If it is < 0 then it is outside
|
||||
// of the polygon.
|
||||
temp_vector = polygon->getVertice(other_vertice);
|
||||
temp_vector -= polygon->getVertice(min_distance_vertex_index);
|
||||
|
||||
temp_vector /= temp_vector.length();
|
||||
|
||||
cp_near = contact_point;
|
||||
cp_near -= polygon->getVertice(min_distance_vertex_index);
|
||||
|
||||
float val = cp_near * temp_vector;
|
||||
if ( (val >= 0 && val <= 1) && (t[i] <= 1.)) {
|
||||
info->time = t[i];
|
||||
info->normal = normals[i];
|
||||
|
||||
info->point = sphere->getPosition();
|
||||
info->point += sphere->getVelocity() * t[i];
|
||||
info->point -= normals[i] * sphere->getRadius ();
|
||||
|
||||
delete[] t;
|
||||
delete[] normals;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if ( (t_min <= 1.) && (t_min >= 0.)) {
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
delete[] t;
|
||||
delete[] normals;
|
||||
|
||||
if (t_min > 1.)
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
// return CHECK_ERROR_UNKNOWN;
|
||||
};
|
||||
|
||||
int check_collision_polygon_sphere_vertices (Shape *shape_a, Shape *shape_b, CollisionInfo *info) {
|
||||
Polygon* polygon = dynamic_cast<Polygon*> (shape_a);
|
||||
Sphere* sphere = dynamic_cast<Sphere*> (shape_b);
|
||||
|
||||
if ( polygon == NULL && sphere == NULL) {
|
||||
polygon = dynamic_cast<Polygon*> (shape_b);
|
||||
sphere = dynamic_cast<Sphere*> (shape_a);
|
||||
}
|
||||
|
||||
if (!polygon || !sphere) {
|
||||
return CHECK_ERROR_INVALID_TYPES;
|
||||
}
|
||||
|
||||
// Transform global velocities to relative velocities:
|
||||
/*
|
||||
sphere->setVelocity (sphere->getVelocity() - polygon->getVelocity());
|
||||
*/
|
||||
vector3d velocity_sphere = sphere->getVelocity();
|
||||
|
||||
vector3d temp_vector (velocity_sphere);
|
||||
if (temp_vector.length2() == 0.) {
|
||||
#ifdef VERBOSE_PHASE
|
||||
cout << "sphere has no velocity!" << endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
vector3d contact_point, cp_near;
|
||||
|
||||
// Okay if we happen to be here, there still might be one of
|
||||
// the corners colliding with the sphere.
|
||||
float a, b, c, t1, t2, t_min = 10000;
|
||||
unsigned int i, j, vertices;
|
||||
vector3d position (sphere->getPosition());
|
||||
vector3d velocity (sphere->getVelocity());
|
||||
float radius = sphere->getRadius();
|
||||
vertices = polygon->getVerticeCount();
|
||||
|
||||
for (i = 0; i < vertices; i++) {
|
||||
vector3d vertice (polygon->getVertice(i));
|
||||
a = b = c = 0;
|
||||
|
||||
// We must ensure that all happens in the x-z-plane (so y == 0.)
|
||||
vertice[1] = 0.;
|
||||
position[1] = 0.;
|
||||
|
||||
vector3d distance_sphere_vertice;
|
||||
for (j = 0; j < 3; j++) {
|
||||
distance_sphere_vertice[j] = position[j] - vertice[j];
|
||||
}
|
||||
#ifdef VERBOSE_PHASE
|
||||
cout << " ===== " << endl;
|
||||
cout << "vertice = ";
|
||||
vertice.print ();
|
||||
velocity.print ();
|
||||
position.print ();
|
||||
cout << "radius = " << radius << endl;
|
||||
cout << "distance = " << distance_sphere_vertice.length () << endl;;
|
||||
#endif
|
||||
for (j = 0; j < 3; j++) {
|
||||
a += velocity[j]*velocity[j];
|
||||
b += 2 * velocity[j] * (position[j] - vertice[j]);
|
||||
c += position[j] * position[j] - 2 * position[j] * vertice[j] + vertice[j] * vertice[j];
|
||||
}
|
||||
c -= radius * radius;
|
||||
|
||||
if (solve_quadratic (a, b, c, &t1, &t2)) {
|
||||
// cout << "solve_quadratic = " << t1 << "\t" << t2 << endl;
|
||||
float t_temp_min = t2;
|
||||
if (t1 < t2)
|
||||
t_temp_min = t1;
|
||||
|
||||
if (t_temp_min < t_min) {
|
||||
if ((t_temp_min <= 1.) && (t_temp_min >= 0.)) {
|
||||
t_min = t_temp_min;
|
||||
temp_vector = position;
|
||||
temp_vector -= vertice;
|
||||
temp_vector /= temp_vector.length ();
|
||||
#ifdef VERBOSE_PHASE
|
||||
cout << "new closest point t = " << t_min << endl;
|
||||
#endif
|
||||
info->time = t_min;
|
||||
info->normal = temp_vector;
|
||||
info->point = vertice;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( (t_min <= 1.) && (t_min >= 0.)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (t_min > 1.)
|
||||
return 0;
|
||||
|
||||
return CHECK_ERROR_UNKNOWN;
|
||||
};
|
||||
|
||||
int check_collision_polygon_sphere (float timestep, Shape *shape_a, Shape *shape_b, CollisionInfo *info) {
|
||||
/* If the first shape given is a sphere and the second one a shape, we have
|
||||
* to remember it to set the right value to *info.
|
||||
*/
|
||||
bool swapped = false;
|
||||
Polygon* polygon_cast_test = dynamic_cast<Polygon*> (shape_a);
|
||||
Sphere* sphere_cast_test = dynamic_cast<Sphere*> (shape_b);
|
||||
|
||||
if ( polygon_cast_test == NULL && sphere_cast_test == NULL) {
|
||||
polygon_cast_test = dynamic_cast<Polygon*> (shape_b);
|
||||
sphere_cast_test = dynamic_cast<Sphere*> (shape_a);
|
||||
|
||||
swapped = true;
|
||||
}
|
||||
|
||||
if (!polygon_cast_test || !sphere_cast_test) {
|
||||
return CHECK_ERROR_INVALID_TYPES;
|
||||
}
|
||||
|
||||
Polygon polygon_copy (*polygon_cast_test);
|
||||
Sphere sphere_copy (*sphere_cast_test);
|
||||
|
||||
unsigned int vertices;
|
||||
vertices = polygon_copy.getVerticeCount();
|
||||
|
||||
#ifdef VERBOSE_PHASE
|
||||
cout << "======== New Polygon Sphere Test: Phase 1" << endl;
|
||||
if (swapped)
|
||||
cout << "Swapped!" << endl;
|
||||
cout << "Polygon position: ";
|
||||
polygon_copy.getPosition().print ();
|
||||
cout << "Polygon velocity: ";
|
||||
polygon_copy.getVelocity().print ();
|
||||
cout << "Sphere position: ";
|
||||
sphere_copy.getPosition().print ();
|
||||
cout << "Sphere velocity: ";
|
||||
sphere_copy.getVelocity().print ();
|
||||
cout << "Timestep : " << timestep << endl;
|
||||
|
||||
cout << "Vertices before transformation = " << endl;
|
||||
int i;
|
||||
for (i = 0; i < vertices; i++) {
|
||||
polygon_copy.getVertice(i).print();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Here we translate the polygon and its velocity into the reference frame
|
||||
// of the polygon.
|
||||
sphere_copy.setPosition (sphere_copy.getPosition() - polygon_copy.getPosition());
|
||||
sphere_copy.setPosition (sphere_copy.getPosition().rotate_y (-polygon_copy.getAngle()));
|
||||
// Here scale the velocity so that our time horizon lies in [0., 1.]
|
||||
sphere_copy.setVelocity ((sphere_copy.getVelocity() - polygon_copy.getVelocity() ) * timestep );
|
||||
sphere_copy.setVelocity (sphere_copy.getVelocity().rotate_y (-polygon_copy.getAngle()));
|
||||
|
||||
#ifdef VERBOSE_PHASE
|
||||
cout << "Vertices after transformation = " << endl;
|
||||
for (i = 0; i < vertices; i++) {
|
||||
polygon_copy.getVertice(i).print();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VERBOSE_PHASE
|
||||
cout << "After transformation:" << endl;
|
||||
cout << "Polygon position: ";
|
||||
polygon_copy.getPosition().print ();
|
||||
cout << "Polygon velocity: ";
|
||||
polygon_copy.getVelocity().print ();
|
||||
cout << "Sphere position: ";
|
||||
sphere_copy.getPosition().print ();
|
||||
cout << "Sphere velocity: ";
|
||||
sphere_copy.getVelocity().print ();
|
||||
#endif
|
||||
|
||||
CollisionInfo sides_info;
|
||||
CollisionInfo vertices_info;
|
||||
int sides_result = 0, vertices_result = 0;
|
||||
|
||||
/* Tricky part: Since polygons are assumed to be convex and we calculated
|
||||
* with both methods a collision, we take the sides result. Since they are
|
||||
* convex the first event to happen is the collision with the side.
|
||||
* Otherwise it would first touch the vertice and then the side, which is
|
||||
* not possible. (\Todo true?)
|
||||
*/
|
||||
|
||||
sides_result = check_collision_polygon_sphere_sides (&polygon_copy, &sphere_copy, &sides_info);
|
||||
// We have to transform the time back to [0., timestep]
|
||||
sides_info.time *= timestep;
|
||||
#ifdef VERBOSE_PHASE
|
||||
cout << "sides_result = " << sides_result << " t = " << sides_info.time << endl;
|
||||
#endif
|
||||
if (sides_result > 0) {
|
||||
sides_info.point.rotate_y (polygon_copy.getAngle());
|
||||
sides_info.normal.rotate_y (polygon_copy.getAngle());
|
||||
sides_info.point += polygon_copy.getPosition();
|
||||
memcpy (info, &sides_info, sizeof (CollisionInfo));
|
||||
sides_info.time *= timestep;
|
||||
if (swapped == true) {
|
||||
info->reference_shape = 1;
|
||||
} else {
|
||||
info->reference_shape = 0;
|
||||
}
|
||||
return sides_result;
|
||||
}
|
||||
|
||||
vertices_result = check_collision_polygon_sphere_vertices (&polygon_copy, &sphere_copy, &vertices_info);
|
||||
// We have to transform the time back to [0., timestep]
|
||||
vertices_info.time *= timestep;
|
||||
#ifdef VERBOSE_PHASE
|
||||
cout << "vertices_res = " << vertices_result << " t = " << vertices_info.time << endl;
|
||||
cout << "vertices_point = ";
|
||||
vertices_info.point.print();
|
||||
#endif
|
||||
if (vertices_result > 0) {
|
||||
vertices_info.point.rotate_y (polygon_copy.getAngle());
|
||||
vertices_info.normal.rotate_y (polygon_copy.getAngle());
|
||||
vertices_info.point += polygon_copy.getPosition();
|
||||
memcpy (info, &vertices_info, sizeof (CollisionInfo));
|
||||
if (swapped == true) {
|
||||
info->reference_shape = 1;
|
||||
} else {
|
||||
info->reference_shape = 0;
|
||||
}
|
||||
return vertices_result;
|
||||
}
|
||||
|
||||
if ((sides_result == 0) && (vertices_result == 0))
|
||||
return 0;
|
||||
|
||||
return CHECK_ERROR_UNKNOWN;
|
||||
};
|
||||
|
||||
int check_collision_sphere_sphere (float timestep, Shape *shape_a, Shape *shape_b, CollisionInfo *info) {
|
||||
/* If the first shape given is a sphere and the second one a shape, we have
|
||||
* to remember it to set the right value to *info.
|
||||
*/
|
||||
Sphere* sphere_test_a = dynamic_cast<Sphere*> (shape_a);
|
||||
Sphere* sphere_test_b = dynamic_cast<Sphere*> (shape_b);
|
||||
|
||||
if (!sphere_test_a || !sphere_test_b) {
|
||||
return CHECK_ERROR_INVALID_TYPES;
|
||||
}
|
||||
|
||||
Sphere sphere_a (*sphere_test_a);
|
||||
Sphere sphere_b (*sphere_test_b);
|
||||
|
||||
// First we check whether there is actually a relative velocity towards each
|
||||
// other:
|
||||
vector3d rel_velocity = sphere_b.getVelocity ();
|
||||
rel_velocity -= sphere_a.getVelocity ();
|
||||
rel_velocity *= timestep;
|
||||
if (rel_velocity.length2() == 0.)
|
||||
return 0;
|
||||
|
||||
vector3d rel_position = sphere_b.getPosition ();
|
||||
rel_position -= sphere_a.getPosition ();
|
||||
|
||||
// We need to ignore height differences
|
||||
rel_position[1] = 0.;
|
||||
rel_velocity[1] = 0.;
|
||||
|
||||
vector3d rel_position_norm = rel_position;
|
||||
rel_position_norm.normalize ();
|
||||
|
||||
float velocity_projection = rel_position_norm * rel_velocity;
|
||||
float distance = rel_position.length();
|
||||
|
||||
if (velocity_projection >= 0.)
|
||||
return 0;
|
||||
|
||||
float t = (- distance + sphere_a.getRadius () + sphere_b.getRadius ()) / velocity_projection;
|
||||
|
||||
#ifdef VERBOSE_PHASE
|
||||
cout << "==== New Sphere Sphere Test ====" << endl;
|
||||
cout << "Relative Position = ";
|
||||
rel_position.print ();
|
||||
cout << "Relative Velocity = ";
|
||||
rel_velocity.print ();
|
||||
cout << "velocity_projection = " << velocity_projection << endl;
|
||||
cout << "distance = " << distance << endl;
|
||||
cout << "- distance + Ra + Rb = " << - distance + sphere_a.getRadius () + sphere_b.getRadius () << endl;
|
||||
cout << "t = " << t << endl;
|
||||
#endif
|
||||
|
||||
// if t < 0 this means we would have to move back in time
|
||||
// to get to the point where the two spheres touched. In other words: they
|
||||
// are overlapping, hence it is an invalid state!
|
||||
if (t < 0)
|
||||
return CHECK_ERROR_OVERLAP;
|
||||
if (t > 1)
|
||||
return 0;
|
||||
|
||||
info->point = sphere_a.getPosition() + rel_position_norm * t;
|
||||
info->time = t * timestep;
|
||||
|
||||
if (sphere_a.getVelocity().length2() == 0.) {
|
||||
info->normal = rel_position_norm;
|
||||
info->reference_shape = 0;
|
||||
} else {
|
||||
info->normal = rel_position_norm * -1.;
|
||||
info->reference_shape = 1;
|
||||
}
|
||||
return 1;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
PROJECT (ENGINETESTS)
|
||||
|
||||
CMAKE_MINIMUM_REQUIRED (VERSION 2.6)
|
||||
|
||||
# Needed for UnitTest++
|
||||
LIST( APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../CMake )
|
||||
|
||||
SET ( TESTS_SRCS
|
||||
main.cc
|
||||
general.cc
|
||||
polygon_sphere.cc
|
||||
sphere_sphere.cc
|
||||
)
|
||||
|
||||
FIND_PACKAGE (UnitTest++)
|
||||
|
||||
INCLUDE_DIRECTORIES ( ../mathlib/ )
|
||||
|
||||
SET_TARGET_PROPERTIES ( ${PROJECT_EXECUTABLES} PROPERTIES
|
||||
LINKER_LANGUAGE CXX
|
||||
)
|
||||
|
||||
IF ( UNITTEST++_FOUND )
|
||||
|
||||
ADD_EXECUTABLE ( coll2dtests ${TESTS_SRCS} )
|
||||
|
||||
INCLUDE_DIRECTORIES ( ${UNITTEST++_INCLUDE_DIR} )
|
||||
|
||||
SET_TARGET_PROPERTIES ( coll2dtests PROPERTIES
|
||||
LINKER_LANGUAGE CXX
|
||||
OUTPUT_NAME runtests
|
||||
)
|
||||
|
||||
TARGET_LINK_LIBRARIES ( coll2dtests
|
||||
${UNITTEST++_LIBRARY}
|
||||
mathlib
|
||||
coll2d
|
||||
)
|
||||
|
||||
OPTION (RUN_AUTOMATIC_TESTS "Perform automatic tests after compilation?" OFF)
|
||||
|
||||
IF (RUN_AUTOMATIC_TESTS)
|
||||
ADD_CUSTOM_COMMAND (TARGET coll2dtests
|
||||
POST_BUILD
|
||||
COMMAND coll2dtests
|
||||
COMMENT "Running automated tests..."
|
||||
)
|
||||
ENDIF (RUN_AUTOMATIC_TESTS)
|
||||
|
||||
ENDIF ( UNITTEST++_FOUND )
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
#include <UnitTest++.h>
|
||||
|
||||
#include <coll2d.h>
|
||||
|
||||
using namespace coll2d;
|
||||
using namespace std;
|
||||
|
||||
TEST ( SphereCopyConstructer ) {
|
||||
Sphere sphere_a (123.);
|
||||
sphere_a.setVelocity (vector3d(1., 2., 3.));
|
||||
|
||||
Sphere sphere_b (sphere_a);
|
||||
CHECK_EQUAL (sphere_a.getRadius (), sphere_b.getRadius ());
|
||||
|
||||
vector3d velocity_a = sphere_a.getVelocity ();
|
||||
vector3d velocity_b = sphere_b.getVelocity ();
|
||||
|
||||
CHECK (velocity_a == velocity_b );
|
||||
|
||||
sphere_b.setVelocity (vector3d (0., 0., 0.));
|
||||
|
||||
velocity_a = sphere_a.getVelocity ();
|
||||
velocity_b = sphere_b.getVelocity ();
|
||||
|
||||
CHECK (velocity_a != velocity_b );
|
||||
}
|
||||
|
||||
TEST ( PolygonCopyConstructer ) {
|
||||
Polygon polygon_a (3);
|
||||
|
||||
vector3d vertice0 (-1., 0., -1.);
|
||||
vector3d vertice1 (1., 0., -1.);
|
||||
vector3d vertice2 (0., 0., 1.);
|
||||
|
||||
polygon_a.setVertice (0, vertice0);
|
||||
polygon_a.setVertice (1, vertice1);
|
||||
polygon_a.setVertice (2, vertice2);
|
||||
|
||||
polygon_a.setVelocity (vector3d(1., 2., 3.));
|
||||
|
||||
Polygon polygon_b (polygon_a);
|
||||
|
||||
vector3d velocity_a = polygon_a.getVelocity ();
|
||||
vector3d velocity_b = polygon_b.getVelocity ();
|
||||
|
||||
CHECK (vertice0 == polygon_b.getVertice (0));
|
||||
CHECK (vertice1 == polygon_b.getVertice (1));
|
||||
CHECK (vertice2 == polygon_b.getVertice (2));
|
||||
|
||||
polygon_b.setVelocity (vector3d (0., 0., 0.));
|
||||
velocity_a = polygon_a.getVelocity ();
|
||||
velocity_b = polygon_b.getVelocity ();
|
||||
|
||||
CHECK (velocity_a != velocity_b );
|
||||
}
|
||||
|
||||
/** Checks whether we identify the different shapes
|
||||
* correctly.
|
||||
*/
|
||||
TEST ( CheckShapeType ) {
|
||||
vector3d sphere_position (0., 0., 0.);
|
||||
|
||||
Shape* polygon = new Polygon (0, NULL);
|
||||
Shape* sphere = new Sphere (0, sphere_position);
|
||||
|
||||
Shape* cast_test = NULL;
|
||||
|
||||
cast_test = dynamic_cast <Sphere*> ( sphere );
|
||||
CHECK_EQUAL (cast_test, sphere);
|
||||
cast_test = dynamic_cast <Sphere*> ( polygon );
|
||||
CHECK (cast_test == NULL );
|
||||
cast_test = dynamic_cast <Polygon*> (polygon);
|
||||
CHECK_EQUAL (cast_test, polygon);
|
||||
cast_test = dynamic_cast <Polygon*> (sphere);
|
||||
CHECK (cast_test == NULL );
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
/** Checks whether the right check function is chosen
|
||||
*/
|
||||
TEST ( CheckGetCheck ) {
|
||||
vector3d sphere_position (0., 0., 0.);
|
||||
|
||||
Shape* polygon = new Polygon (0, NULL);
|
||||
Shape* sphere = new Sphere (0, sphere_position);
|
||||
|
||||
check_cb check = NULL;
|
||||
|
||||
// polygon - sphere -> polygon_sphere
|
||||
check = get_check (polygon, sphere);
|
||||
CHECK (static_cast<check_cb> (check) == static_cast<check_cb> (check_collision_polygon_sphere));
|
||||
|
||||
// sphere - polygon -> polygon_sphere
|
||||
check = get_check (sphere, polygon);
|
||||
CHECK (static_cast<check_cb> (check) == static_cast<check_cb> (check_collision_polygon_sphere));
|
||||
|
||||
// and we do not want that the pointers have changed!
|
||||
// (as it used to be in previous versions)
|
||||
CHECK (dynamic_cast <Polygon*> (sphere) == NULL);
|
||||
CHECK (dynamic_cast <Sphere*> (polygon) == NULL);
|
||||
|
||||
check = get_check (sphere, sphere);
|
||||
CHECK (check == check_collision_sphere_sphere);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckErrorNotImplemented ) {
|
||||
Shape* polygon = new Polygon (0, NULL);
|
||||
vector3d velocity (0., 0., 0.);
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_rel (1., polygon, polygon, &velocity, &info);
|
||||
|
||||
CHECK (result == CHECK_ERROR_NOT_IMPLEMENTED);
|
||||
|
||||
delete polygon;
|
||||
}
|
||||
|
||||
TEST ( CheckCalculateContactPlanePoint ) {
|
||||
vector3d normal (1., 0., 0.);
|
||||
vector3d plane_point (0., 0., 0.);
|
||||
vector3d point (1., 0., 0.);
|
||||
vector3d velocity (-1., 0., 0);
|
||||
|
||||
float result;
|
||||
|
||||
// Directly moving towards the plane
|
||||
result = calculate_contact_plane_point (normal, plane_point, point, velocity);
|
||||
CHECK_EQUAL (1, result);
|
||||
|
||||
// Moving with a slight angle onto the plane
|
||||
velocity.setValues (-1., 0., 0.2);
|
||||
result = calculate_contact_plane_point (normal, plane_point, point, velocity);
|
||||
CHECK_EQUAL (1, result);
|
||||
|
||||
velocity.setValues (-1., 0., 0.);
|
||||
|
||||
// Point is "below" the plane and moves even deeper
|
||||
plane_point.setValues (2., 0., 0);
|
||||
result = calculate_contact_plane_point (normal, plane_point, point, velocity);
|
||||
CHECK_EQUAL (-999, result);
|
||||
|
||||
// Point is "below" but moves towards the plane
|
||||
velocity.setValues (1., 0., 0);
|
||||
result = calculate_contact_plane_point (normal, plane_point, point, velocity);
|
||||
CHECK_EQUAL (-111, result);
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionStepsize ) {
|
||||
vector3d normal (1., 0., 0.);
|
||||
vector3d plane_point (0., 0., 0.);
|
||||
vector3d point (1., 0., 0.);
|
||||
vector3d velocity (-1., 0., 0);
|
||||
|
||||
float result;
|
||||
|
||||
// Directly moving towards the plane
|
||||
result = calculate_contact_plane_point (normal, plane_point, point, velocity);
|
||||
CHECK_EQUAL (1, result);
|
||||
|
||||
// Moving with a slight angle onto the plane
|
||||
velocity.setValues (-1., 0., 0.2);
|
||||
result = calculate_contact_plane_point (normal, plane_point, point, velocity);
|
||||
CHECK_EQUAL (1, result);
|
||||
|
||||
velocity.setValues (-1., 0., 0.);
|
||||
|
||||
// Point is "below" the plane and moves even deeper
|
||||
plane_point.setValues (2., 0., 0);
|
||||
result = calculate_contact_plane_point (normal, plane_point, point, velocity);
|
||||
CHECK_EQUAL (-999, result);
|
||||
|
||||
// Point is "below" but moves towards the plane
|
||||
velocity.setValues (1., 0., 0);
|
||||
result = calculate_contact_plane_point (normal, plane_point, point, velocity);
|
||||
CHECK_EQUAL (-111, result);
|
||||
}
|
||||
|
||||
/* Here we test, whether the value of info.reference_shape is correct.
|
||||
* If we swap the shapes passed to check_collision, then the value must swap,
|
||||
* too.
|
||||
*/
|
||||
TEST ( CheckReferenceShapeValue ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
// first part of the test, the collision occurs
|
||||
// on an edge
|
||||
vector3d sphere_position (2.3, 0., 0.);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
sphere->setVelocity (vector3d (-1., 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision (1., polygon, sphere, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (0, info.reference_shape);
|
||||
|
||||
result = check_collision (1., sphere, polygon, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (1, info.reference_shape);
|
||||
|
||||
// here the collision occurs on a vertice
|
||||
sphere->setPosition (vector3d (1.5, 0., -2.5));
|
||||
sphere->setVelocity (vector3d (0., 0., 1.));
|
||||
|
||||
result = check_collision (1., sphere, polygon, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (1, info.reference_shape);
|
||||
|
||||
result = check_collision (1., polygon, sphere, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (0, info.reference_shape);
|
||||
|
||||
delete sphere;
|
||||
delete polygon;
|
||||
}
|
||||
|
||||
/* Test whether Polygon::getCopy() does what it should */
|
||||
TEST ( CheckPolygonGetCopy ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Polygon* polygon = new Polygon (4, vertices);
|
||||
Polygon* polygon_copy = polygon->getCopy();
|
||||
|
||||
CHECK (polygon != polygon_copy);
|
||||
CHECK_EQUAL (polygon->getVerticeCount(), polygon_copy->getVerticeCount());
|
||||
|
||||
unsigned int i, count;
|
||||
count = polygon->getVerticeCount ();
|
||||
|
||||
for (i = 0; i < count; i ++) {
|
||||
vector3d vertice = polygon->getVertice (i);
|
||||
vector3d vertice_copy = polygon_copy->getVertice (i);
|
||||
|
||||
int j;
|
||||
for (j = 0; j < 3; j++) {
|
||||
CHECK_EQUAL (vertice[j], vertice_copy[j]);
|
||||
}
|
||||
}
|
||||
|
||||
delete polygon;
|
||||
delete polygon_copy;
|
||||
}
|
||||
|
||||
/* Test whether Sphere::getCopy() does what it should */
|
||||
TEST ( CheckSphereGetCopy ) {
|
||||
Sphere* sphere = new Sphere (1.23);
|
||||
Sphere* sphere_copy = sphere->getCopy();
|
||||
|
||||
CHECK_EQUAL (sphere->getRadius(), sphere_copy->getRadius());
|
||||
CHECK (sphere != sphere_copy);
|
||||
|
||||
delete sphere;
|
||||
delete sphere_copy;
|
||||
}
|
||||
|
||||
TEST ( SphereSetGetRadius ) {
|
||||
Sphere sphere (123.);
|
||||
CHECK_EQUAL (123, sphere.getRadius());
|
||||
|
||||
sphere.setRadius (456.);
|
||||
CHECK_EQUAL (456, sphere.getRadius());
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <UnitTest++.h>
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
return UnitTest::RunAllTests ();
|
||||
}
|
||||
@@ -0,0 +1,544 @@
|
||||
#include <UnitTest++.h>
|
||||
|
||||
#include <coll2d.h>
|
||||
|
||||
using namespace coll2d;
|
||||
using namespace std;
|
||||
|
||||
TEST ( CheckErrorInvalidTypes ) {
|
||||
Shape* polygon = new Polygon (0, NULL);
|
||||
vector3d velocity (0., 0., 0.);
|
||||
vector3d sphere_position (2.1, 0., 0.);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
sphere->setVelocity (vector3d(0., 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_polygon_sphere (1., sphere, sphere, &info);
|
||||
CHECK (result == CHECK_ERROR_INVALID_TYPES);
|
||||
|
||||
result = check_collision_polygon_sphere (1., polygon, polygon, &info);
|
||||
CHECK (result == CHECK_ERROR_INVALID_TYPES);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereNoVelocity ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., -1.);
|
||||
vertices[1].setValues (1., 0., -1.);
|
||||
vertices[2].setValues (1., 0., 1.);
|
||||
vertices[3].setValues (-1., 0., 1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
vector3d sphere_position (2.1, 0., 0.);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
|
||||
vector3d velocity (0., 0., 0.);
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_rel (1., polygon, sphere, &velocity, &info);
|
||||
|
||||
CHECK (result >= 0);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereDiverging ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
vector3d sphere_position (2.1, 0., 0.);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
|
||||
vector3d velocity (1., 0., 0.);
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_rel (1., polygon, sphere, &velocity, &info);
|
||||
|
||||
CHECK (result >= 0);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereContact ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
vector3d sphere_position (2., 0., 0.);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
sphere->setVelocity (vector3d (-1., 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision (1., polygon, sphere, &info);
|
||||
|
||||
CHECK (result > 0);
|
||||
CHECK_EQUAL (0.0, info.time);
|
||||
CHECK_EQUAL (1., info.normal[0]);
|
||||
CHECK_EQUAL (0., info.normal[1]);
|
||||
CHECK_EQUAL (0., info.normal[2]);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereColliding ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
vector3d sphere_position (2.5, 0., 0.1);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
|
||||
vector3d velocity (-1., 0., 0.);
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_rel (1., polygon, sphere, &velocity, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (0.5, info.time);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereCollidingTop ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
vector3d sphere_position (0., 0., 2.5);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
|
||||
vector3d velocity (0., 0., -1.);
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_rel (1., polygon, sphere, &velocity, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (0.5, info.time);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereCollidingNonPerpendicular ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
vector3d sphere_position (0., 0., 2.5);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
|
||||
vector3d velocity (0.01, 0., -1.);
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_rel (1., polygon, sphere, &velocity, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (0.5, info.time);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereCollidingCorner) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
vector3d sphere_position ( 1.5, 0., 2.5);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
|
||||
vector3d velocity (0.0, 0., -1.);
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_rel (1., polygon, sphere, &velocity, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
// In this test we make sure, that the z value of both the polygon and the
|
||||
// sphere get ignored:
|
||||
TEST ( CheckCollisionPolygonSphereCollidingCornerIgnoreHeight) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
vector3d sphere_position ( 1.5, 10., 2.5);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
sphere->setVelocity (vector3d (0., 0., -1.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision (1., polygon, sphere, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
|
||||
vertices[0].setValues (-1., -10., 1.);
|
||||
vertices[1].setValues (1., -10., 1.);
|
||||
vertices[2].setValues (1., -10., -1.);
|
||||
vertices[3].setValues (-1., -10., -1.);
|
||||
|
||||
sphere->setPosition (vector3d (1.5, 0., 2.5));
|
||||
result = check_collision (1., polygon, sphere, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereCollidingCornerTop) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
vector3d sphere_position (1.5, 0., - 2.5);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
|
||||
vector3d velocity (0., 0., 1.);
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_rel (1., polygon, sphere, &velocity, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereCollidingCornerNeighbour) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., -0.99);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
vector3d sphere_position (1.5 , 0., - 2.5);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
|
||||
vector3d velocity (0., 0., 1.);
|
||||
|
||||
CollisionInfo info;
|
||||
check_collision_rel (1., polygon, sphere, &velocity, &info);
|
||||
|
||||
CHECK (info.point == vertices[2]);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereNonCollidingSetPosition ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
vector3d sphere_position (2.5, 0., 0.1);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
sphere->setPosition (vector3d (35, 0, 0));
|
||||
vector3d velocity (-1., 0., 0.);
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_rel (1., polygon, sphere, &velocity, &info);
|
||||
|
||||
CHECK_EQUAL (0, result);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
// In this test we set the velocity of the polygon instead of the
|
||||
// sphere.
|
||||
TEST ( CheckCollisionPolygonSphereCollidingPolygonSetVelocity ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
vector3d sphere_position (2.5, 0., 0.);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
|
||||
vector3d velocity (1., 0., 0.);
|
||||
polygon->setVelocity (velocity);
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision (1., polygon, sphere, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (0.5, info.time);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckSetGetAngle ) {
|
||||
Shape* polygon = new Polygon (0, NULL);
|
||||
|
||||
polygon->setAngle (0.1234567);
|
||||
|
||||
CHECK (fabs (0.1234567 - polygon->getAngle ()) < 1.0e-7);
|
||||
|
||||
delete polygon;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereDiamond ) {
|
||||
vector3d vertices[4];
|
||||
float sqrt2 = sqrt (2);
|
||||
|
||||
vertices[0].setValues (-sqrt2, 0., 0.);
|
||||
vertices[1].setValues (0., 0., sqrt2);
|
||||
vertices[2].setValues (sqrt2, 0., 0.);
|
||||
vertices[3].setValues (0., 0., -sqrt2);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
Shape* sphere = new Sphere (1., vector3d (sqrt2 + 1.5, 0., 0.));
|
||||
sphere->setVelocity (vector3d (-1., 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision (1., polygon, sphere, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK (fabs (0.5 - info.time) <= 1.0e-6);
|
||||
CHECK_EQUAL (0, info.reference_shape);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckPolygonSpherePassingBy ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
vector3d sphere_position (1., 0., 2.5);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
sphere->setVelocity (vector3d (-2., 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision (1., polygon, sphere, &info);
|
||||
|
||||
CHECK_EQUAL (0, result);
|
||||
|
||||
delete sphere;
|
||||
delete polygon;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereReturnValuePoint ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
polygon->setPosition (vector3d (sqrt (2), 0., - sqrt (2)));
|
||||
polygon->setAngle (M_PI * 0.25);
|
||||
|
||||
Shape* sphere = new Sphere (1, vector3d (-sqrt(2) * 0.5, 0., sqrt (2) * 0.5));
|
||||
sphere->setVelocity (vector3d (sqrt (2), 0., -sqrt(2)));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision (1., polygon, sphere, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK ( fabs (0.5 - info.time) < 1.0e-6);
|
||||
CHECK ( (info.point - vector3d (sqrt (2) * 0.5, 0., -sqrt(2) * 0.5)).length() < 1.0e-6 );
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereReturnValuePointTranslated ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
polygon->setPosition (vector3d (sqrt (2) + 1., 0., - sqrt (2) - 1.));
|
||||
polygon->setAngle (M_PI * 0.25);
|
||||
|
||||
Shape* sphere = new Sphere (1, vector3d (-sqrt(2) * 0.5 + 1., 0., sqrt (2) * 0.5 -1.));
|
||||
sphere->setVelocity (vector3d (sqrt (2), 0., -sqrt(2)));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision (1., polygon, sphere, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK ( fabs (0.5 - info.time) < 1.0e-6);
|
||||
CHECK ( (info.point - vector3d (sqrt (2) * 0.5 + 1, 0., -sqrt(2) * 0.5 - 1.)).length() < 1.0e-6 );
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereReturnValuePointVerticeTranslated ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
polygon->setPosition (vector3d (0. + 2., 0., - sqrt (2) - 1.5));
|
||||
polygon->setAngle (M_PI * 0.25);
|
||||
|
||||
Shape* sphere = new Sphere (1, vector3d (0. + 2., 0., 0.));
|
||||
sphere->setVelocity (vector3d (0. , 0., -1.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision (1., polygon, sphere, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK ( fabs (0.5 - info.time) < 1.0e-6);
|
||||
CHECK ( (info.point - vector3d (0. + 2., 0., -1.5)).length() < 1.0e-6 );
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereReferenceShapePolygon ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
polygon->setPosition (vector3d (0., 0., 0.));
|
||||
polygon->setVelocity (vector3d (1., 0., 0.));
|
||||
|
||||
Shape* sphere = new Sphere (1, vector3d (2.5, 0., 0.));
|
||||
sphere->setVelocity (vector3d (0., 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision (1., polygon, sphere, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK ( fabs (0.5 - info.time) < 1.0e-6);
|
||||
CHECK_EQUAL ( 0, info.reference_shape );
|
||||
|
||||
polygon->setPosition (vector3d (0., 0., 0.));
|
||||
polygon->setVelocity (vector3d (1., 0., 0.));
|
||||
sphere->setPosition (vector3d (2.5, 0., 0.));
|
||||
sphere->setVelocity (vector3d (0., 0., 0.));
|
||||
|
||||
result = check_collision (1., sphere, polygon, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK ( fabs (0.5 - info.time) < 1.0e-6);
|
||||
CHECK_EQUAL ( 1, info.reference_shape );
|
||||
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckCollisionPolygonSphereTimestep ) {
|
||||
vector3d vertices[4];
|
||||
|
||||
vertices[0].setValues (-1., 0., 1.);
|
||||
vertices[1].setValues (1., 0., 1.);
|
||||
vertices[2].setValues (1., 0., -1.);
|
||||
vertices[3].setValues (-1., 0., -1.);
|
||||
|
||||
Shape* polygon = new Polygon (4, vertices);
|
||||
|
||||
vector3d sphere_position (2.5, 0., 0.1);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
|
||||
vector3d velocity (-1., 0., 0.);
|
||||
sphere->setVelocity (velocity);
|
||||
|
||||
CollisionInfo info;
|
||||
int result;
|
||||
result = check_collision (1., polygon, sphere, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (0.5, info.time);
|
||||
|
||||
result = check_collision (2., polygon, sphere, &info);
|
||||
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (0.5, info.time);
|
||||
|
||||
result = check_collision (0.499, polygon, sphere, &info);
|
||||
CHECK_EQUAL (0, result);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,245 @@
|
||||
#include <UnitTest++.h>
|
||||
|
||||
#include <coll2d.h>
|
||||
|
||||
using namespace coll2d;
|
||||
using namespace std;
|
||||
|
||||
TEST ( CheckSphereSphereInvalidTypes ) {
|
||||
Shape* polygon = new Polygon (0, NULL);
|
||||
vector3d velocity (0., 0., 0.);
|
||||
vector3d sphere_position (2.1, 0., 0.);
|
||||
Shape* sphere = new Sphere (1, sphere_position);
|
||||
sphere->setVelocity (vector3d(0., 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_sphere_sphere (1., polygon, sphere, &info);
|
||||
CHECK (result == CHECK_ERROR_INVALID_TYPES);
|
||||
|
||||
delete polygon;
|
||||
delete sphere;
|
||||
}
|
||||
|
||||
TEST ( CheckSphereSphereNoVelocity ) {
|
||||
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
|
||||
Shape* sphere_b = new Sphere (1, vector3d (4., 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
|
||||
CHECK_EQUAL (0, result);
|
||||
|
||||
delete sphere_a;
|
||||
delete sphere_b;
|
||||
}
|
||||
|
||||
/* This tests whether we report a collision time of 0.0 when two spheres are
|
||||
* in contact with each other
|
||||
*/
|
||||
TEST ( CheckCollisionSphereSphereContact ) {
|
||||
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
|
||||
Shape* sphere_b = new Sphere (1, vector3d (2., 0., 0.));
|
||||
|
||||
sphere_b->setVelocity (vector3d(-1., 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
|
||||
|
||||
CHECK (result >= 0);
|
||||
CHECK_EQUAL (0.0, info.time);
|
||||
|
||||
delete sphere_a;
|
||||
delete sphere_b;
|
||||
}
|
||||
|
||||
TEST ( CheckSphereSphereDiverging ) {
|
||||
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
|
||||
Shape* sphere_b = new Sphere (1, vector3d (4., 0., 0.));
|
||||
|
||||
sphere_b->setVelocity (vector3d (1., 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
|
||||
CHECK_EQUAL (0, result);
|
||||
|
||||
delete sphere_a;
|
||||
delete sphere_b;
|
||||
}
|
||||
|
||||
TEST ( CheckSphereSphereCollision ) {
|
||||
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
|
||||
Shape* sphere_b = new Sphere (1, vector3d (3., 0., 0.));
|
||||
|
||||
sphere_b->setVelocity (vector3d (-1., 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
|
||||
CHECK_EQUAL (1, result);
|
||||
|
||||
delete sphere_a;
|
||||
delete sphere_b;
|
||||
}
|
||||
|
||||
TEST ( CheckSphereSphereCollisionCheckOrder ) {
|
||||
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
|
||||
Shape* sphere_b = new Sphere (1, vector3d (3., 0., 0.));
|
||||
|
||||
sphere_a->setVelocity (vector3d (1., 0., 0.));
|
||||
sphere_b->setVelocity (vector3d (-1.5, 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
|
||||
CHECK_EQUAL (1, result);
|
||||
|
||||
vector3d normal = info.normal;
|
||||
result = check_collision_sphere_sphere (1., sphere_b, sphere_a, &info);
|
||||
CHECK_EQUAL (1, result);
|
||||
|
||||
CHECK ( normal[0] == -info.normal[0]);
|
||||
CHECK ( normal[1] == -info.normal[1]);
|
||||
CHECK ( normal[2] == -info.normal[2]);
|
||||
|
||||
delete sphere_a;
|
||||
delete sphere_b;
|
||||
}
|
||||
|
||||
TEST ( CheckSphereSphereNoCollision ) {
|
||||
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
|
||||
Shape* sphere_b = new Sphere (1, vector3d (3., 0., 0.));
|
||||
|
||||
sphere_b->setVelocity (vector3d (-0.9, 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
|
||||
CHECK_EQUAL (0, result);
|
||||
|
||||
delete sphere_a;
|
||||
delete sphere_b;
|
||||
}
|
||||
|
||||
TEST ( CheckSphereSphereCollisionResult ) {
|
||||
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
|
||||
Shape* sphere_b = new Sphere (1, vector3d (2.5, 0., 0.));
|
||||
|
||||
sphere_b->setVelocity (vector3d (-1, 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (0.5, info.time);
|
||||
|
||||
delete sphere_a;
|
||||
delete sphere_b;
|
||||
}
|
||||
|
||||
TEST ( CheckSphereSphereMovingNonHorizontal ) {
|
||||
Shape* sphere_a = new Sphere (3., vector3d (0., 0., 0.));
|
||||
Shape* sphere_b = new Sphere (1.5, vector3d (3., 0., 4.));
|
||||
|
||||
sphere_a->setVelocity (vector3d (3./5., 0., 4./5.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
|
||||
|
||||
vector3d result_normal = vector3d (-3., 0., -4.).normalize();
|
||||
vector3d collision_point = result_normal * -0.5;
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (0.5, info.time);
|
||||
CHECK_EQUAL (1, info.reference_shape);
|
||||
CHECK (result_normal == info.normal);
|
||||
CHECK (collision_point == info.point);
|
||||
|
||||
sphere_a->setVelocity (vector3d (0., 0., 0.));
|
||||
|
||||
sphere_b->setVelocity (vector3d (-3./5., 0., -4./5.));
|
||||
result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (0.5, info.time);
|
||||
|
||||
delete sphere_a;
|
||||
delete sphere_b;
|
||||
}
|
||||
|
||||
/* If there is one of the sphere non moving we must ensure that we
|
||||
* set the moving one as the incidence shape.
|
||||
*/
|
||||
TEST ( CheckSphereSphereReferenceShape ) {
|
||||
Shape* sphere_a = new Sphere (3., vector3d (0., 0., 0.));
|
||||
Shape* sphere_b = new Sphere (1.5, vector3d (3., 0., 4.));
|
||||
|
||||
sphere_a->setVelocity (vector3d (3./5., 0., 4./5.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
|
||||
|
||||
vector3d result_normal = vector3d (-3., 0., -4.).normalize();
|
||||
vector3d collision_point = result_normal * 0.5;
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (0.5, info.time);
|
||||
CHECK (result_normal == info.normal);
|
||||
CHECK_EQUAL (1, info.reference_shape);
|
||||
|
||||
sphere_a->setVelocity (vector3d (0., 0., 0.));
|
||||
|
||||
sphere_b->setVelocity (vector3d (-3./5., 0., -4./5.));
|
||||
result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK (result_normal * -1. == info.normal);
|
||||
CHECK_EQUAL (0.5, info.time);
|
||||
CHECK_EQUAL (0, info.reference_shape);
|
||||
|
||||
delete sphere_a;
|
||||
delete sphere_b;
|
||||
}
|
||||
|
||||
TEST ( CheckSphereSphereIgnoreHeight ) {
|
||||
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
|
||||
Shape* sphere_b = new Sphere (1, vector3d (3., 0., 0.));
|
||||
|
||||
sphere_b->setVelocity (vector3d (-2., 0., 0.));
|
||||
|
||||
sphere_a->setPosition (vector3d (0., 10., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
|
||||
CHECK_EQUAL (1, result);
|
||||
|
||||
delete sphere_a;
|
||||
delete sphere_b;
|
||||
}
|
||||
|
||||
TEST ( CheckSphereSphereCollisionTimestep ) {
|
||||
Shape* sphere_a = new Sphere (1., vector3d (0., 0., 0.));
|
||||
Shape* sphere_b = new Sphere (1, vector3d (3., 0., 0.));
|
||||
|
||||
sphere_b->setVelocity (vector3d (-1., 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
|
||||
CHECK_EQUAL (1, result);
|
||||
CHECK_EQUAL (1, info.time);
|
||||
|
||||
result = check_collision_sphere_sphere (2., sphere_a, sphere_b, &info);
|
||||
CHECK_EQUAL (1., result);
|
||||
CHECK_EQUAL (1., info.time);
|
||||
|
||||
result = check_collision_sphere_sphere (0.5, sphere_a, sphere_b, &info);
|
||||
CHECK_EQUAL (0, result);
|
||||
|
||||
delete sphere_a;
|
||||
delete sphere_b;
|
||||
}
|
||||
|
||||
TEST ( CheckPerpendicularMovement ) {
|
||||
Shape* sphere_a = new Sphere (0.4, vector3d (0., 0., 0.));
|
||||
Shape* sphere_b = new Sphere (0.4, vector3d (0., 0., -1.));
|
||||
|
||||
sphere_a->setVelocity (vector3d (0., 0., 0.));
|
||||
sphere_b->setVelocity (vector3d (5., 0., 0.));
|
||||
|
||||
CollisionInfo info;
|
||||
int result = check_collision_sphere_sphere (1., sphere_a, sphere_b, &info);
|
||||
CHECK_EQUAL (0, result);
|
||||
|
||||
delete sphere_a;
|
||||
delete sphere_b;
|
||||
}
|
||||
Reference in New Issue
Block a user