fysxasteroids/engine/libraries/coll2d/include/coll2d.h

347 lines
8.8 KiB
C++

#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 */