Clean the code :

- Use the mVariable syntax for member variables
- Every lines contain at most 100 characters
- Add private copy-constructor and assignment operators when needed
This commit is contained in:
Daniel Chappuis 2012-10-09 22:21:02 +02:00
parent f47298d7eb
commit 4ca42f9392
71 changed files with 3559 additions and 2130 deletions

View File

@ -31,7 +31,7 @@
using namespace reactphysics3d; using namespace reactphysics3d;
// Constructor // Constructor
Body::Body(bodyindex id) : id(id) { Body::Body(bodyindex id) : mID(id) {
} }

View File

@ -44,44 +44,69 @@ namespace reactphysics3d {
class Body { class Body {
protected : protected :
bodyindex id; // ID of the body
// -------------------- Attributes -------------------- //
// ID of the body
bodyindex mID;
// -------------------- Methods -------------------- //
// Private copy-constructor
Body(const Body& body);
// Private assignment operator
Body& operator=(const Body& body);
public : public :
Body(bodyindex id); // Constructor
virtual ~Body(); // Destructor
bodyindex getID() const; // Return the id of the body // -------------------- Methods -------------------- //
// Operators // Constructor
bool operator<(const Body& body2) const; // Smaller than operator Body(bodyindex id);
bool operator>(const Body& body2) const; // Larger than operator
bool operator==(const Body& body2) const; // Equal operator // Destructor
bool operator!=(const Body& body2) const; // Not equal operator virtual ~Body();
// Return the id of the body
bodyindex getID() const;
// Smaller than operator
bool operator<(const Body& body2) const;
// Larger than operator
bool operator>(const Body& body2) const;
// Equal operator
bool operator==(const Body& body2) const;
// Not equal operator
bool operator!=(const Body& body2) const;
}; };
// Return the id of the body // Return the id of the body
inline bodyindex Body::getID() const { inline bodyindex Body::getID() const {
return id; return mID;
} }
// Smaller than operator // Smaller than operator
inline bool Body::operator<(const Body& body2) const { inline bool Body::operator<(const Body& body2) const {
return (id < body2.id); return (mID < body2.mID);
} }
// Larger than operator // Larger than operator
inline bool Body::operator>(const Body& body2) const { inline bool Body::operator>(const Body& body2) const {
return (id > body2.id); return (mID > body2.mID);
} }
// Equal operator // Equal operator
inline bool Body::operator==(const Body& body2) const { inline bool Body::operator==(const Body& body2) const {
return (id == body2.id); return (mID == body2.mID);
} }
// Not equal operator // Not equal operator
inline bool Body::operator!=(const Body& body2) const { inline bool Body::operator!=(const Body& body2) const {
return (id != body2.id); return (mID != body2.mID);
} }
} }

View File

@ -31,25 +31,27 @@
using namespace reactphysics3d; using namespace reactphysics3d;
// Constructor // Constructor
CollisionBody::CollisionBody(const Transform& transform, CollisionShape *collisionShape, bodyindex id) CollisionBody::CollisionBody(const Transform& transform, CollisionShape *collisionShape,
: Body(id), collisionShape(collisionShape), transform(transform), isActive(true), hasMoved(false) { bodyindex id)
: Body(id), mCollisionShape(collisionShape), mTransform(transform),
mIsActive(true), mHasMoved(false) {
assert(collisionShape); assert(collisionShape);
isMotionEnabled = true; mIsMotionEnabled = true;
isCollisionEnabled = true; mIsCollisionEnabled = true;
interpolationFactor = 0.0; mInterpolationFactor = 0.0;
// Initialize the old transform // Initialize the old transform
oldTransform = transform; mOldTransform = transform;
// Create the AABB for broad-phase collision detection // Create the AABB for broad-phase collision detection
aabb = new AABB(transform, collisionShape->getLocalExtents(OBJECT_MARGIN)); mAabb = new AABB(transform, collisionShape->getLocalExtents(OBJECT_MARGIN));
} }
// Destructor // Destructor
CollisionBody::~CollisionBody() { CollisionBody::~CollisionBody() {
// Delete the AABB // Delete the AABB
delete aabb; delete mAabb;
} }

View File

@ -48,127 +48,194 @@ namespace reactphysics3d {
class CollisionBody : public Body { class CollisionBody : public Body {
protected : protected :
CollisionShape* collisionShape; // Collision shape of the body
Transform transform; // Position and orientation of the body // -------------------- Attributes -------------------- //
Transform oldTransform; // Last position and orientation of the body
decimal interpolationFactor; // Interpolation factor used for the state interpolation // Collision shape of the body
bool isActive; // True if the body is active (not sleeping because of deactivation) CollisionShape* mCollisionShape;
bool isMotionEnabled; // True if the body is able to move
bool isCollisionEnabled; // True if the body can collide with others bodies // Position and orientation of the body
AABB* aabb; // Axis-Aligned Bounding Box for Broad-Phase collision detection Transform mTransform;
bool hasMoved; // True if the body has moved during the last frame
// Last position and orientation of the body
Transform mOldTransform;
// Interpolation factor used for the state interpolation
decimal mInterpolationFactor;
// True if the body is active (not sleeping)
bool mIsActive;
// True if the body is able to move
bool mIsMotionEnabled;
// True if the body can collide with others bodies
bool mIsCollisionEnabled;
// AABB for Broad-Phase collision detection
AABB* mAabb;
// True if the body has moved during the last frame
bool mHasMoved;
// -------------------- Methods -------------------- //
// Private copy-constructor
CollisionBody(const CollisionBody& body);
// Private assignment operator
CollisionBody& operator=(const CollisionBody& body);
public : public :
CollisionBody(const Transform& transform, CollisionShape* collisionShape, bodyindex id); // Constructor
virtual ~CollisionBody(); // Destructor
bool getHasMoved() const; // Return true if the body has moved during the last frame // -------------------- Methods -------------------- //
void setHasMoved(bool hasMoved); // Set the hasMoved variable (true if the body has moved during the last frame)
CollisionShape* getCollisionShape() const; // Return the collision shape // Constructor
void setCollisionShape(CollisionShape* collisionShape); // Set the collision shape CollisionBody(const Transform& transform, CollisionShape* collisionShape, bodyindex id);
bool getIsActive() const; // Return true if the body is active
void setIsActive(bool isActive); // Set the isActive variable // Destructor
const Transform& getTransform() const; // Return the current position and orientation virtual ~CollisionBody();
void setTransform(const Transform& transform); // Set the current position and orientation
const AABB* getAABB() const; // Return the AAABB of the body // Return true if the body has moved during the last frame
Transform getInterpolatedTransform() const; // Return the interpolated transform for rendering bool getHasMoved() const;
void setInterpolationFactor(decimal factor); // Set the interpolation factor of the body
bool getIsMotionEnabled() const; // Return if the rigid body can move // Set the hasMoved variable (true if the body has moved during the last frame)
void setIsMotionEnabled(bool isMotionEnabled); // Set the value to true if the body can move void setHasMoved(bool hasMoved);
bool getIsCollisionEnabled() const; // Return true if the body can collide with others bodies
void setIsCollisionEnabled(bool isCollisionEnabled); // Set the isCollisionEnabled value // Return the collision shape
void updateOldTransform(); // Update the old transform with the current one CollisionShape* getCollisionShape() const;
void updateAABB(); // Update the Axis-Aligned Bounding Box coordinates
// Set the collision shape
void setCollisionShape(CollisionShape* collisionShape);
// Return true for an active body
bool getIsActive() const;
// Set the isActive variable
void setIsActive(bool isActive);
// Return the current position and orientation
const Transform& getTransform() const;
// Set the current position and orientation
void setTransform(const Transform& transform);
// Return the AAABB of the body
const AABB* getAABB() const;
// Return the interpolated transform for rendering
Transform getInterpolatedTransform() const;
// Set the interpolation factor of the body
void setInterpolationFactor(decimal factor);
// Return if the rigid body can move
bool getIsMotionEnabled() const;
// Set the value to true if the body can move
void setIsMotionEnabled(bool isMotionEnabled);
// Return true if the body can collide with others bodies
bool getIsCollisionEnabled() const;
// Set the isCollisionEnabled value
void setIsCollisionEnabled(bool isCollisionEnabled);
// Update the old transform with the current one
void updateOldTransform();
// Update the Axis-Aligned Bounding Box coordinates
void updateAABB();
}; };
// Return true if the body has moved during the last frame // Return true if the body has moved during the last frame
inline bool CollisionBody::getHasMoved() const { inline bool CollisionBody::getHasMoved() const {
return hasMoved; return mHasMoved;
} }
// Set the hasMoved variable (true if the body has moved during the last frame) // Set the hasMoved variable (true if the body has moved during the last frame)
inline void CollisionBody::setHasMoved(bool hasMoved) { inline void CollisionBody::setHasMoved(bool hasMoved) {
this->hasMoved = hasMoved; mHasMoved = hasMoved;
} }
// Return the collision shape // Return the collision shape
inline CollisionShape* CollisionBody::getCollisionShape() const { inline CollisionShape* CollisionBody::getCollisionShape() const {
assert(collisionShape); assert(mCollisionShape);
return collisionShape; return mCollisionShape;
} }
// Set the collision shape // Set the collision shape
inline void CollisionBody::setCollisionShape(CollisionShape* collisionShape) { inline void CollisionBody::setCollisionShape(CollisionShape* collisionShape) {
assert(collisionShape); assert(collisionShape);
this->collisionShape = collisionShape; mCollisionShape = collisionShape;
} }
// Return true if the body is active // Return true if the body is active
inline bool CollisionBody::getIsActive() const { inline bool CollisionBody::getIsActive() const {
return isActive; return mIsActive;
} }
// Set the isActive variable // Set the isActive variable
inline void CollisionBody::setIsActive(bool isActive) { inline void CollisionBody::setIsActive(bool isActive) {
this->isActive = isActive; mIsActive = isActive;
} }
// Return the interpolated transform for rendering // Return the interpolated transform for rendering
inline Transform CollisionBody::getInterpolatedTransform() const { inline Transform CollisionBody::getInterpolatedTransform() const {
return Transform::interpolateTransforms(oldTransform, transform, interpolationFactor); return Transform::interpolateTransforms(mOldTransform, mTransform, mInterpolationFactor);
} }
// Set the interpolation factor of the body // Set the interpolation factor of the body
inline void CollisionBody::setInterpolationFactor(decimal factor) { inline void CollisionBody::setInterpolationFactor(decimal factor) {
// Set the factor // Set the factor
interpolationFactor = factor; mInterpolationFactor = factor;
} }
// Return if the rigid body can move // Return if the rigid body can move
inline bool CollisionBody::getIsMotionEnabled() const { inline bool CollisionBody::getIsMotionEnabled() const {
return isMotionEnabled; return mIsMotionEnabled;
} }
// Set the value to true if the body can move // Set the value to true if the body can move
inline void CollisionBody::setIsMotionEnabled(bool isMotionEnabled) { inline void CollisionBody::setIsMotionEnabled(bool isMotionEnabled) {
this->isMotionEnabled = isMotionEnabled; mIsMotionEnabled = isMotionEnabled;
} }
// Return the current position and orientation // Return the current position and orientation
inline const Transform& CollisionBody::getTransform() const { inline const Transform& CollisionBody::getTransform() const {
return transform; return mTransform;
} }
// Set the current position and orientation // Set the current position and orientation
inline void CollisionBody::setTransform(const Transform& transform) { inline void CollisionBody::setTransform(const Transform& transform) {
// Check if the body has moved // Check if the body has moved
if (this->transform != transform) { if (this->mTransform != transform) {
hasMoved = true; mHasMoved = true;
} }
this->transform = transform; mTransform = transform;
} }
// Return the AAABB of the body // Return the AAABB of the body
inline const AABB* CollisionBody::getAABB() const { inline const AABB* CollisionBody::getAABB() const {
return aabb; return mAabb;
} }
// Return true if the body can collide with others bodies // Return true if the body can collide with others bodies
inline bool CollisionBody::getIsCollisionEnabled() const { inline bool CollisionBody::getIsCollisionEnabled() const {
return isCollisionEnabled; return mIsCollisionEnabled;
} }
// Set the isCollisionEnabled value // Set the isCollisionEnabled value
inline void CollisionBody::setIsCollisionEnabled(bool isCollisionEnabled) { inline void CollisionBody::setIsCollisionEnabled(bool isCollisionEnabled) {
this->isCollisionEnabled = isCollisionEnabled; mIsCollisionEnabled = isCollisionEnabled;
} }
// Update the old transform with the current one // Update the old transform with the current one
// This is used to compute the interpolated position and orientation of the body // This is used to compute the interpolated position and orientation of the body
inline void CollisionBody::updateOldTransform() { inline void CollisionBody::updateOldTransform() {
oldTransform = transform; mOldTransform = mTransform;
} }
// Update the rigid body in order to reflect a change in the body state // Update the rigid body in order to reflect a change in the body state
@ -177,7 +244,7 @@ inline void CollisionBody::updateAABB() {
// TODO : An AABB should not be updated every frame but only if the body has moved // TODO : An AABB should not be updated every frame but only if the body has moved
// Update the AABB // Update the AABB
aabb->update(transform, collisionShape->getLocalExtents(OBJECT_MARGIN)); mAabb->update(mTransform, mCollisionShape->getLocalExtents(OBJECT_MARGIN));
} }
} }

View File

@ -31,17 +31,19 @@
using namespace reactphysics3d; using namespace reactphysics3d;
// Constructor // Constructor
RigidBody::RigidBody(const Transform& transform, decimal mass, const Matrix3x3& inertiaTensorLocal, CollisionShape *collisionShape, bodyindex id) RigidBody::RigidBody(const Transform& transform, decimal mass, const Matrix3x3& inertiaTensorLocal,
: CollisionBody(transform, collisionShape, id), inertiaTensorLocal(inertiaTensorLocal), CollisionShape *collisionShape, bodyindex id)
mass(mass), inertiaTensorLocalInverse(inertiaTensorLocal.getInverse()), massInverse(1.0/mass) { : CollisionBody(transform, collisionShape, id), mInertiaTensorLocal(inertiaTensorLocal),
mMass(mass), mInertiaTensorLocalInverse(inertiaTensorLocal.getInverse()),
mMassInverse(1.0/mass) {
restitution = 1.0; mRestitution = 1.0;
// Set the body pointer of the AABB and the collision shape // Set the body pointer of the AABB and the collision shape
aabb->setBodyPointer(this); mAabb->setBodyPointer(this);
assert(collisionShape); assert(collisionShape);
assert(aabb); assert(mAabb);
} }
// Destructor // Destructor

View File

@ -23,8 +23,8 @@
* * * *
********************************************************************************/ ********************************************************************************/
#ifndef RIGIDBODY_H #ifndef RIGID_BODY_H
#define RIGIDBODY_H #define RIGID_BODY_H
// Libraries // Libraries
#include <cassert> #include <cassert>
@ -47,156 +47,236 @@ class RigidBody : public CollisionBody {
protected : protected :
// TODO : Remove the mass variable (duplicate with inverseMass) // TODO : Remove the mass variable (duplicate with inverseMass)
decimal mass; // Mass of the body
Vector3 linearVelocity; // Linear velocity of the body // -------------------- Attributes -------------------- //
Vector3 angularVelocity; // Angular velocity of the body
Vector3 externalForce; // Current external force on the body // Mass of the body
Vector3 externalTorque; // Current external torque on the body decimal mMass;
Matrix3x3 inertiaTensorLocal; // Local inertia tensor of the body (in body coordinates)
Matrix3x3 inertiaTensorLocalInverse; // Inverse of the inertia tensor of the body (in body coordinates) // Linear velocity of the body
decimal massInverse; // Inverse of the mass of the body Vector3 mLinearVelocity;
decimal restitution; // Coefficient of restitution (between 0 and 1), 1 for a very boucing body
// Angular velocity of the body
Vector3 mAngularVelocity;
// Current external force on the body
Vector3 mExternalForce;
// Current external torque on the body
Vector3 mExternalTorque;
// Local inertia tensor of the body (in local-space)
Matrix3x3 mInertiaTensorLocal;
// Inverse of the inertia tensor of the body
Matrix3x3 mInertiaTensorLocalInverse;
// Inverse of the mass of the body
decimal mMassInverse;
// Coefficient of restitution (between 0 and 1) where 1 is for a very bouncy body
decimal mRestitution;
// -------------------- Methods -------------------- //
// Private copy-constructor
RigidBody(const RigidBody& body);
// Private assignment operator
RigidBody& operator=(const RigidBody& body);
public : public :
RigidBody(const Transform& transform, decimal mass, const Matrix3x3& inertiaTensorLocal,
CollisionShape* collisionShape, bodyindex id); // Constructor // Copy-constructor
virtual ~RigidBody(); // Destructor
decimal getMass() const; // Return the mass of the body // -------------------- Methods -------------------- //
void setMass(decimal mass); // Set the mass of the body
Vector3 getLinearVelocity() const; // Return the linear velocity // Constructor
void setLinearVelocity(const Vector3& linearVelocity); // Set the linear velocity of the body RigidBody(const Transform& transform, decimal mass, const Matrix3x3& inertiaTensorLocal,
Vector3 getAngularVelocity() const; // Return the angular velocity CollisionShape* collisionShape, bodyindex id); // Copy-constructor
void setAngularVelocity(const Vector3& angularVelocity); // Set the angular velocity
void setMassInverse(decimal massInverse); // Set the inverse of the mass // Destructor
Vector3 getExternalForce() const; // Return the current external force of the body virtual ~RigidBody();
void setExternalForce(const Vector3& force); // Set the current external force on the body
Vector3 getExternalTorque() const; // Return the current external torque of the body // Return the mass of the body
void setExternalTorque(const Vector3& torque); // Set the current external torque of the body decimal getMass() const;
decimal getMassInverse() const; // Return the inverse of the mass of the body
Matrix3x3 getInertiaTensorLocal() const; // Return the local inertia tensor of the body (in body coordinates) // Set the mass of the body
void setInertiaTensorLocal(const Matrix3x3& inertiaTensorLocal); // Set the local inertia tensor of the body (in body coordinates) void setMass(decimal mass);
Matrix3x3 getInertiaTensorLocalInverse() const; // Get the inverse of the inertia tensor
Matrix3x3 getInertiaTensorWorld() const; // Return the inertia tensor in world coordinates // Return the linear velocity
Matrix3x3 getInertiaTensorInverseWorld() const; // Return the inverse of the inertia tensor in world coordinates Vector3 getLinearVelocity() const;
// Set the linear velocity of the body
void setLinearVelocity(const Vector3& linearVelocity);
// Return the angular velocity
Vector3 getAngularVelocity() const;
// Set the angular velocity
void setAngularVelocity(const Vector3& angularVelocity);
// Set the inverse of the mass
void setMassInverse(decimal massInverse);
// Return the current external force of the body
Vector3 getExternalForce() const;
// Set the current external force on the body
void setExternalForce(const Vector3& force);
// Return the current external torque of the body
Vector3 getExternalTorque() const;
// Set the current external torque of the body
void setExternalTorque(const Vector3& torque);
// Return the inverse of the mass of the body
decimal getMassInverse() const;
// Return the local inertia tensor of the body (in body coordinates)
Matrix3x3 getInertiaTensorLocal() const;
// Set the local inertia tensor of the body (in body coordinates)
void setInertiaTensorLocal(const Matrix3x3& inertiaTensorLocal);
// Get the inverse of the inertia tensor
Matrix3x3 getInertiaTensorLocalInverse() const;
// Return the inertia tensor in world coordinates
Matrix3x3 getInertiaTensorWorld() const;
// Return the inverse of the inertia tensor in world coordinates
Matrix3x3 getInertiaTensorInverseWorld() const;
decimal getRestitution() const; // Get the restitution coefficient // Get the restitution coefficient
void setRestitution(decimal restitution) throw(std::invalid_argument); // Set the restitution coefficient decimal getRestitution() const;
// Set the restitution coefficient
void setRestitution(decimal restitution) throw(std::invalid_argument);
}; };
// Method that return the mass of the body // Method that return the mass of the body
inline decimal RigidBody::getMass() const { inline decimal RigidBody::getMass() const {
return mass; return mMass;
}; };
// Method that set the mass of the body // Method that set the mass of the body
inline void RigidBody::setMass(decimal mass) { inline void RigidBody::setMass(decimal mass) {
this->mass = mass; mMass = mass;
} }
// Return the linear velocity // Return the linear velocity
inline Vector3 RigidBody::getLinearVelocity() const { inline Vector3 RigidBody::getLinearVelocity() const {
return linearVelocity; return mLinearVelocity;
} }
// Return the angular velocity of the body // Return the angular velocity of the body
inline Vector3 RigidBody::getAngularVelocity() const { inline Vector3 RigidBody::getAngularVelocity() const {
return angularVelocity; return mAngularVelocity;
} }
inline void RigidBody::setAngularVelocity(const Vector3& angularVelocity) { inline void RigidBody::setAngularVelocity(const Vector3& angularVelocity) {
this->angularVelocity = angularVelocity; mAngularVelocity = angularVelocity;
} }
// Set the inverse of the mass // Set the inverse of the mass
inline void RigidBody::setMassInverse(decimal massInverse) { inline void RigidBody::setMassInverse(decimal massInverse) {
this->massInverse = massInverse; mMassInverse = massInverse;
} }
// Get the inverse of the inertia tensor // Get the inverse of the inertia tensor
inline Matrix3x3 RigidBody::getInertiaTensorLocalInverse() const { inline Matrix3x3 RigidBody::getInertiaTensorLocalInverse() const {
return inertiaTensorLocalInverse; return mInertiaTensorLocalInverse;
} }
// Return the external force on the body // Return the external force on the body
inline Vector3 RigidBody::getExternalForce() const { inline Vector3 RigidBody::getExternalForce() const {
return externalForce; return mExternalForce;
} }
// Set the external force on the body // Set the external force on the body
inline void RigidBody::setExternalForce(const Vector3& force) { inline void RigidBody::setExternalForce(const Vector3& force) {
this->externalForce = force; mExternalForce = force;
} }
// Return the current external torque on the body // Return the current external torque on the body
inline Vector3 RigidBody::getExternalTorque() const { inline Vector3 RigidBody::getExternalTorque() const {
return externalTorque; return mExternalTorque;
} }
// Set the current external torque on the body // Set the current external torque on the body
inline void RigidBody::setExternalTorque(const Vector3& torque) { inline void RigidBody::setExternalTorque(const Vector3& torque) {
this->externalTorque = torque; mExternalTorque = torque;
} }
// Return the inverse of the mass of the body // Return the inverse of the mass of the body
inline decimal RigidBody::getMassInverse() const { inline decimal RigidBody::getMassInverse() const {
return massInverse; return mMassInverse;
} }
// Return the local inertia tensor of the body (in body coordinates) // Return the local inertia tensor of the body (in body coordinates)
inline Matrix3x3 RigidBody::getInertiaTensorLocal() const { inline Matrix3x3 RigidBody::getInertiaTensorLocal() const {
return inertiaTensorLocal; return mInertiaTensorLocal;
} }
// Set the local inertia tensor of the body (in body coordinates) // Set the local inertia tensor of the body (in body coordinates)
inline void RigidBody::setInertiaTensorLocal(const Matrix3x3& inertiaTensorLocal) { inline void RigidBody::setInertiaTensorLocal(const Matrix3x3& inertiaTensorLocal) {
this->inertiaTensorLocal = inertiaTensorLocal; mInertiaTensorLocal = inertiaTensorLocal;
} }
// Return the inertia tensor in world coordinates // Return the inertia tensor in world coordinates
// The inertia tensor I_w in world coordinates in computed with the local inertia tensor I_b in body coordinates // The inertia tensor I_w in world coordinates is computed
// with the local inertia tensor I_b in body coordinates
// by I_w = R * I_b * R^T // by I_w = R * I_b * R^T
// where R is the rotation matrix (and R^T its transpose) of the current orientation quaternion of the body // where R is the rotation matrix (and R^T its transpose) of
// the current orientation quaternion of the body
inline Matrix3x3 RigidBody::getInertiaTensorWorld() const { inline Matrix3x3 RigidBody::getInertiaTensorWorld() const {
// Compute and return the inertia tensor in world coordinates // Compute and return the inertia tensor in world coordinates
return transform.getOrientation().getMatrix() * inertiaTensorLocal * transform.getOrientation().getMatrix().getTranspose(); return mTransform.getOrientation().getMatrix() * mInertiaTensorLocal *
mTransform.getOrientation().getMatrix().getTranspose();
} }
// Return the inverse of the inertia tensor in world coordinates // Return the inverse of the inertia tensor in world coordinates
// The inertia tensor I_w in world coordinates in computed with the local inverse inertia tensor I_b^-1 in body coordinates // The inertia tensor I_w in world coordinates is computed with the
// local inverse inertia tensor I_b^-1 in body coordinates
// by I_w = R * I_b^-1 * R^T // by I_w = R * I_b^-1 * R^T
// where R is the rotation matrix (and R^T its transpose) of the current orientation quaternion of the body // where R is the rotation matrix (and R^T its transpose) of the
// current orientation quaternion of the body
inline Matrix3x3 RigidBody::getInertiaTensorInverseWorld() const { inline Matrix3x3 RigidBody::getInertiaTensorInverseWorld() const {
// Compute and return the inertia tensor in world coordinates // Compute and return the inertia tensor in world coordinates
return transform.getOrientation().getMatrix() * inertiaTensorLocalInverse * transform.getOrientation().getMatrix().getTranspose(); return mTransform.getOrientation().getMatrix() * mInertiaTensorLocalInverse *
mTransform.getOrientation().getMatrix().getTranspose();
} }
// Set the linear velocity of the rigid body // Set the linear velocity of the rigid body
inline void RigidBody::setLinearVelocity(const Vector3& linearVelocity) { inline void RigidBody::setLinearVelocity(const Vector3& linearVelocity) {
// If the body is able to move // If the body is able to move
if (isMotionEnabled) { if (mIsMotionEnabled) {
// Update the linear velocity of the current body state // Update the linear velocity of the current body state
this->linearVelocity = linearVelocity; mLinearVelocity = linearVelocity;
} }
} }
// Get the restitution coeffficient of the rigid body // Get the restitution coeffficient of the rigid body
inline decimal RigidBody::getRestitution() const { inline decimal RigidBody::getRestitution() const {
return restitution; return mRestitution;
} }
// Set the restitution coefficient // Set the restitution coefficient
inline void RigidBody::setRestitution(decimal restitution) throw(std::invalid_argument) { inline void RigidBody::setRestitution(decimal restitution) throw(std::invalid_argument) {
// Check if the restitution coefficient is between 0 and 1 // Check if the restitution coefficient is between 0 and 1
if (restitution >= 0.0 && restitution <= 1.0) { if (restitution >= 0.0 && restitution <= 1.0) {
this->restitution = restitution; mRestitution = restitution;
} }
else { else {
throw std::invalid_argument("Error : the restitution coefficent must be between 0 and 1"); throw std::invalid_argument("Error : the restitution coefficent must be between 0 and 1");
} }
} }
} // End of the ReactPhyscis3D namespace } // End of the ReactPhyscis3D namespace
#endif #endif

View File

@ -38,28 +38,49 @@ namespace reactphysics3d {
struct BroadPhasePair { struct BroadPhasePair {
public: public:
CollisionBody* body1; // Pointer to the first body
CollisionBody* body2; // Pointer to the second body
Vector3 previousSeparatingAxis; // Previous cached separating axis
BroadPhasePair(CollisionBody* body1, CollisionBody* body2); // Constructor // -------------------- Attributes -------------------- //
~BroadPhasePair(); // Destructor
bodyindexpair getBodiesIndexPair() const; // Return the pair of bodies index // Pointer to the first body
CollisionBody* body1;
// Operators // Pointer to the second body
bool operator<(const BroadPhasePair& broadPhasePair2) const; // Smaller than operator CollisionBody* body2;
bool operator>(const BroadPhasePair& broadPhasePair2) const; // Larger than operator
bool operator==(const BroadPhasePair& broadPhasePair2) const; // Equal operator // Previous cached separating axis
bool operator!=(const BroadPhasePair& broadPhasePair2) const; // Not equal operator Vector3 previousSeparatingAxis;
// -------------------- Methods -------------------- //
// Constructor
BroadPhasePair(CollisionBody* body1, CollisionBody* body2);
// Destructor
~BroadPhasePair();
// Return the pair of bodies index
bodyindexpair getBodiesIndexPair() const;
// Smaller than operator
bool operator<(const BroadPhasePair& broadPhasePair2) const;
// Larger than operator
bool operator>(const BroadPhasePair& broadPhasePair2) const;
// Equal operator
bool operator==(const BroadPhasePair& broadPhasePair2) const;
// Not equal operator
bool operator!=(const BroadPhasePair& broadPhasePair2) const;
}; };
// Return the pair of bodies index // Return the pair of bodies index
inline bodyindexpair BroadPhasePair::getBodiesIndexPair() const { inline bodyindexpair BroadPhasePair::getBodiesIndexPair() const {
// Construct the pair of body index // Construct the pair of body index
bodyindexpair indexPair = body1->getID() < body2->getID() ? std::make_pair(body1->getID(), body2->getID()) : bodyindexpair indexPair = body1->getID() < body2->getID() ?
std::make_pair(body2->getID(), body1->getID()); std::make_pair(body1->getID(), body2->getID()) :
std::make_pair(body2->getID(), body1->getID());
assert(indexPair.first != indexPair.second); assert(indexPair.first != indexPair.second);
return indexPair; return indexPair;
} }

View File

@ -46,19 +46,19 @@ using namespace std;
// Constructor // Constructor
CollisionDetection::CollisionDetection(CollisionWorld* world) CollisionDetection::CollisionDetection(CollisionWorld* world)
: world(world), narrowPhaseGJKAlgorithm(memoryPoolContactInfos), : mWorld(world), mNarrowPhaseGJKAlgorithm(mMemoryPoolContactInfos),
narrowPhaseSphereVsSphereAlgorithm(memoryPoolContactInfos) { mNarrowPhaseSphereVsSphereAlgorithm(mMemoryPoolContactInfos) {
// Create the broad-phase algorithm that will be used (Sweep and Prune with AABB) // Create the broad-phase algorithm that will be used (Sweep and Prune with AABB)
broadPhaseAlgorithm = new SweepAndPruneAlgorithm(*this); mBroadPhaseAlgorithm = new SweepAndPruneAlgorithm(*this);
assert(broadPhaseAlgorithm); assert(mBroadPhaseAlgorithm);
} }
// Destructor // Destructor
CollisionDetection::~CollisionDetection() { CollisionDetection::~CollisionDetection() {
// Delete the broad-phase algorithm // Delete the broad-phase algorithm
delete broadPhaseAlgorithm; delete mBroadPhaseAlgorithm;
} }
// Compute the collision detection // Compute the collision detection
@ -90,13 +90,13 @@ bool CollisionDetection::computeCollisionDetection() {
void CollisionDetection::computeBroadPhase() { void CollisionDetection::computeBroadPhase() {
// Notify the broad-phase algorithm about the bodies that have moved since last frame // Notify the broad-phase algorithm about the bodies that have moved since last frame
for (set<CollisionBody*>::iterator it = world->getBodiesBeginIterator(); it != world->getBodiesEndIterator(); it++) { for (set<CollisionBody*>::iterator it = mWorld->getBodiesBeginIterator(); it != mWorld->getBodiesEndIterator(); it++) {
// If the body has moved // If the body has moved
if ((*it)->getHasMoved()) { if ((*it)->getHasMoved()) {
// Notify the broad-phase that the body has moved // Notify the broad-phase that the body has moved
broadPhaseAlgorithm->updateObject(*it, *((*it)->getAABB())); mBroadPhaseAlgorithm->updateObject(*it, *((*it)->getAABB()));
} }
} }
} }
@ -107,7 +107,7 @@ bool CollisionDetection::computeNarrowPhase() {
map<bodyindexpair, BroadPhasePair*>::iterator it; map<bodyindexpair, BroadPhasePair*>::iterator it;
// For each possible collision pair of bodies // For each possible collision pair of bodies
for (it = overlappingPairs.begin(); it != overlappingPairs.end(); it++) { for (it = mOverlappingPairs.begin(); it != mOverlappingPairs.end(); it++) {
ContactInfo* contactInfo = 0; ContactInfo* contactInfo = 0;
BroadPhasePair* pair = (*it).second; BroadPhasePair* pair = (*it).second;
@ -117,7 +117,7 @@ bool CollisionDetection::computeNarrowPhase() {
CollisionBody* const body2 = pair->body2; CollisionBody* const body2 = pair->body2;
// Update the contact cache of the overlapping pair // Update the contact cache of the overlapping pair
world->updateOverlappingPair(pair); mWorld->updateOverlappingPair(pair);
// Select the narrow phase algorithm to use according to the two collision shapes // Select the narrow phase algorithm to use according to the two collision shapes
NarrowPhaseAlgorithm& narrowPhaseAlgorithm = SelectNarrowPhaseAlgorithm(body1->getCollisionShape(), body2->getCollisionShape()); NarrowPhaseAlgorithm& narrowPhaseAlgorithm = SelectNarrowPhaseAlgorithm(body1->getCollisionShape(), body2->getCollisionShape());
@ -132,11 +132,11 @@ bool CollisionDetection::computeNarrowPhase() {
collisionExists = true; collisionExists = true;
// Notify the world about the new narrow-phase contact // Notify the world about the new narrow-phase contact
world->notifyNewContact(pair, contactInfo); mWorld->notifyNewContact(pair, contactInfo);
// Delete and remove the contact info from the memory pool // Delete and remove the contact info from the memory pool
contactInfo->ContactInfo::~ContactInfo(); contactInfo->ContactInfo::~ContactInfo();
memoryPoolContactInfos.freeObject(contactInfo); mMemoryPoolContactInfos.freeObject(contactInfo);
} }
} }
@ -151,14 +151,14 @@ void CollisionDetection::broadPhaseNotifyAddedOverlappingPair(BodyPair* addedPai
bodyindexpair indexPair = addedPair->getBodiesIndexPair(); bodyindexpair indexPair = addedPair->getBodiesIndexPair();
// Create the corresponding broad-phase pair object // Create the corresponding broad-phase pair object
BroadPhasePair* broadPhasePair = new (memoryPoolOverlappingPairs.allocateObject()) BroadPhasePair(addedPair->body1, addedPair->body2); BroadPhasePair* broadPhasePair = new (mMemoryPoolBroadPhasePairs.allocateObject()) BroadPhasePair(addedPair->body1, addedPair->body2);
// Add the pair into the set of overlapping pairs (if not there yet) // Add the pair into the set of overlapping pairs (if not there yet)
pair<map<bodyindexpair, BroadPhasePair*>::iterator, bool> check = overlappingPairs.insert(make_pair(indexPair, broadPhasePair)); pair<map<bodyindexpair, BroadPhasePair*>::iterator, bool> check = mOverlappingPairs.insert(make_pair(indexPair, broadPhasePair));
assert(check.second); assert(check.second);
// Notify the world about the new broad-phase overlapping pair // Notify the world about the new broad-phase overlapping pair
world->notifyAddedOverlappingPair(broadPhasePair); mWorld->notifyAddedOverlappingPair(broadPhasePair);
} }
// Allow the broadphase to notify the collision detection about a removed overlapping pair // Allow the broadphase to notify the collision detection about a removed overlapping pair
@ -168,14 +168,14 @@ void CollisionDetection::broadPhaseNotifyRemovedOverlappingPair(BodyPair* remove
bodyindexpair indexPair = removedPair->getBodiesIndexPair(); bodyindexpair indexPair = removedPair->getBodiesIndexPair();
// Get the broad-phase pair // Get the broad-phase pair
BroadPhasePair* broadPhasePair = overlappingPairs[indexPair]; BroadPhasePair* broadPhasePair = mOverlappingPairs[indexPair];
assert(broadPhasePair); assert(broadPhasePair);
// Notify the world about the removed broad-phase pair // Notify the world about the removed broad-phase pair
world->notifyRemovedOverlappingPair(broadPhasePair); mWorld->notifyRemovedOverlappingPair(broadPhasePair);
// Remove the overlapping pair from the memory pool // Remove the overlapping pair from the memory pool
broadPhasePair->BroadPhasePair::~BroadPhasePair(); broadPhasePair->BroadPhasePair::~BroadPhasePair();
memoryPoolOverlappingPairs.freeObject(broadPhasePair); mMemoryPoolBroadPhasePairs.freeObject(broadPhasePair);
overlappingPairs.erase(indexPair); mOverlappingPairs.erase(indexPair);
} }

View File

@ -59,39 +59,84 @@ class CollisionWorld;
class CollisionDetection { class CollisionDetection {
private : private :
CollisionWorld* world; // Pointer to the physics world
std::map<bodyindexpair, BroadPhasePair*> overlappingPairs; // Broad-phase overlapping pairs of bodies
BroadPhaseAlgorithm* broadPhaseAlgorithm; // Broad-phase algorithm
GJKAlgorithm narrowPhaseGJKAlgorithm; // Narrow-phase GJK algorithm
SphereVsSphereAlgorithm narrowPhaseSphereVsSphereAlgorithm; // Narrow-phase Sphere vs Sphere algorithm
MemoryPool<ContactInfo> memoryPoolContactInfos; // Memory pool for the contact info
MemoryPool<BroadPhasePair> memoryPoolOverlappingPairs; // Memory pool for the overlapping pairs
void computeBroadPhase(); // Compute the broad-phase collision detection // -------------------- Attributes -------------------- //
bool computeNarrowPhase(); // Compute the narrow-phase collision detection
// Pointer to the physics world
CollisionWorld* mWorld;
// Broad-phase overlapping pairs
std::map<bodyindexpair, BroadPhasePair*> mOverlappingPairs;
// Broad-phase algorithm
BroadPhaseAlgorithm* mBroadPhaseAlgorithm;
// Narrow-phase GJK algorithm
GJKAlgorithm mNarrowPhaseGJKAlgorithm;
// Narrow-phase Sphere vs Sphere algorithm
SphereVsSphereAlgorithm mNarrowPhaseSphereVsSphereAlgorithm;
// Memory pool for contactinfo
MemoryPool<ContactInfo> mMemoryPoolContactInfos;
// Memory pool for broad-phase pairs
MemoryPool<BroadPhasePair> mMemoryPoolBroadPhasePairs;
// -------------------- Methods -------------------- //
// Private copy-constructor
CollisionDetection(const CollisionDetection& collisionDetection);
// Private assignment operator
CollisionDetection& operator=(const CollisionDetection& collisionDetection);
// Compute the broad-phase collision detection
void computeBroadPhase();
// Compute the narrow-phase collision detection
bool computeNarrowPhase();
// Select the narrow phase algorithm to use given two collision shapes
NarrowPhaseAlgorithm& SelectNarrowPhaseAlgorithm(CollisionShape* collisionShape1, NarrowPhaseAlgorithm& SelectNarrowPhaseAlgorithm(CollisionShape* collisionShape1,
CollisionShape* collisionShape2); // Select the narrow phase algorithm to use given two collision shapes CollisionShape* collisionShape2);
public : public :
CollisionDetection(CollisionWorld* world); // Constructor
~CollisionDetection(); // Destructor // -------------------- Methods -------------------- //
void addBody(CollisionBody* body); // Add a body to the collision detection // Constructor
void removeBody(CollisionBody* body); // Remove a body from the collision detection CollisionDetection(CollisionWorld* world);
bool computeCollisionDetection(); // Compute the collision detection
void broadPhaseNotifyAddedOverlappingPair(BodyPair* pair); // Allow the broadphase to notify the collision detection about a new overlapping pair // Destructor
void broadPhaseNotifyRemovedOverlappingPair(BodyPair* pair); // Allow the broadphase to notify the collision detection about a removed overlapping pair ~CollisionDetection();
// Add a body to the collision detection
void addBody(CollisionBody* body);
// Remove a body from the collision detection
void removeBody(CollisionBody* body);
// Compute the collision detection
bool computeCollisionDetection();
// Allow the broadphase to notify the collision detection about a new overlapping pair
void broadPhaseNotifyAddedOverlappingPair(BodyPair* pair);
// Allow the broadphase to notify the collision detection about a removed overlapping pair
void broadPhaseNotifyRemovedOverlappingPair(BodyPair* pair);
}; };
// Select the narrow-phase collision algorithm to use given two collision shapes // Select the narrow-phase collision algorithm to use given two collision shapes
inline NarrowPhaseAlgorithm& CollisionDetection::SelectNarrowPhaseAlgorithm(CollisionShape* collisionShape1, CollisionShape* collisionShape2) { inline NarrowPhaseAlgorithm& CollisionDetection::SelectNarrowPhaseAlgorithm(
CollisionShape* collisionShape1, CollisionShape* collisionShape2) {
// Sphere vs Sphere algorithm // Sphere vs Sphere algorithm
if (collisionShape1->getType() == SPHERE && collisionShape2->getType() == SPHERE) { if (collisionShape1->getType() == SPHERE && collisionShape2->getType() == SPHERE) {
return narrowPhaseSphereVsSphereAlgorithm; return mNarrowPhaseSphereVsSphereAlgorithm;
} }
else { // GJK algorithm else { // GJK algorithm
return narrowPhaseGJKAlgorithm; return mNarrowPhaseGJKAlgorithm;
} }
} }
@ -99,14 +144,14 @@ inline NarrowPhaseAlgorithm& CollisionDetection::SelectNarrowPhaseAlgorithm(Coll
inline void CollisionDetection::addBody(CollisionBody* body) { inline void CollisionDetection::addBody(CollisionBody* body) {
// Add the body to the broad-phase // Add the body to the broad-phase
broadPhaseAlgorithm->addObject(body, *(body->getAABB())); mBroadPhaseAlgorithm->addObject(body, *(body->getAABB()));
} }
// Remove a body from the collision detection // Remove a body from the collision detection
inline void CollisionDetection::removeBody(CollisionBody* body) { inline void CollisionDetection::removeBody(CollisionBody* body) {
// Remove the body from the broad-phase // Remove the body from the broad-phase
broadPhaseAlgorithm->removeObject(body); mBroadPhaseAlgorithm->removeObject(body);
} }
} // End of the ReactPhysics3D namespace } // End of the ReactPhysics3D namespace

View File

@ -42,14 +42,38 @@ namespace reactphysics3d {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
struct ContactInfo { struct ContactInfo {
private:
// -------------------- Methods -------------------- //
// Private copy-constructor
ContactInfo(const ContactInfo& contactInfo);
// Private assignment operator
ContactInfo& operator=(const ContactInfo& contactInfo);
public: public:
const Vector3 normal; // Normal vector the the collision contact in world space
const decimal penetrationDepth; // Penetration depth of the contact // -------------------- Attributes -------------------- //
const Vector3 localPoint1; // Contact point of body 1 in local space of body 1
const Vector3 localPoint2; // Contact point of body 2 in local space of body 2 // Normal vector the the collision contact in world space
const Vector3 normal;
// Penetration depth of the contact
const decimal penetrationDepth;
// Contact point of body 1 in local space of body 1
const Vector3 localPoint1;
// Contact point of body 2 in local space of body 2
const Vector3 localPoint2;
// -------------------- Methods -------------------- //
// Constructor
ContactInfo(const Vector3& normal, decimal penetrationDepth, ContactInfo(const Vector3& normal, decimal penetrationDepth,
const Vector3& localPoint1, const Vector3& localPoint2); // Constructor const Vector3& localPoint1, const Vector3& localPoint2);
}; };
} // End of the ReactPhysics3D namespace } // End of the ReactPhysics3D namespace

View File

@ -31,7 +31,7 @@ using namespace reactphysics3d;
// Constructor // Constructor
BroadPhaseAlgorithm::BroadPhaseAlgorithm(CollisionDetection& collisionDetection) BroadPhaseAlgorithm::BroadPhaseAlgorithm(CollisionDetection& collisionDetection)
:pairManager(collisionDetection), collisionDetection(collisionDetection) { :mPairManager(collisionDetection), mCollisionDetection(collisionDetection) {
} }

View File

@ -51,39 +51,68 @@ class CollisionDetection;
-------------------------------------------------------------------- --------------------------------------------------------------------
*/ */
class BroadPhaseAlgorithm { class BroadPhaseAlgorithm {
protected : protected :
PairManager pairManager; // Pair manager that contains the active pairs of bodies
CollisionDetection& collisionDetection; // Reference to the collision detection object // -------------------- Attributes -------------------- //
// Pair manager containing the overlapping pairs
PairManager mPairManager;
// Reference to the collision detection object
CollisionDetection& mCollisionDetection;
// -------------------- Methods -------------------- //
// Private copy-constructor
BroadPhaseAlgorithm(const BroadPhaseAlgorithm& algorithm);
// Private assignment operator
BroadPhaseAlgorithm& operator=(const BroadPhaseAlgorithm& algorithm);
public : public :
BroadPhaseAlgorithm(CollisionDetection& collisionDetection); // Constructor
virtual ~BroadPhaseAlgorithm(); // Destructor // -------------------- Methods -------------------- //
// Constructor
BroadPhaseAlgorithm(CollisionDetection& collisionDetection);
// Destructor
virtual ~BroadPhaseAlgorithm();
// TODO : DELETE THIS METHOD // TODO : DELETE THIS METHOD
uint getNbOverlappingPairs() const; uint getNbOverlappingPairs() const;
virtual void addObject(CollisionBody* body, const AABB& aabb)=0; // Notify the broad-phase about a new object in the world // Notify the broad-phase about a new object in the world
virtual void removeObject(CollisionBody* body)=0; // Notify the broad-phase about an object that has been removed from the world virtual void addObject(CollisionBody* body, const AABB& aabb)=0;
virtual void updateObject(CollisionBody* body, const AABB& aabb)=0; // Notify the broad-phase that the AABB of an object has changed
BodyPair* beginOverlappingPairsPointer() const; // Return a pointer to the first active pair (used to iterate over the active pairs) // Notify the broad-phase about an object that has been removed from the world
BodyPair* endOverlappingPairsPointer() const; // Return a pointer to the last active pair (used to iterate over the active pairs) virtual void removeObject(CollisionBody* body)=0;
// Notify the broad-phase that the AABB of an object has changed
virtual void updateObject(CollisionBody* body, const AABB& aabb)=0;
// Return a pointer to the first active pair (used to iterate over the active pairs)
BodyPair* beginOverlappingPairsPointer() const;
// Return a pointer to the last active pair (used to iterate over the active pairs)
BodyPair* endOverlappingPairsPointer() const;
}; };
// TODO : DELETE THIS METHOD // TODO : DELETE THIS METHOD
inline uint BroadPhaseAlgorithm::getNbOverlappingPairs() const { inline uint BroadPhaseAlgorithm::getNbOverlappingPairs() const {
return pairManager.getNbOverlappingPairs(); return mPairManager.getNbOverlappingPairs();
} }
// Return a pointer to the first active pair (used to iterate over the overlapping pairs) // Return a pointer to the first active pair (used to iterate over the overlapping pairs)
inline BodyPair* BroadPhaseAlgorithm::beginOverlappingPairsPointer() const { inline BodyPair* BroadPhaseAlgorithm::beginOverlappingPairsPointer() const {
return pairManager.beginOverlappingPairsPointer(); return mPairManager.beginOverlappingPairsPointer();
} }
// Return a pointer to the last active pair (used to iterate over the overlapping pairs) // Return a pointer to the last active pair (used to iterate over the overlapping pairs)
inline BodyPair* BroadPhaseAlgorithm::endOverlappingPairsPointer() const { inline BodyPair* BroadPhaseAlgorithm::endOverlappingPairsPointer() const {
return pairManager.endOverlappingPairsPointer(); return mPairManager.endOverlappingPairsPointer();
} }
} // End of reactphysics3d namespace } // End of reactphysics3d namespace

View File

@ -43,16 +43,40 @@ namespace reactphysics3d {
-------------------------------------------------------------------- --------------------------------------------------------------------
*/ */
class NoBroadPhaseAlgorithm : public BroadPhaseAlgorithm { class NoBroadPhaseAlgorithm : public BroadPhaseAlgorithm {
protected : protected :
std::set<CollisionBody*> bodies; // All bodies of the world
// -------------------- Attributes -------------------- //
// All bodies of the world
std::set<CollisionBody*> mBodies;
// -------------------- Methods -------------------- //
// Private copy-constructor
NoBroadPhaseAlgorithm(const NoBroadPhaseAlgorithm& algorithm);
// Private assignment operator
NoBroadPhaseAlgorithm& operator=(const NoBroadPhaseAlgorithm& algorithm);
public : public :
NoBroadPhaseAlgorithm(CollisionDetection& collisionDetection); // Constructor
virtual ~NoBroadPhaseAlgorithm(); // Destructor // -------------------- Methods -------------------- //
// Constructor
NoBroadPhaseAlgorithm(CollisionDetection& collisionDetection);
// Destructor
virtual ~NoBroadPhaseAlgorithm();
virtual void addObject(CollisionBody* body, const AABB& aabb); // Notify the broad-phase about a new object in the world // Notify the broad-phase about a new object in the world
virtual void removeObject(CollisionBody* body); // Notify the broad-phase about an object that has been removed from the world virtual void addObject(CollisionBody* body, const AABB& aabb);
virtual void updateObject(CollisionBody* body, const AABB& aabb); // Notify the broad-phase that the AABB of an object has changed
// Notify the broad-phase about an object that has been removed from the world
virtual void removeObject(CollisionBody* body);
// Notify the broad-phase that the AABB of an object has changed
virtual void updateObject(CollisionBody* body, const AABB& aabb);
}; };
@ -62,31 +86,31 @@ inline void NoBroadPhaseAlgorithm::addObject(CollisionBody* body, const AABB& aa
std::cout << "New body in broadphase with id=" << body->getID() << std::endl; std::cout << "New body in broadphase with id=" << body->getID() << std::endl;
// For each body that is already in the world // For each body that is already in the world
for (std::set<CollisionBody*>::iterator it = bodies.begin(); it != bodies.end(); ++it) { for (std::set<CollisionBody*>::iterator it = mBodies.begin(); it != mBodies.end(); ++it) {
// Add an overlapping pair with the new body // Add an overlapping pair with the new body
pairManager.addPair(*it, body); mPairManager.addPair(*it, body);
} }
// Add the new body into the list of bodies // Add the new body into the list of bodies
bodies.insert(body); mBodies.insert(body);
} }
// Notify the broad-phase about an object that has been removed from the world // Notify the broad-phase about an object that has been removed from the world
inline void NoBroadPhaseAlgorithm::removeObject(CollisionBody* body) { inline void NoBroadPhaseAlgorithm::removeObject(CollisionBody* body) {
// For each body that is in the world // For each body that is in the world
for (std::set<CollisionBody*>::iterator it = bodies.begin(); it != bodies.end(); ++it) { for (std::set<CollisionBody*>::iterator it = mBodies.begin(); it != mBodies.end(); ++it) {
if ((*it)->getID() != body->getID()) { if ((*it)->getID() != body->getID()) {
// Remove the overlapping pair with the new body // Remove the overlapping pair with the new body
pairManager.removePair((*it)->getID(), body->getID()); mPairManager.removePair((*it)->getID(), body->getID());
} }
} }
// Remove the body from the broad-phase // Remove the body from the broad-phase
bodies.erase(body); mBodies.erase(body);
} }
// Notify the broad-phase that the AABB of an object has changed // Notify the broad-phase that the AABB of an object has changed

View File

@ -34,22 +34,23 @@ using namespace reactphysics3d;
bodyindex PairManager::INVALID_INDEX = std::numeric_limits<reactphysics3d::bodyindex>::max(); bodyindex PairManager::INVALID_INDEX = std::numeric_limits<reactphysics3d::bodyindex>::max();
// Constructor of PairManager // Constructor of PairManager
PairManager::PairManager(CollisionDetection& collisionDetection) : collisionDetection(collisionDetection) { PairManager::PairManager(CollisionDetection& collisionDetection)
hashTable = 0; : mCollisionDetection(collisionDetection) {
overlappingPairs = 0; mHashTable = 0;
offsetNextPair = 0; mOverlappingPairs = 0;
nbOverlappingPairs = 0; mOffsetNextPair = 0;
hashMask = 0; mNbOverlappingPairs = 0;
nbElementsHashTable = 0; mHashMask = 0;
mNbElementsHashTable = 0;
} }
// Destructor of PairManager // Destructor of PairManager
PairManager::~PairManager() { PairManager::~PairManager() {
// Release the allocated memory // Release the allocated memory
free(offsetNextPair); free(mOffsetNextPair);
free(overlappingPairs); free(mOverlappingPairs);
free(hashTable); free(mHashTable);
} }
// Add a pair of bodies in the pair manager and returns a pointer to // Add a pair of bodies in the pair manager and returns a pointer to
@ -66,7 +67,7 @@ BodyPair* PairManager::addPair(CollisionBody* body1, CollisionBody* body2) {
bodyindex id2 = body2->getID(); bodyindex id2 = body2->getID();
// Compute the hash value of the two bodies // Compute the hash value of the two bodies
uint hashValue = computeHashBodies(id1, id2) & hashMask; uint hashValue = computeHashBodies(id1, id2) & mHashMask;
// Try to find the pair in the current overlapping pairs. // Try to find the pair in the current overlapping pairs.
BodyPair* pair = findPairWithHashValue(id1, id2, hashValue); BodyPair* pair = findPairWithHashValue(id1, id2, hashValue);
@ -78,31 +79,31 @@ BodyPair* PairManager::addPair(CollisionBody* body1, CollisionBody* body2) {
} }
// If we need to allocate more pairs in the set of overlapping pairs // If we need to allocate more pairs in the set of overlapping pairs
if (nbOverlappingPairs >= nbElementsHashTable) { if (mNbOverlappingPairs >= mNbElementsHashTable) {
// Increase the size of the hash table (always a power of two) // Increase the size of the hash table (always a power of two)
nbElementsHashTable = computeNextPowerOfTwo(nbOverlappingPairs + 1); mNbElementsHashTable = computeNextPowerOfTwo(mNbOverlappingPairs + 1);
// Compute the new hash mask with the new hash size // Compute the new hash mask with the new hash size
hashMask = nbElementsHashTable - 1; mHashMask = mNbElementsHashTable - 1;
// Reallocate more pairs // Reallocate more pairs
reallocatePairs(); reallocatePairs();
// Compute the new hash value (using the new hash size and hash mask) // Compute the new hash value (using the new hash size and hash mask)
hashValue = computeHashBodies(id1, id2) & hashMask; hashValue = computeHashBodies(id1, id2) & mHashMask;
} }
// Create the new overlapping pair // Create the new overlapping pair
BodyPair* newPair = &overlappingPairs[nbOverlappingPairs]; BodyPair* newPair = &mOverlappingPairs[mNbOverlappingPairs];
newPair->body1 = body1; newPair->body1 = body1;
newPair->body2 = body2; newPair->body2 = body2;
// Put the new pair as the initial pair with this hash value // Put the new pair as the initial pair with this hash value
offsetNextPair[nbOverlappingPairs] = hashTable[hashValue]; mOffsetNextPair[mNbOverlappingPairs] = mHashTable[hashValue];
hashTable[hashValue] = nbOverlappingPairs++; mHashTable[hashValue] = mNbOverlappingPairs++;
// Notify the collision detection about this new overlapping pair // Notify the collision detection about this new overlapping pair
collisionDetection.broadPhaseNotifyAddedOverlappingPair(newPair); mCollisionDetection.broadPhaseNotifyAddedOverlappingPair(newPair);
// Return a pointer to the new created pair // Return a pointer to the new created pair
return newPair; return newPair;
@ -116,7 +117,7 @@ bool PairManager::removePair(bodyindex id1, bodyindex id2) {
sortIDs(id1, id2); sortIDs(id1, id2);
// Compute the hash value of the pair to remove // Compute the hash value of the pair to remove
const uint hashValue = computeHashBodies(id1, id2) & hashMask; const uint hashValue = computeHashBodies(id1, id2) & mHashMask;
// Find the pair to remove // Find the pair to remove
BodyPair* pair = findPairWithHashValue(id1, id2, hashValue); BodyPair* pair = findPairWithHashValue(id1, id2, hashValue);
@ -130,7 +131,7 @@ bool PairManager::removePair(bodyindex id1, bodyindex id2) {
assert(pair->body2->getID() == id2); assert(pair->body2->getID() == id2);
// Notify the collision detection about this removed overlapping pair // Notify the collision detection about this removed overlapping pair
collisionDetection.broadPhaseNotifyRemovedOverlappingPair(pair); mCollisionDetection.broadPhaseNotifyRemovedOverlappingPair(pair);
// Remove the pair from the set of overlapping pairs // Remove the pair from the set of overlapping pairs
removePairWithHashValue(id1, id2, hashValue, computePairOffset(pair)); removePairWithHashValue(id1, id2, hashValue, computePairOffset(pair));
@ -142,18 +143,19 @@ bool PairManager::removePair(bodyindex id1, bodyindex id2) {
} }
// Internal method to remove a pair from the set of overlapping pair // Internal method to remove a pair from the set of overlapping pair
void PairManager::removePairWithHashValue(bodyindex id1, bodyindex id2, luint hashValue, bodyindex indexPair) { void PairManager::removePairWithHashValue(bodyindex id1, bodyindex id2, luint hashValue,
bodyindex indexPair) {
// Get the initial offset of the pairs with // Get the initial offset of the pairs with
// the corresponding hash value // the corresponding hash value
bodyindex offset = hashTable[hashValue]; bodyindex offset = mHashTable[hashValue];
assert(offset != INVALID_INDEX); assert(offset != INVALID_INDEX);
// Look for the pair in the set of overlapping pairs // Look for the pair in the set of overlapping pairs
bodyindex previousPair = INVALID_INDEX; bodyindex previousPair = INVALID_INDEX;
while(offset != indexPair) { while(offset != indexPair) {
previousPair = offset; previousPair = offset;
offset = offsetNextPair[offset]; offset = mOffsetNextPair[offset];
} }
// If the pair was the first one with this hash // If the pair was the first one with this hash
@ -161,22 +163,22 @@ void PairManager::removePairWithHashValue(bodyindex id1, bodyindex id2, luint ha
if (previousPair == INVALID_INDEX) { if (previousPair == INVALID_INDEX) {
// Replace the pair to remove in the // Replace the pair to remove in the
// hash table by the next one // hash table by the next one
hashTable[hashValue] = offsetNextPair[indexPair]; mHashTable[hashValue] = mOffsetNextPair[indexPair];
} }
else { // If the pair was not the first one else { // If the pair was not the first one
// Replace the pair to remove in the // Replace the pair to remove in the
// hash table by the next one // hash table by the next one
assert(offsetNextPair[previousPair] == indexPair); assert(mOffsetNextPair[previousPair] == indexPair);
offsetNextPair[previousPair] = offsetNextPair[indexPair]; mOffsetNextPair[previousPair] = mOffsetNextPair[indexPair];
} }
const bodyindex indexLastPair = nbOverlappingPairs - 1; const bodyindex indexLastPair = mNbOverlappingPairs - 1;
// If the pair to remove is the last one in the list // If the pair to remove is the last one in the list
if (indexPair == indexLastPair) { if (indexPair == indexLastPair) {
// We simply decrease the number of overlapping pairs // We simply decrease the number of overlapping pairs
nbOverlappingPairs--; mNbOverlappingPairs--;
} }
else { // If the pair to remove is in the middle of the list else { // If the pair to remove is in the middle of the list
@ -184,11 +186,12 @@ void PairManager::removePairWithHashValue(bodyindex id1, bodyindex id2, luint ha
// now free because of the pair we want to remove // now free because of the pair we want to remove
// Get the last pair // Get the last pair
const BodyPair* lastPair = &overlappingPairs[indexLastPair]; const BodyPair* lastPair = &mOverlappingPairs[indexLastPair];
const uint lastPairHashValue = computeHashBodies(lastPair->body1->getID(), lastPair->body2->getID()) & hashMask; const uint lastPairHashValue = computeHashBodies(lastPair->body1->getID(),
lastPair->body2->getID()) & mHashMask;
// Compute the initial offset of the last pair // Compute the initial offset of the last pair
bodyindex offset = hashTable[lastPairHashValue]; bodyindex offset = mHashTable[lastPairHashValue];
assert(offset != INVALID_INDEX); assert(offset != INVALID_INDEX);
// Go through the pairs with the same hash value // Go through the pairs with the same hash value
@ -196,29 +199,29 @@ void PairManager::removePairWithHashValue(bodyindex id1, bodyindex id2, luint ha
bodyindex previous = INVALID_INDEX; bodyindex previous = INVALID_INDEX;
while(offset != indexLastPair) { while(offset != indexLastPair) {
previous = offset; previous = offset;
offset = offsetNextPair[offset]; offset = mOffsetNextPair[offset];
} }
// If the last pair is not the first one with this hash value // If the last pair is not the first one with this hash value
if (previous != INVALID_INDEX) { if (previous != INVALID_INDEX) {
// Remove the offset of the last pair in the "nextOffset" array // Remove the offset of the last pair in the "nextOffset" array
assert(offsetNextPair[previous] == indexLastPair); assert(mOffsetNextPair[previous] == indexLastPair);
offsetNextPair[previous] = offsetNextPair[indexLastPair]; mOffsetNextPair[previous] = mOffsetNextPair[indexLastPair];
} }
else { // If the last pair is the first offset with this hash value else { // If the last pair is the first offset with this hash value
// Remove the offset of the last pair in the "nextOffset" array // Remove the offset of the last pair in the "nextOffset" array
hashTable[lastPairHashValue] = offsetNextPair[indexLastPair]; mHashTable[lastPairHashValue] = mOffsetNextPair[indexLastPair];
} }
// Replace the pair to remove by the last pair in // Replace the pair to remove by the last pair in
// the overlapping pairs array // the overlapping pairs array
overlappingPairs[indexPair] = overlappingPairs[indexLastPair]; mOverlappingPairs[indexPair] = mOverlappingPairs[indexLastPair];
offsetNextPair[indexPair] = hashTable[lastPairHashValue]; mOffsetNextPair[indexPair] = mHashTable[lastPairHashValue];
hashTable[lastPairHashValue] = indexPair; mHashTable[lastPairHashValue] = indexPair;
nbOverlappingPairs--; mNbOverlappingPairs--;
} }
} }
@ -226,9 +229,9 @@ void PairManager::removePairWithHashValue(bodyindex id1, bodyindex id2, luint ha
BodyPair* PairManager::lookForAPair(bodyindex id1, bodyindex id2, luint hashValue) const { BodyPair* PairManager::lookForAPair(bodyindex id1, bodyindex id2, luint hashValue) const {
// Look for the pair in the set of overlapping pairs // Look for the pair in the set of overlapping pairs
bodyindex offset = hashTable[hashValue]; bodyindex offset = mHashTable[hashValue];
while (offset != INVALID_INDEX && isDifferentPair(overlappingPairs[offset], id1, id2)) { while (offset != INVALID_INDEX && isDifferentPair(mOverlappingPairs[offset], id1, id2)) {
offset = offsetNextPair[offset]; offset = mOffsetNextPair[offset];
} }
// If the pair has not been found in the overlapping pairs // If the pair has not been found in the overlapping pairs
@ -237,50 +240,51 @@ BodyPair* PairManager::lookForAPair(bodyindex id1, bodyindex id2, luint hashValu
return 0; return 0;
} }
assert(offset < nbOverlappingPairs); assert(offset < mNbOverlappingPairs);
// The pair has been found in the set of overlapping pairs, then // The pair has been found in the set of overlapping pairs, then
// we return a pointer to it // we return a pointer to it
return &overlappingPairs[offset]; return &mOverlappingPairs[offset];
} }
// Reallocate more pairs // Reallocate more pairs
void PairManager::reallocatePairs() { void PairManager::reallocatePairs() {
// Reallocate the hash table and initialize it // Reallocate the hash table and initialize it
free(hashTable); free(mHashTable);
hashTable = (bodyindex*) malloc(nbElementsHashTable * sizeof(bodyindex)); mHashTable = (bodyindex*) malloc(mNbElementsHashTable * sizeof(bodyindex));
assert(hashTable); assert(mHashTable);
for (bodyindex i=0; i<nbElementsHashTable; i++) { for (bodyindex i=0; i<mNbElementsHashTable; i++) {
hashTable[i] = INVALID_INDEX; mHashTable[i] = INVALID_INDEX;
} }
// Reallocate the overlapping pairs // Reallocate the overlapping pairs
BodyPair* newOverlappingPairs = (BodyPair*) malloc(nbElementsHashTable * sizeof(BodyPair)); BodyPair* newOverlappingPairs = (BodyPair*) malloc(mNbElementsHashTable * sizeof(BodyPair));
bodyindex* newOffsetNextPair = (bodyindex*) malloc(nbElementsHashTable * sizeof(bodyindex)); bodyindex* newOffsetNextPair = (bodyindex*) malloc(mNbElementsHashTable * sizeof(bodyindex));
assert(newOverlappingPairs); assert(newOverlappingPairs);
assert(newOffsetNextPair); assert(newOffsetNextPair);
// If there is already some overlapping pairs // If there is already some overlapping pairs
if (nbOverlappingPairs) { if (mNbOverlappingPairs) {
// Copy the pairs to the new location // Copy the pairs to the new location
memcpy(newOverlappingPairs, overlappingPairs, nbOverlappingPairs * sizeof(BodyPair)); memcpy(newOverlappingPairs, mOverlappingPairs, mNbOverlappingPairs * sizeof(BodyPair));
} }
// Recompute the hash table with the new hash values // Recompute the hash table with the new hash values
for (bodyindex i=0; i<nbOverlappingPairs; i++) { for (bodyindex i=0; i<mNbOverlappingPairs; i++) {
const uint newHashValue = computeHashBodies(overlappingPairs[i].body1->getID(), overlappingPairs[i].body2->getID()) & hashMask; const uint newHashValue = computeHashBodies(mOverlappingPairs[i].body1->getID(),
newOffsetNextPair[i] = hashTable[newHashValue]; mOverlappingPairs[i].body2->getID()) & mHashMask;
hashTable[newHashValue] = i; newOffsetNextPair[i] = mHashTable[newHashValue];
mHashTable[newHashValue] = i;
} }
// Delete the old pairs // Delete the old pairs
free(offsetNextPair); free(mOffsetNextPair);
free(overlappingPairs); free(mOverlappingPairs);
// Replace by the new data // Replace by the new data
overlappingPairs = newOverlappingPairs; mOverlappingPairs = newOverlappingPairs;
offsetNextPair = newOffsetNextPair; mOffsetNextPair = newOffsetNextPair;
} }

View File

@ -43,6 +43,7 @@ class CollisionDetection;
struct BodyPair { struct BodyPair {
public: public:
CollisionBody* body1; // Pointer to the first body CollisionBody* body1; // Pointer to the first body
CollisionBody* body2; // Pointer to the second body CollisionBody* body2; // Pointer to the second body
@ -50,8 +51,10 @@ struct BodyPair {
bodyindexpair getBodiesIndexPair() const { bodyindexpair getBodiesIndexPair() const {
// Construct the pair of body index // Construct the pair of body index
bodyindexpair indexPair = body1->getID() < body2->getID() ? std::make_pair(body1->getID(), body2->getID()) : bodyindexpair indexPair = body1->getID() < body2->getID() ?
std::make_pair(body2->getID(), body1->getID()); std::make_pair(body1->getID(), body2->getID()) :
std::make_pair(body2->getID(), body1->getID());
assert(indexPair.first != indexPair.second); assert(indexPair.first != indexPair.second);
return indexPair; return indexPair;
} }
@ -66,54 +69,134 @@ struct BodyPair {
-------------------------------------------------------------------- --------------------------------------------------------------------
*/ */
class PairManager { class PairManager {
private : private :
bodyindex nbElementsHashTable; // Number of elements in the hash table
uint hashMask; // Hash mask for the hash function // -------------------- Attributes -------------------- //
bodyindex nbOverlappingPairs; // Number of overlapping pairs
bodyindex* hashTable; // Hash table that contains the offset of the first pair of the list of // Number of elements in the hash table
// pairs with the same hash value in the "overlappingPairs" array bodyindex mNbElementsHashTable;
bodyindex* offsetNextPair; // Array that contains for each offset, the offset of the next pair with
// the same hash value // Hash mask for the hash function
// for a given same hash value uint mHashMask;
BodyPair* overlappingPairs; // Array that contains the currently active pairs
static bodyindex INVALID_INDEX; // Invalid ID // Number of overlapping pairs
CollisionDetection& collisionDetection; // Reference to the collision detection bodyindex mNbOverlappingPairs;
// Hash table that contains the offset of the first pair of the list of
// pairs with the same hash value in the "overlappingPairs" array
bodyindex* mHashTable;
// Array that contains for each offset, the offset of the next pair with
// the same hash value for a given same hash value
bodyindex* mOffsetNextPair;
// Array that contains the overlapping pairs
BodyPair* mOverlappingPairs;
// Invalid ID
static bodyindex INVALID_INDEX;
// Reference to the collision detection
CollisionDetection& mCollisionDetection;
void sortBodiesUsingID(CollisionBody*& body1, CollisionBody*& body2) const; // Sort the bodies according to their IDs (smallest ID first) // -------------------- Methods -------------------- //
void sortIDs(bodyindex& id1, bodyindex& id2) const; // Sort the IDs (smallest ID first)
bool isDifferentPair(const BodyPair& pair1, bodyindex pair2ID1, // Private copy-constructor
bodyindex pair2ID2) const; // Return true if pair1 and pair2 are the same PairManager(const PairManager& pairManager);
uint computeHashBodies(uint id1, uint id2) const; // Compute the hash value of two bodies using their IDs
int computeHash32Bits(int key) const; // This method returns an hash value for a 32 bits key // Private assignment operator
luint computeNextPowerOfTwo(luint number) const; // Return the next power of two PairManager& operator=(const PairManager& pairManager);
void reallocatePairs(); // Reallocate memory for more pairs
void shrinkMemory(); // Shrink the allocated memory // Sort the bodies according to their IDs (smallest ID first)
bodyindex computePairOffset(const BodyPair* pair) const; // Compute the offset of a given pair void sortBodiesUsingID(CollisionBody*& body1, CollisionBody*& body2) const;
BodyPair* lookForAPair(bodyindex id1, bodyindex id2,
luint hashValue) const; // Look for a pair in the set of overlapping pairs // Sort the IDs (smallest ID first)
BodyPair* findPairWithHashValue(bodyindex id1, bodyindex id2, void sortIDs(bodyindex& id1, bodyindex& id2) const;
luint hashValue) const; // Find a pair given two body IDs and an hash value
// Return true if pair1 and pair2 are the same
bool isDifferentPair(const BodyPair& pair1, bodyindex pair2ID1, bodyindex pair2ID2) const;
// Compute the hash value of two bodies using their IDs
uint computeHashBodies(uint id1, uint id2) const;
// This method returns an hash value for a 32 bits key
int computeHash32Bits(int key) const;
// Return the next power of two
luint computeNextPowerOfTwo(luint number) const;
// Reallocate memory for more pairs
void reallocatePairs();
// Shrink the allocated memory
void shrinkMemory();
// Compute the offset of a given pair
bodyindex computePairOffset(const BodyPair* pair) const;
// Look for a pair in the set of overlapping pairs
BodyPair* lookForAPair(bodyindex id1, bodyindex id2, luint hashValue) const;
// Find a pair given two body IDs and an hash value
BodyPair* findPairWithHashValue(bodyindex id1, bodyindex id2, luint hashValue) const;
// Remove a pair from the set of active pair
void removePairWithHashValue(bodyindex id1, bodyindex id2, luint hashValue, void removePairWithHashValue(bodyindex id1, bodyindex id2, luint hashValue,
bodyindex indexPair); // Remove a pair from the set of active pair bodyindex indexPair);
public : public :
PairManager(CollisionDetection& collisionDetection); // Constructor
~PairManager(); // Destructor // ----- Methods ----- //
// Constructor
PairManager(CollisionDetection& collisionDetection);
// Destructor
~PairManager();
bodyindex getNbOverlappingPairs() const; // Return the number of active pairs // Return the number of active pairs
BodyPair* addPair(CollisionBody* body1, CollisionBody* body2); // Add a pair of bodies in the pair manager bodyindex getNbOverlappingPairs() const;
bool removePair(bodyindex id1, bodyindex id2); // Remove a pair of bodies from the pair manager
BodyPair* findPair(bodyindex id1, bodyindex id2) const; // Find a pair given two body IDs // Add a pair of bodies in the pair manager
BodyPair* beginOverlappingPairsPointer() const; // Return a pointer to the first overlapping pair (used to iterate over the active pairs) BodyPair* addPair(CollisionBody* body1, CollisionBody* body2);
BodyPair* endOverlappingPairsPointer() const; // Return a pointer to the last overlapping pair (used to iterate over the active pairs)
void registerAddedOverlappingPairCallback(void (CollisionDetection::*callbackFunction) (const BodyPair* addedActivePair)); // Register a callback function (using a function pointer) that will be called when a new overlapping pair is added in the pair manager // Remove a pair of bodies from the pair manager
void unregisterAddedOverlappingPairCallback(); // Unregister the callback function that will be called when a new active pair is added in the pair manager bool removePair(bodyindex id1, bodyindex id2);
void registerRemovedOverlappingPairCallback(void (CollisionDetection::*callbackFunction) (const BodyPair* removedActivePair)); // Register a callback function (using a function pointer) that will be called when an overlapping pair is removed from the pair manager
void unregisterRemovedOverlappingPairCallback(); // Unregister a callback function that will be called when a active pair is removed from the pair manager // Find a pair given two body IDs
BodyPair* findPair(bodyindex id1, bodyindex id2) const;
// Return a pointer to the first overlapping pair (used to
// iterate over the active pairs)
BodyPair* beginOverlappingPairsPointer() const;
// Return a pointer to the last overlapping pair (used to
// iterate over the active pairs)
BodyPair* endOverlappingPairsPointer() const;
// Register a callback function (using a function pointer) that will be
// called when a new overlapping pair is added in the pair manager
void registerAddedOverlappingPairCallback(void (CollisionDetection::*callbackFunction)
(const BodyPair* addedActivePair));
// Unregister the callback function that will be called
// when a new active pair is added in the pair manager
void unregisterAddedOverlappingPairCallback();
// Register a callback function (using a function pointer)
// that will be called when an overlapping pair is removed from the pair manager
void registerRemovedOverlappingPairCallback(void (CollisionDetection::*callbackFunction)
(const BodyPair* removedActivePair));
// Unregister a callback function that will be called
// when a active pair is removed from the pair manager
void unregisterRemovedOverlappingPairCallback();
}; };
// Return the number of overlapping pairs // Return the number of overlapping pairs
inline bodyindex PairManager::getNbOverlappingPairs() const { inline bodyindex PairManager::getNbOverlappingPairs() const {
return nbOverlappingPairs; return mNbOverlappingPairs;
} }
// Compute the hash value of two bodies // Compute the hash value of two bodies
@ -122,7 +205,8 @@ inline uint PairManager::computeHashBodies(uint id1, uint id2) const {
} }
// Return true if pair1 and pair2 are the same // Return true if pair1 and pair2 are the same
inline bool PairManager::isDifferentPair(const BodyPair& pair1, bodyindex pair2ID1, bodyindex pair2ID2) const { inline bool PairManager::isDifferentPair(const BodyPair& pair1, bodyindex pair2ID1,
bodyindex pair2ID2) const {
return (pair2ID1 != pair1.body1->getID() || pair2ID2 != pair1.body2->getID()); return (pair2ID1 != pair1.body1->getID() || pair2ID2 != pair1.body2->getID());
} }
@ -176,13 +260,13 @@ inline int PairManager::computeHash32Bits(int key) const {
inline BodyPair* PairManager::findPair(bodyindex id1, bodyindex id2) const { inline BodyPair* PairManager::findPair(bodyindex id1, bodyindex id2) const {
// Check if the hash table has been allocated yet // Check if the hash table has been allocated yet
if (!hashTable) return 0; if (!mHashTable) return 0;
// Sort the IDs // Sort the IDs
sortIDs(id1, id2); sortIDs(id1, id2);
// Compute the hash value of the pair to find // Compute the hash value of the pair to find
uint hashValue = computeHashBodies(id1, id2) & hashMask; uint hashValue = computeHashBodies(id1, id2) & mHashMask;
// Look for the pair in the set of overlapping pairs // Look for the pair in the set of overlapping pairs
lookForAPair(id1, id2, hashValue); lookForAPair(id1, id2, hashValue);
@ -191,10 +275,11 @@ inline BodyPair* PairManager::findPair(bodyindex id1, bodyindex id2) const {
// Find a pair given two body IDs and an hash value // Find a pair given two body IDs and an hash value
// This internal version is used to avoid computing multiple times in the // This internal version is used to avoid computing multiple times in the
// caller method // caller method
inline BodyPair* PairManager::findPairWithHashValue(bodyindex id1, bodyindex id2, luint hashValue) const { inline BodyPair* PairManager::findPairWithHashValue(bodyindex id1, bodyindex id2,
luint hashValue) const {
// Check if the hash table has been allocated yet // Check if the hash table has been allocated yet
if (!hashTable) return 0; if (!mHashTable) return 0;
// Look for the pair in the set of overlapping pairs // Look for the pair in the set of overlapping pairs
return lookForAPair(id1, id2, hashValue); return lookForAPair(id1, id2, hashValue);
@ -204,34 +289,34 @@ inline BodyPair* PairManager::findPairWithHashValue(bodyindex id1, bodyindex id2
inline void PairManager::shrinkMemory() { inline void PairManager::shrinkMemory() {
// Check if the allocated memory can be reduced // Check if the allocated memory can be reduced
const bodyindex correctNbElementsHashTable = computeNextPowerOfTwo(nbOverlappingPairs); const bodyindex correctNbElementsHashTable = computeNextPowerOfTwo(mNbOverlappingPairs);
if (nbElementsHashTable == correctNbElementsHashTable) return; if (mNbElementsHashTable == correctNbElementsHashTable) return;
// Reduce the allocated memory // Reduce the allocated memory
nbElementsHashTable = correctNbElementsHashTable; mNbElementsHashTable = correctNbElementsHashTable;
hashMask = nbElementsHashTable - 1; mHashMask = mNbElementsHashTable - 1;
reallocatePairs(); reallocatePairs();
} }
// Compute the offset of a given pair in the array of overlapping pairs // Compute the offset of a given pair in the array of overlapping pairs
inline bodyindex PairManager::computePairOffset(const BodyPair* pair) const { inline bodyindex PairManager::computePairOffset(const BodyPair* pair) const {
return ((bodyindex)((size_t(pair) - size_t(overlappingPairs))) / sizeof(BodyPair)); return ((bodyindex)((size_t(pair) - size_t(mOverlappingPairs))) / sizeof(BodyPair));
} }
// Return a pointer to the first overlapping pair (used to iterate over the overlapping pairs) or // Return a pointer to the first overlapping pair (used to iterate over the overlapping pairs) or
// returns 0 if there is no overlapping pairs. // returns 0 if there is no overlapping pairs.
inline BodyPair* PairManager::beginOverlappingPairsPointer() const { inline BodyPair* PairManager::beginOverlappingPairsPointer() const {
return &overlappingPairs[0]; return &mOverlappingPairs[0];
} }
// Return a pointer to the last overlapping pair (used to iterate over the overlapping pairs) or // Return a pointer to the last overlapping pair (used to iterate over the overlapping pairs) or
// returns 0 if there is no overlapping pairs. // returns 0 if there is no overlapping pairs.
inline BodyPair* PairManager::endOverlappingPairsPointer() const { inline BodyPair* PairManager::endOverlappingPairsPointer() const {
if (nbOverlappingPairs > 0) { if (mNbOverlappingPairs > 0) {
return &overlappingPairs[nbOverlappingPairs-1]; return &mOverlappingPairs[mNbOverlappingPairs-1];
} }
else { else {
return &overlappingPairs[0]; return &mOverlappingPairs[0];
} }
} }

View File

@ -47,20 +47,20 @@ AABBInt::AABBInt(const AABB& aabb) {
// Constructor // Constructor
SweepAndPruneAlgorithm::SweepAndPruneAlgorithm(CollisionDetection& collisionDetection) SweepAndPruneAlgorithm::SweepAndPruneAlgorithm(CollisionDetection& collisionDetection)
:BroadPhaseAlgorithm(collisionDetection) { :BroadPhaseAlgorithm(collisionDetection) {
boxes = 0; mBoxes = 0;
endPoints[0] = 0; mEndPoints[0] = 0;
endPoints[1] = 0; mEndPoints[1] = 0;
endPoints[2] = 0; mEndPoints[2] = 0;
nbBoxes = 0; mNbBoxes = 0;
nbMaxBoxes = 0; mNbMaxBoxes = 0;
} }
// Destructor // Destructor
SweepAndPruneAlgorithm::~SweepAndPruneAlgorithm() { SweepAndPruneAlgorithm::~SweepAndPruneAlgorithm() {
delete[] boxes; delete[] mBoxes;
delete[] endPoints[0]; delete[] mEndPoints[0];
delete[] endPoints[1]; delete[] mEndPoints[1];
delete[] endPoints[2]; delete[] mEndPoints[2];
} }
// Notify the broad-phase about a new object in the world // Notify the broad-phase about a new object in the world
@ -71,50 +71,50 @@ void SweepAndPruneAlgorithm::addObject(CollisionBody* body, const AABB& aabb) {
// If the index of the first free box is valid (means that // If the index of the first free box is valid (means that
// there is a bucket in the middle of the array that doesn't // there is a bucket in the middle of the array that doesn't
// contain a box anymore because it has been removed) // contain a box anymore because it has been removed)
if (!freeBoxIndices.empty()) { if (!mFreeBoxIndices.empty()) {
boxIndex = freeBoxIndices.back(); boxIndex = mFreeBoxIndices.back();
freeBoxIndices.pop_back(); mFreeBoxIndices.pop_back();
} }
else { else {
// If the array boxes and end-points arrays are full // If the array boxes and end-points arrays are full
if (nbBoxes == nbMaxBoxes) { if (mNbBoxes == mNbMaxBoxes) {
// Resize the arrays to make them larger // Resize the arrays to make them larger
resizeArrays(); resizeArrays();
} }
boxIndex = nbBoxes; boxIndex = mNbBoxes;
} }
// Move the maximum limit end-point two elements further // Move the maximum limit end-point two elements further
// at the end-points array in all three axis // at the end-points array in all three axis
const luint nbSentinels = 2; const luint nbSentinels = 2;
const luint indexLimitEndPoint = 2 * nbBoxes + nbSentinels - 1; const luint indexLimitEndPoint = 2 * mNbBoxes + nbSentinels - 1;
for (uint axis=0; axis<3; axis++) { for (uint axis=0; axis<3; axis++) {
EndPoint* maxLimitEndPoint = &endPoints[axis][indexLimitEndPoint]; EndPoint* maxLimitEndPoint = &mEndPoints[axis][indexLimitEndPoint];
assert(endPoints[axis][0].boxID == INVALID_INDEX && endPoints[axis][0].isMin == true); assert(mEndPoints[axis][0].boxID == INVALID_INDEX && mEndPoints[axis][0].isMin == true);
assert(maxLimitEndPoint->boxID == INVALID_INDEX && maxLimitEndPoint->isMin == false); assert(maxLimitEndPoint->boxID == INVALID_INDEX && maxLimitEndPoint->isMin == false);
EndPoint* newMaxLimitEndPoint = &endPoints[axis][indexLimitEndPoint + 2]; EndPoint* newMaxLimitEndPoint = &mEndPoints[axis][indexLimitEndPoint + 2];
newMaxLimitEndPoint->setValues(maxLimitEndPoint->boxID, maxLimitEndPoint->isMin, maxLimitEndPoint->value); newMaxLimitEndPoint->setValues(maxLimitEndPoint->boxID, maxLimitEndPoint->isMin, maxLimitEndPoint->value);
} }
// Create a new box // Create a new box
BoxAABB* box = &boxes[boxIndex]; BoxAABB* box = &mBoxes[boxIndex];
box->body = body; box->body = body;
const uint minEndPointValue = encodeFloatIntoInteger(DECIMAL_LARGEST - 2.0); const uint minEndPointValue = encodeFloatIntoInteger(DECIMAL_LARGEST - 2.0);
const uint maxEndPointValue = encodeFloatIntoInteger(DECIMAL_LARGEST - 1.0); const uint maxEndPointValue = encodeFloatIntoInteger(DECIMAL_LARGEST - 1.0);
for (uint axis=0; axis<3; axis++) { for (uint axis=0; axis<3; axis++) {
box->min[axis] = indexLimitEndPoint; box->min[axis] = indexLimitEndPoint;
box->max[axis] = indexLimitEndPoint + 1; box->max[axis] = indexLimitEndPoint + 1;
EndPoint* minimumEndPoint = &endPoints[axis][box->min[axis]]; EndPoint* minimumEndPoint = &mEndPoints[axis][box->min[axis]];
minimumEndPoint->setValues(body->getID(), true, minEndPointValue); minimumEndPoint->setValues(body->getID(), true, minEndPointValue);
EndPoint* maximumEndPoint = &endPoints[axis][box->max[axis]]; EndPoint* maximumEndPoint = &mEndPoints[axis][box->max[axis]];
maximumEndPoint->setValues(body->getID(), false, maxEndPointValue); maximumEndPoint->setValues(body->getID(), false, maxEndPointValue);
} }
// Add the body pointer to box index mapping // Add the body pointer to box index mapping
mapBodyToBoxIndex.insert(pair<CollisionBody*, bodyindex>(body, boxIndex)); mMapBodyToBoxIndex.insert(pair<CollisionBody*, bodyindex>(body, boxIndex));
nbBoxes++; mNbBoxes++;
// Call the update method to put the end-points of the new AABB at the // Call the update method to put the end-points of the new AABB at the
// correct position in the array. This will also create the overlapping // correct position in the array. This will also create the overlapping
@ -134,14 +134,14 @@ void SweepAndPruneAlgorithm::removeObject(CollisionBody* body) {
updateObject(body, aabb); updateObject(body, aabb);
// Get the corresponding box // Get the corresponding box
bodyindex boxIndex = mapBodyToBoxIndex[body]; bodyindex boxIndex = mMapBodyToBoxIndex[body];
BoxAABB* box = &boxes[boxIndex]; BoxAABB* box = &mBoxes[boxIndex];
// Add the box index into the list of free indices // Add the box index into the list of free indices
freeBoxIndices.push_back(boxIndex); mFreeBoxIndices.push_back(boxIndex);
mapBodyToBoxIndex.erase(body); mMapBodyToBoxIndex.erase(body);
nbBoxes--; mNbBoxes--;
} }
// Notify the broad-phase that the AABB of an object has changed // Notify the broad-phase that the AABB of an object has changed
@ -151,8 +151,8 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
AABBInt aabbInt(aabb); AABBInt aabbInt(aabb);
// Get the corresponding box // Get the corresponding box
bodyindex boxIndex = mapBodyToBoxIndex[body]; bodyindex boxIndex = mMapBodyToBoxIndex[body];
BoxAABB* box = &boxes[boxIndex]; BoxAABB* box = &mBoxes[boxIndex];
// Current axis // Current axis
for (uint axis=0; axis<3; axis++) { for (uint axis=0; axis<3; axis++) {
@ -162,7 +162,7 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
const uint otherAxis2 = (1 << otherAxis1) & 3; const uint otherAxis2 = (1 << otherAxis1) & 3;
// Get the starting end-point of the current axis // Get the starting end-point of the current axis
EndPoint* startEndPointsCurrentAxis = endPoints[axis]; EndPoint* startEndPointsCurrentAxis = mEndPoints[axis];
// -------- Update the minimum end-point ------------// // -------- Update the minimum end-point ------------//
@ -184,7 +184,7 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
const luint savedEndPointIndex = indexEndPoint; const luint savedEndPointIndex = indexEndPoint;
while ((--currentMinEndPoint)->value > limit) { while ((--currentMinEndPoint)->value > limit) {
BoxAABB* id1 = &boxes[currentMinEndPoint->boxID]; BoxAABB* id1 = &mBoxes[currentMinEndPoint->boxID];
const bool isMin = currentMinEndPoint->isMin; const bool isMin = currentMinEndPoint->isMin;
// If it's a maximum end-point // If it's a maximum end-point
@ -198,7 +198,7 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
testIntersect1DSortedAABBs(*id1, aabbInt, startEndPointsCurrentAxis, axis)) { testIntersect1DSortedAABBs(*id1, aabbInt, startEndPointsCurrentAxis, axis)) {
// Add an overlapping pair to the pair manager // Add an overlapping pair to the pair manager
pairManager.addPair(body, id1->body); mPairManager.addPair(body, id1->body);
} }
} }
@ -214,10 +214,10 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
// Update the current minimum endpoint that we are moving // Update the current minimum endpoint that we are moving
if (savedEndPointIndex != indexEndPoint) { if (savedEndPointIndex != indexEndPoint) {
if (savedEndPoint.isMin) { if (savedEndPoint.isMin) {
boxes[savedEndPoint.boxID].min[axis] = indexEndPoint; mBoxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
} }
else { else {
boxes[savedEndPoint.boxID].max[axis] = indexEndPoint; mBoxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
} }
startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint; startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint;
@ -235,7 +235,7 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
// For each end-point between the current position of the minimum // For each end-point between the current position of the minimum
// end-point and the new position of the minimum end-point // end-point and the new position of the minimum end-point
while ((++currentMinEndPoint)->value < limit) { while ((++currentMinEndPoint)->value < limit) {
BoxAABB* id1 = &boxes[currentMinEndPoint->boxID]; BoxAABB* id1 = &mBoxes[currentMinEndPoint->boxID];
const bool isMin = currentMinEndPoint->isMin; const bool isMin = currentMinEndPoint->isMin;
// If it's a maximum end-point // If it's a maximum end-point
@ -247,7 +247,7 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
if (testIntersect2D(*box, *id1, otherAxis1, otherAxis2)) { if (testIntersect2D(*box, *id1, otherAxis1, otherAxis2)) {
// Remove the pair from the pair manager // Remove the pair from the pair manager
pairManager.removePair(body->getID(), id1->body->getID()); mPairManager.removePair(body->getID(), id1->body->getID());
} }
} }
@ -263,10 +263,10 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
// Update the current minimum endpoint that we are moving // Update the current minimum endpoint that we are moving
if (savedEndPointIndex != indexEndPoint) { if (savedEndPointIndex != indexEndPoint) {
if (savedEndPoint.isMin) { if (savedEndPoint.isMin) {
boxes[savedEndPoint.boxID].min[axis] = indexEndPoint; mBoxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
} }
else { else {
boxes[savedEndPoint.boxID].max[axis] = indexEndPoint; mBoxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
} }
startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint; startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint;
@ -295,7 +295,7 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
while ((++currentMaxEndPoint)->value < limit) { while ((++currentMaxEndPoint)->value < limit) {
// Get the next end-point // Get the next end-point
BoxAABB* id1 = &boxes[currentMaxEndPoint->boxID]; BoxAABB* id1 = &mBoxes[currentMaxEndPoint->boxID];
const bool isMin = currentMaxEndPoint->isMin; const bool isMin = currentMaxEndPoint->isMin;
// If it's a maximum end-point // If it's a maximum end-point
@ -309,7 +309,7 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
testIntersect1DSortedAABBs(*id1, aabbInt, startEndPointsCurrentAxis,axis)) { testIntersect1DSortedAABBs(*id1, aabbInt, startEndPointsCurrentAxis,axis)) {
// Add an overlapping pair to the pair manager // Add an overlapping pair to the pair manager
pairManager.addPair(body, id1->body); mPairManager.addPair(body, id1->body);
} }
} }
@ -325,10 +325,10 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
// Update the current minimum endpoint that we are moving // Update the current minimum endpoint that we are moving
if (savedEndPointIndex != indexEndPoint) { if (savedEndPointIndex != indexEndPoint) {
if (savedEndPoint.isMin) { if (savedEndPoint.isMin) {
boxes[savedEndPoint.boxID].min[axis] = indexEndPoint; mBoxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
} }
else { else {
boxes[savedEndPoint.boxID].max[axis] = indexEndPoint; mBoxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
} }
startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint; startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint;
@ -344,7 +344,7 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
// For each end-point between the current position of the maximum // For each end-point between the current position of the maximum
// end-point and the new position of the maximum end-point // end-point and the new position of the maximum end-point
while ((--currentMaxEndPoint)->value > limit) { while ((--currentMaxEndPoint)->value > limit) {
BoxAABB* id1 = &boxes[currentMaxEndPoint->boxID]; BoxAABB* id1 = &mBoxes[currentMaxEndPoint->boxID];
const bool isMin = currentMaxEndPoint->isMin; const bool isMin = currentMaxEndPoint->isMin;
// If it's a minimum end-point // If it's a minimum end-point
@ -356,7 +356,7 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
if (testIntersect2D(*box, *id1, otherAxis1, otherAxis2)) { if (testIntersect2D(*box, *id1, otherAxis1, otherAxis2)) {
// Remove the pair from the pair manager // Remove the pair from the pair manager
pairManager.removePair(body->getID(), id1->body->getID()); mPairManager.removePair(body->getID(), id1->body->getID());
} }
} }
@ -372,10 +372,10 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
// Update the current minimum endpoint that we are moving // Update the current minimum endpoint that we are moving
if (savedEndPointIndex != indexEndPoint) { if (savedEndPointIndex != indexEndPoint) {
if (savedEndPoint.isMin) { if (savedEndPoint.isMin) {
boxes[savedEndPoint.boxID].min[axis] = indexEndPoint; mBoxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
} }
else { else {
boxes[savedEndPoint.boxID].max[axis] = indexEndPoint; mBoxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
} }
startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint; startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint;
@ -389,8 +389,8 @@ void SweepAndPruneAlgorithm::resizeArrays() {
// New number of boxes in the array // New number of boxes in the array
const luint nbSentinels = 2; const luint nbSentinels = 2;
const luint newNbMaxBoxes = nbMaxBoxes ? 2 * nbMaxBoxes : 100; const luint newNbMaxBoxes = mNbMaxBoxes ? 2 * mNbMaxBoxes : 100;
const luint nbEndPoints = nbBoxes * 2 + nbSentinels; const luint nbEndPoints = mNbBoxes * 2 + nbSentinels;
const luint newNbEndPoints = newNbMaxBoxes * 2 + nbSentinels; const luint newNbEndPoints = newNbMaxBoxes * 2 + nbSentinels;
// Allocate memory for the new boxes and end-points arrays // Allocate memory for the new boxes and end-points arrays
@ -405,14 +405,14 @@ void SweepAndPruneAlgorithm::resizeArrays() {
assert(newEndPointsZArray); assert(newEndPointsZArray);
// If the arrays were not empty before // If the arrays were not empty before
if (nbBoxes > 0) { if (mNbBoxes > 0) {
// Copy the data in the old arrays into the new one // Copy the data in the old arrays into the new one
memcpy(newBoxesArray, boxes, sizeof(BoxAABB) * nbBoxes); memcpy(newBoxesArray, mBoxes, sizeof(BoxAABB) * mNbBoxes);
size_t nbBytesNewEndPoints = sizeof(EndPoint) * nbEndPoints; size_t nbBytesNewEndPoints = sizeof(EndPoint) * nbEndPoints;
memcpy(newEndPointsXArray, endPoints[0], nbBytesNewEndPoints); memcpy(newEndPointsXArray, mEndPoints[0], nbBytesNewEndPoints);
memcpy(newEndPointsYArray, endPoints[1], nbBytesNewEndPoints); memcpy(newEndPointsYArray, mEndPoints[1], nbBytesNewEndPoints);
memcpy(newEndPointsZArray, endPoints[2], nbBytesNewEndPoints); memcpy(newEndPointsZArray, mEndPoints[2], nbBytesNewEndPoints);
} }
else { // If the arrays were empty else { // If the arrays were empty
@ -428,16 +428,16 @@ void SweepAndPruneAlgorithm::resizeArrays() {
} }
// Delete the old arrays // Delete the old arrays
delete[] boxes; delete[] mBoxes;
delete[] endPoints[0]; delete[] mEndPoints[0];
delete[] endPoints[1]; delete[] mEndPoints[1];
delete[] endPoints[2]; delete[] mEndPoints[2];
// Assign the pointer to the new arrays // Assign the pointer to the new arrays
boxes = newBoxesArray; mBoxes = newBoxesArray;
endPoints[0] = newEndPointsXArray; mEndPoints[0] = newEndPointsXArray;
endPoints[1] = newEndPointsYArray; mEndPoints[1] = newEndPointsYArray;
endPoints[2] = newEndPointsZArray; mEndPoints[2] = newEndPointsZArray;
nbMaxBoxes = newNbMaxBoxes; mNbMaxBoxes = newNbMaxBoxes;
} }

View File

@ -39,40 +39,43 @@ namespace reactphysics3d {
// EndPoint structure that represent an end-point of an AABB // EndPoint structure that represent an end-point of an AABB
// on one of the three x,y or z axis // on one of the three x,y or z axis
struct EndPoint { struct EndPoint {
public: public:
// TODO : Use uint here
bodyindex boxID; // ID of the AABB box corresponding to this end-point bodyindex boxID; // ID of the AABB box corresponding to this end-point
bool isMin; // True if the end-point is a minimum end-point of a box bool isMin; // True if the end-point is a minimum end-point of a box
uint value; // Value (one dimension coordinate) of the end-point uint value; // Value (one dimension coordinate) of the end-point
void setValues(bodyindex boxID, bool isMin, uint value); // Set the values of the endpoint // Set the values of the endpoint
}; void setValues(bodyindex boxID, bool isMin, uint value) {
this->boxID = boxID;
// Set the values of the endpoint this->isMin = isMin;
inline void EndPoint::setValues(bodyindex boxID, bool isMin, uint value) { this->value = value;
this->boxID = boxID; }
this->isMin = isMin; };
this->value = value;
}
// Structure BoxAABB that represents an AABB in the // Structure BoxAABB that represents an AABB in the
// Sweep-And-Prune algorithm // Sweep-And-Prune algorithm
struct BoxAABB { struct BoxAABB {
public: public:
bodyindex min[3]; // Index of the three minimum end-points of the AABB over the axis X, Y and Z
bodyindex max[3]; // Index of the three maximum end-points of the AABB over the axis X, Y and Z bodyindex min[3]; // Index of the 3 minimum end-points of the AABB over the x,y,z axis
bodyindex max[3]; // Index of the 3 maximum end-points of the AABB over the x,y,z axis
CollisionBody* body; // Body that corresponds to the owner of the AABB CollisionBody* body; // Body that corresponds to the owner of the AABB
}; };
// Structure AABBInt // Structure AABBInt
// Axis-Aligned Bounding box with integer coordinates // Axis-Aligned Bounding box with integer coordinates
struct AABBInt { struct AABBInt {
public: public:
uint min[3]; // Minimum values on the three axis uint min[3]; // Minimum values on the three axis
uint max[3]; // Maximum values on the three axis uint max[3]; // Maximum values on the three axis
AABBInt(const AABB& aabb); // Constructor // Constructor
AABBInt(const AABB& aabb);
}; };
@ -87,29 +90,70 @@ struct AABBInt {
class SweepAndPruneAlgorithm : public BroadPhaseAlgorithm { class SweepAndPruneAlgorithm : public BroadPhaseAlgorithm {
protected : protected :
static bodyindex INVALID_INDEX; // Invalid array index
// -------------------- Attributes -------------------- //
// Invalid array index
static bodyindex INVALID_INDEX;
// Array that contains all the AABB boxes of the broad-phase
BoxAABB* mBoxes;
// Array of end-points on the three axis
EndPoint* mEndPoints[3];
// Number of AABB boxes in the broad-phase
bodyindex mNbBoxes;
// Max number of boxes in the boxes array
bodyindex mNbMaxBoxes;
// Indices that are not used by any boxes
std::vector<bodyindex> mFreeBoxIndices;
// Map a body pointer to a box index
std::map<CollisionBody*,bodyindex> mMapBodyToBoxIndex;
BoxAABB* boxes; // Array that contains all the AABB boxes of the broad-phase // -------------------- Methods -------------------- //
EndPoint* endPoints[3]; // Array of end-points on the three axis
bodyindex nbBoxes; // Number of AABB boxes in the broad-phase // Private copy-constructor
bodyindex nbMaxBoxes; // Maximum number of boxes in the boxes array SweepAndPruneAlgorithm(const SweepAndPruneAlgorithm& algorithm);
std::vector<bodyindex> freeBoxIndices; // Indices that are not used by any boxes
std::map<CollisionBody*, bodyindex> mapBodyToBoxIndex; // Map a body pointer to its box index // Private assignment operator
SweepAndPruneAlgorithm& operator=(const SweepAndPruneAlgorithm& algorithm);
void resizeArrays(); // Resize the boxes and end-points arrays when it's full
void addPair(CollisionBody* body1, CollisionBody* body2); // Add an overlapping pair of AABBS // Resize the boxes and end-points arrays when it's full
void resizeArrays();
// Add an overlapping pair of AABBS
void addPair(CollisionBody* body1, CollisionBody* body2);
// Check for 1D box intersection
bool testIntersect1DSortedAABBs(const BoxAABB& box1, const AABBInt& box2, bool testIntersect1DSortedAABBs(const BoxAABB& box1, const AABBInt& box2,
const EndPoint* const baseEndPoint, uint axis) const; // Check for 1D box intersection const EndPoint* const baseEndPoint, uint axis) const;
// Check for 2D box intersection
bool testIntersect2D(const BoxAABB& box1, const BoxAABB& box2, bool testIntersect2D(const BoxAABB& box1, const BoxAABB& box2,
luint axis1, uint axis2) const; // Check for 2D box intersection luint axis1, uint axis2) const;
public : public :
SweepAndPruneAlgorithm(CollisionDetection& collisionDetection); // Constructor
virtual ~SweepAndPruneAlgorithm(); // Destructor
virtual void addObject(CollisionBody* body, const AABB& aabb); // Notify the broad-phase about a new object in the world // -------------------- Methods -------------------- //
virtual void removeObject(CollisionBody* body); // Notify the broad-phase about a object that has been removed from the world
virtual void updateObject(CollisionBody* body, const AABB& aabb); // Notify the broad-phase that the AABB of an object has changed // Constructor
SweepAndPruneAlgorithm(CollisionDetection& mCollisionDetection);
// Destructor
virtual ~SweepAndPruneAlgorithm();
// Notify the broad-phase about a new object in the world
virtual void addObject(CollisionBody* body, const AABB& aabb);
// Notify the broad-phase about a object that has been removed from the world
virtual void removeObject(CollisionBody* body);
// Notify the broad-phase that the AABB of an object has changed
virtual void updateObject(CollisionBody* body, const AABB& aabb);
}; };
// Encode a floating value into a integer value in order to // Encode a floating value into a integer value in order to
@ -135,8 +179,10 @@ inline uint encodeFloatIntoInteger(float number) {
// Check for 1D box intersection between two boxes that are sorted on the // Check for 1D box intersection between two boxes that are sorted on the
// given axis. Therefore, only one test is necessary here. We know that the // given axis. Therefore, only one test is necessary here. We know that the
// minimum of box1 cannot be larger that the maximum of box2 on the axis. // minimum of box1 cannot be larger that the maximum of box2 on the axis.
inline bool SweepAndPruneAlgorithm::testIntersect1DSortedAABBs(const BoxAABB& box1, const AABBInt& box2, inline bool SweepAndPruneAlgorithm::testIntersect1DSortedAABBs(const BoxAABB& box1,
const EndPoint* const endPointsArray, uint axis) const { const AABBInt& box2,
const EndPoint* const endPointsArray,
uint axis) const {
return !(endPointsArray[box1.max[axis]].value < box2.min[axis]); return !(endPointsArray[box1.max[axis]].value < box2.min[axis]);
} }

View File

@ -33,7 +33,7 @@ using namespace reactphysics3d;
// Constructor // Constructor
EPAAlgorithm::EPAAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos) EPAAlgorithm::EPAAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos)
: memoryPoolContactInfos(memoryPoolContactInfos) { : mMemoryPoolContactInfos(memoryPoolContactInfos) {
} }
@ -45,7 +45,8 @@ EPAAlgorithm::~EPAAlgorithm() {
// Decide if the origin is in the tetrahedron // Decide if the origin is in the tetrahedron
// Return 0 if the origin is in the tetrahedron and return the number (1,2,3 or 4) of // Return 0 if the origin is in the tetrahedron and return the number (1,2,3 or 4) of
// the vertex that is wrong if the origin is not in the tetrahedron // the vertex that is wrong if the origin is not in the tetrahedron
int EPAAlgorithm::isOriginInTetrahedron(const Vector3& p1, const Vector3& p2, const Vector3& p3, const Vector3& p4) const { int EPAAlgorithm::isOriginInTetrahedron(const Vector3& p1, const Vector3& p2,
const Vector3& p3, const Vector3& p4) const {
// Check vertex 1 // Check vertex 1
Vector3 normal1 = (p2-p1).cross(p3-p1); Vector3 normal1 = (p2-p1).cross(p3-p1);
@ -81,20 +82,28 @@ int EPAAlgorithm::isOriginInTetrahedron(const Vector3& p1, const Vector3& p2, co
// intersect. An initial simplex that contains origin has been computed with // intersect. An initial simplex that contains origin has been computed with
// GJK algorithm. The EPA Algorithm will extend this simplex polytope to find // GJK algorithm. The EPA Algorithm will extend this simplex polytope to find
// the correct penetration depth // the correct penetration depth
bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, const CollisionShape* collisionShape1, const Transform& transform1, bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simplex,
const CollisionShape* collisionShape2, const Transform& transform2, const CollisionShape* collisionShape1,
const Transform& transform1,
const CollisionShape* collisionShape2,
const Transform& transform2,
Vector3& v, ContactInfo*& contactInfo) { Vector3& v, ContactInfo*& contactInfo) {
Vector3 suppPointsA[MAX_SUPPORT_POINTS]; // Support points of object A in local coordinates
Vector3 suppPointsB[MAX_SUPPORT_POINTS]; // Support points of object B in local coordinates
Vector3 points[MAX_SUPPORT_POINTS]; // Current points
TrianglesStore triangleStore; // Store the triangles
TriangleEPA* triangleHeap[MAX_FACETS]; // Heap that contains the face candidate of the EPA algorithm
// Transform a point from local space of body 2 to local space of body 1 (the GJK algorithm is done in local space of body 1) Vector3 suppPointsA[MAX_SUPPORT_POINTS]; // Support points of object A in local coordinates
Vector3 suppPointsB[MAX_SUPPORT_POINTS]; // Support points of object B in local coordinates
Vector3 points[MAX_SUPPORT_POINTS]; // Current points
TrianglesStore triangleStore; // Store the triangles
TriangleEPA* triangleHeap[MAX_FACETS]; // Heap that contains the face
// candidate of the EPA algorithm
// Transform a point from local space of body 2 to local
// space of body 1 (the GJK algorithm is done in local space of body 1)
Transform body2Tobody1 = transform1.inverse() * transform2; Transform body2Tobody1 = transform1.inverse() * transform2;
// Matrix that transform a direction from local space of body 1 into local space of body 2 // Matrix that transform a direction from local
Matrix3x3 rotateToBody2 = transform2.getOrientation().getMatrix().getTranspose() * transform1.getOrientation().getMatrix(); // space of body 1 into local space of body 2
Matrix3x3 rotateToBody2 = transform2.getOrientation().getMatrix().getTranspose() *
transform1.getOrientation().getMatrix();
// Get the simplex computed previously by the GJK algorithm // Get the simplex computed previously by the GJK algorithm
unsigned int nbVertices = simplex.getSimplex(suppPointsA, suppPointsB, points); unsigned int nbVertices = simplex.getSimplex(suppPointsA, suppPointsB, points);
@ -113,8 +122,9 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
// The EPA algorithm. // The EPA algorithm.
switch(nbVertices) { switch(nbVertices) {
case 1: case 1:
// Only one point in the simplex (which should be the origin). We have a touching contact // Only one point in the simplex (which should be the origin).
// with zero penetration depth. We drop that kind of contact. Therefore, we return false // We have a touching contact with zero penetration depth.
// We drop that kind of contact. Therefore, we return false
return false; return false;
case 2: { case 2: {
@ -149,17 +159,23 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
// Compute the support point in the direction of v1 // Compute the support point in the direction of v1
suppPointsA[2] = collisionShape1->getLocalSupportPoint(v1, OBJECT_MARGIN); suppPointsA[2] = collisionShape1->getLocalSupportPoint(v1, OBJECT_MARGIN);
suppPointsB[2] = body2Tobody1 * collisionShape2->getLocalSupportPoint(rotateToBody2 * (-v1), OBJECT_MARGIN); suppPointsB[2] = body2Tobody1 * collisionShape2->getLocalSupportPoint(rotateToBody2 *
(-v1),
OBJECT_MARGIN);
points[2] = suppPointsA[2] - suppPointsB[2]; points[2] = suppPointsA[2] - suppPointsB[2];
// Compute the support point in the direction of v2 // Compute the support point in the direction of v2
suppPointsA[3] = collisionShape1->getLocalSupportPoint(v2, OBJECT_MARGIN); suppPointsA[3] = collisionShape1->getLocalSupportPoint(v2, OBJECT_MARGIN);
suppPointsB[3] = body2Tobody1 * collisionShape2->getLocalSupportPoint(rotateToBody2 * (-v2), OBJECT_MARGIN); suppPointsB[3] = body2Tobody1 * collisionShape2->getLocalSupportPoint(rotateToBody2 *
(-v2),
OBJECT_MARGIN);
points[3] = suppPointsA[3] - suppPointsB[3]; points[3] = suppPointsA[3] - suppPointsB[3];
// Compute the support point in the direction of v3 // Compute the support point in the direction of v3
suppPointsA[4] = collisionShape1->getLocalSupportPoint(v3, OBJECT_MARGIN); suppPointsA[4] = collisionShape1->getLocalSupportPoint(v3, OBJECT_MARGIN);
suppPointsB[4] = body2Tobody1 * collisionShape2->getLocalSupportPoint(rotateToBody2 * (-v3), OBJECT_MARGIN); suppPointsB[4] = body2Tobody1 * collisionShape2->getLocalSupportPoint(rotateToBody2 *
(-v3),
OBJECT_MARGIN);
points[4] = suppPointsA[4] - suppPointsB[4]; points[4] = suppPointsA[4] - suppPointsB[4];
// Now we have an hexahedron (two tetrahedron glued together). We can simply keep the // Now we have an hexahedron (two tetrahedron glued together). We can simply keep the
@ -173,7 +189,8 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
suppPointsB[1] = suppPointsB[4]; suppPointsB[1] = suppPointsB[4];
points[1] = points[4]; points[1] = points[4];
} }
else if (isOriginInTetrahedron(points[1], points[2], points[3], points[4]) == 0) { // If the origin is in the tetrahedron of points 1, 2, 3, 4 // If the origin is in the tetrahedron of points 1, 2, 3, 4
else if (isOriginInTetrahedron(points[1], points[2], points[3], points[4]) == 0) {
// We use the point 4 instead of point 0 for the initial tetrahedron // We use the point 4 instead of point 0 for the initial tetrahedron
suppPointsA[0] = suppPointsA[4]; suppPointsA[0] = suppPointsA[4];
suppPointsB[0] = suppPointsB[4]; suppPointsB[0] = suppPointsB[4];
@ -209,7 +226,8 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
// If the constructed tetrahedron is not correct // If the constructed tetrahedron is not correct
if (!(face0 && face1 && face2 && face3 && face0->getDistSquare() > 0.0 && if (!(face0 && face1 && face2 && face3 && face0->getDistSquare() > 0.0 &&
face1->getDistSquare() > 0.0 && face2->getDistSquare() > 0.0 && face3->getDistSquare() > 0.0)) { face1->getDistSquare() > 0.0 && face2->getDistSquare() > 0.0 &&
face3->getDistSquare() > 0.0)) {
return false; return false;
} }
@ -254,10 +272,13 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
// Compute the two new vertices to obtain a hexahedron // Compute the two new vertices to obtain a hexahedron
suppPointsA[3] = collisionShape1->getLocalSupportPoint(n, OBJECT_MARGIN); suppPointsA[3] = collisionShape1->getLocalSupportPoint(n, OBJECT_MARGIN);
suppPointsB[3] = body2Tobody1 * collisionShape2->getLocalSupportPoint(rotateToBody2 * (-n), OBJECT_MARGIN); suppPointsB[3] = body2Tobody1 * collisionShape2->getLocalSupportPoint(rotateToBody2 *
(-n),
OBJECT_MARGIN);
points[3] = suppPointsA[3] - suppPointsB[3]; points[3] = suppPointsA[3] - suppPointsB[3];
suppPointsA[4] = collisionShape1->getLocalSupportPoint(-n, OBJECT_MARGIN); suppPointsA[4] = collisionShape1->getLocalSupportPoint(-n, OBJECT_MARGIN);
suppPointsB[4] = body2Tobody1 * collisionShape2->getLocalSupportPoint(rotateToBody2 * n, OBJECT_MARGIN); suppPointsB[4] = body2Tobody1 * collisionShape2->getLocalSupportPoint(rotateToBody2 * n,
OBJECT_MARGIN);
points[4] = suppPointsA[4] - suppPointsB[4]; points[4] = suppPointsA[4] - suppPointsB[4];
// Construct the triangle faces // Construct the triangle faces
@ -314,7 +335,7 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
triangle = triangleHeap[0]; triangle = triangleHeap[0];
// Get the next candidate face (the face closest to the origin) // Get the next candidate face (the face closest to the origin)
std::pop_heap(&triangleHeap[0], &triangleHeap[nbTriangles], triangleComparison); std::pop_heap(&triangleHeap[0], &triangleHeap[nbTriangles], mTriangleComparison);
nbTriangles--; nbTriangles--;
// If the candidate face in the heap is not obsolete // If the candidate face in the heap is not obsolete
@ -325,9 +346,13 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
break; break;
} }
// Compute the support point of the Minkowski difference (A-B) in the closest point direction // Compute the support point of the Minkowski
suppPointsA[nbVertices] = collisionShape1->getLocalSupportPoint(triangle->getClosestPoint(), OBJECT_MARGIN); // difference (A-B) in the closest point direction
suppPointsB[nbVertices] = body2Tobody1 * collisionShape2->getLocalSupportPoint(rotateToBody2 * (-triangle->getClosestPoint()), OBJECT_MARGIN); suppPointsA[nbVertices] = collisionShape1->getLocalSupportPoint(
triangle->getClosestPoint(), OBJECT_MARGIN);
suppPointsB[nbVertices] = body2Tobody1 * collisionShape2->getLocalSupportPoint(
rotateToBody2 * (-triangle->getClosestPoint()),
OBJECT_MARGIN);
points[nbVertices] = suppPointsA[nbVertices] - suppPointsB[nbVertices]; points[nbVertices] = suppPointsA[nbVertices] - suppPointsB[nbVertices];
int indexNewVertex = nbVertices; int indexNewVertex = nbVertices;
@ -377,7 +402,9 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
assert(penetrationDepth > 0.0); assert(penetrationDepth > 0.0);
// Create the contact info object // Create the contact info object
contactInfo = new (memoryPoolContactInfos.allocateObject()) ContactInfo(normal, penetrationDepth, pALocal, pBLocal); contactInfo = new (mMemoryPoolContactInfos.allocateObject()) ContactInfo(normal,
penetrationDepth,
pALocal, pBLocal);
return true; return true;
} }

View File

@ -72,35 +72,67 @@ class TriangleComparison {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class EPAAlgorithm { class EPAAlgorithm {
private: private:
MemoryPool<ContactInfo>& memoryPoolContactInfos; // Reference to the memory pool for contact infos
TriangleComparison triangleComparison; // Triangle comparison operator // -------------------- Attributes -------------------- //
// Reference to the memory pool
MemoryPool<ContactInfo>& mMemoryPoolContactInfos;
// Triangle comparison operator
TriangleComparison mTriangleComparison;
void addFaceCandidate(TriangleEPA* triangle, TriangleEPA** heap, // -------------------- Methods -------------------- //
uint& nbTriangles, decimal upperBoundSquarePenDepth); // Add a triangle face in the candidate triangle heap
// Private copy-constructor
EPAAlgorithm(const EPAAlgorithm& algorithm);
// Private assignment operator
EPAAlgorithm& operator=(const EPAAlgorithm& algorithm);
// Add a triangle face in the candidate triangle heap
void addFaceCandidate(TriangleEPA* triangle, TriangleEPA** heap, uint& nbTriangles,
decimal upperBoundSquarePenDepth);
// Decide if the origin is in the tetrahedron
int isOriginInTetrahedron(const Vector3& p1, const Vector3& p2, int isOriginInTetrahedron(const Vector3& p1, const Vector3& p2,
const Vector3& p3, const Vector3& p4) const; // Decide if the origin is in the tetrahedron const Vector3& p3, const Vector3& p4) const;
public: public:
EPAAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos); // Constructor
~EPAAlgorithm(); // Destructor
bool computePenetrationDepthAndContactPoints(Simplex simplex, const CollisionShape* collisionShape1, const Transform& transform1, // -------------------- Methods -------------------- //
const CollisionShape* collisionShape2, const Transform& transform2,
Vector3& v, ContactInfo*& contactInfo); // Compute the penetration depth with EPA algorithm // Constructor
EPAAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos);
// Destructor
~EPAAlgorithm();
// Compute the penetration depth with EPA algorithm
bool computePenetrationDepthAndContactPoints(const Simplex& simplex,
const CollisionShape* collisionShape1,
const Transform& transform1,
const CollisionShape* collisionShape2,
const Transform& transform2,
Vector3& v, ContactInfo*& contactInfo);
}; };
// Add a triangle face in the candidate triangle heap in the EPA algorithm // Add a triangle face in the candidate triangle heap in the EPA algorithm
inline void EPAAlgorithm::addFaceCandidate(TriangleEPA* triangle, TriangleEPA** heap, inline void EPAAlgorithm::addFaceCandidate(TriangleEPA* triangle, TriangleEPA** heap,
uint& nbTriangles, decimal upperBoundSquarePenDepth) { uint& nbTriangles, decimal upperBoundSquarePenDepth) {
// If the closest point of the affine hull of triangle points is internal to the triangle and // If the closest point of the affine hull of triangle
// if the distance of the closest point from the origin is at most the penetration depth upper bound // points is internal to the triangle and if the distance
if (triangle->isClosestPointInternalToTriangle() && triangle->getDistSquare() <= upperBoundSquarePenDepth) { // of the closest point from the origin is at most the
// penetration depth upper bound
if (triangle->isClosestPointInternalToTriangle() &&
triangle->getDistSquare() <= upperBoundSquarePenDepth) {
// Add the triangle face to the list of candidates // Add the triangle face to the list of candidates
heap[nbTriangles] = triangle; heap[nbTriangles] = triangle;
nbTriangles++; nbTriangles++;
std::push_heap(&heap[0], &heap[nbTriangles], triangleComparison); std::push_heap(&heap[0], &heap[nbTriangles], mTriangleComparison);
} }
} }

View File

@ -40,10 +40,16 @@ EdgeEPA::EdgeEPA() {
// Constructor // Constructor
EdgeEPA::EdgeEPA(TriangleEPA* ownerTriangle, int index) EdgeEPA::EdgeEPA(TriangleEPA* ownerTriangle, int index)
: ownerTriangle(ownerTriangle), index(index) { : mOwnerTriangle(ownerTriangle), mIndex(index) {
assert(index >= 0 && index < 3); assert(index >= 0 && index < 3);
} }
// Copy-constructor
EdgeEPA::EdgeEPA(const EdgeEPA& edge) {
mOwnerTriangle = edge.mOwnerTriangle;
mIndex = edge.mIndex;
}
// Destructor // Destructor
EdgeEPA::~EdgeEPA() { EdgeEPA::~EdgeEPA() {
@ -51,21 +57,24 @@ EdgeEPA::~EdgeEPA() {
// Return the index of the source vertex of the edge (vertex starting the edge) // Return the index of the source vertex of the edge (vertex starting the edge)
uint EdgeEPA::getSourceVertexIndex() const { uint EdgeEPA::getSourceVertexIndex() const {
return (*ownerTriangle)[index]; return (*mOwnerTriangle)[mIndex];
} }
// Return the index of the target vertex of the edge (vertex ending the edge) // Return the index of the target vertex of the edge (vertex ending the edge)
uint EdgeEPA::getTargetVertexIndex() const { uint EdgeEPA::getTargetVertexIndex() const {
return (*ownerTriangle)[indexOfNextCounterClockwiseEdge(index)]; return (*mOwnerTriangle)[indexOfNextCounterClockwiseEdge(mIndex)];
} }
// Execute the recursive silhouette algorithm from this edge // Execute the recursive silhouette algorithm from this edge
bool EdgeEPA::computeSilhouette(const Vector3* vertices, uint indexNewVertex, TrianglesStore& triangleStore) { bool EdgeEPA::computeSilhouette(const Vector3* vertices, uint indexNewVertex,
TrianglesStore& triangleStore) {
// If the edge has not already been visited // If the edge has not already been visited
if (!ownerTriangle->getIsObsolete()) { if (!mOwnerTriangle->getIsObsolete()) {
// If the triangle of this edge is not visible from the given point // If the triangle of this edge is not visible from the given point
if (!ownerTriangle->isVisibleFromVertex(vertices, indexNewVertex)) { if (!mOwnerTriangle->isVisibleFromVertex(vertices, indexNewVertex)) {
TriangleEPA* triangle = triangleStore.newTriangle(vertices, indexNewVertex, getTargetVertexIndex(), getSourceVertexIndex()); TriangleEPA* triangle = triangleStore.newTriangle(vertices, indexNewVertex,
getTargetVertexIndex(),
getSourceVertexIndex());
// If the triangle has been created // If the triangle has been created
if (triangle) { if (triangle) {
@ -77,14 +86,19 @@ bool EdgeEPA::computeSilhouette(const Vector3* vertices, uint indexNewVertex, Tr
} }
else { else {
// The current triangle is visible and therefore obsolete // The current triangle is visible and therefore obsolete
ownerTriangle->setIsObsolete(true); mOwnerTriangle->setIsObsolete(true);
int backup = triangleStore.getNbTriangles(); int backup = triangleStore.getNbTriangles();
if(!ownerTriangle->getAdjacentEdge(indexOfNextCounterClockwiseEdge(this->index)).computeSilhouette(vertices, indexNewVertex, triangleStore)) { if(!mOwnerTriangle->getAdjacentEdge(indexOfNextCounterClockwiseEdge(
ownerTriangle->setIsObsolete(false); this->mIndex)).computeSilhouette(vertices,
indexNewVertex,
triangleStore)) {
mOwnerTriangle->setIsObsolete(false);
TriangleEPA* triangle = triangleStore.newTriangle(vertices, indexNewVertex, getTargetVertexIndex(), getSourceVertexIndex()); TriangleEPA* triangle = triangleStore.newTriangle(vertices, indexNewVertex,
getTargetVertexIndex(),
getSourceVertexIndex());
// If the triangle has been created // If the triangle has been created
if (triangle) { if (triangle) {
@ -94,12 +108,17 @@ bool EdgeEPA::computeSilhouette(const Vector3* vertices, uint indexNewVertex, Tr
return false; return false;
} }
else if (!ownerTriangle->getAdjacentEdge(indexOfPreviousCounterClockwiseEdge(this->index)).computeSilhouette(vertices, indexNewVertex, triangleStore)) { else if (!mOwnerTriangle->getAdjacentEdge(indexOfPreviousCounterClockwiseEdge(
ownerTriangle->setIsObsolete(false); this->mIndex)).computeSilhouette(vertices,
indexNewVertex,
triangleStore)) {
mOwnerTriangle->setIsObsolete(false);
triangleStore.setNbTriangles(backup); triangleStore.setNbTriangles(backup);
TriangleEPA* triangle = triangleStore.newTriangle(vertices, indexNewVertex, getTargetVertexIndex(), getSourceVertexIndex()); TriangleEPA* triangle = triangleStore.newTriangle(vertices, indexNewVertex,
getTargetVertexIndex(),
getSourceVertexIndex());
if (triangle) { if (triangle) {
halfLink(EdgeEPA(triangle, 1), *this); halfLink(EdgeEPA(triangle, 1), *this);

View File

@ -44,31 +44,67 @@ class TrianglesStore;
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class EdgeEPA { class EdgeEPA {
private: private:
TriangleEPA* ownerTriangle; // Pointer to the triangle that contains this edge
int index; // Index of the edge in the triangle (between 0 and 2). // -------------------- Attributes -------------------- //
// The edge with index i connect triangle vertices i and (i+1 % 3)
// Pointer to the triangle that contains this edge
TriangleEPA* mOwnerTriangle;
// Index of the edge in the triangle (between 0 and 2).
// The edge with index i connect triangle vertices i and (i+1 % 3)
int mIndex;
public: public:
EdgeEPA(); // Constructor
EdgeEPA(TriangleEPA* ownerTriangle, int index); // Constructor // -------------------- Methods -------------------- //
~EdgeEPA(); // Destructor
TriangleEPA* getOwnerTriangle() const; // Return the pointer to the owner triangle // Constructor
int getIndex() const; // Return the index of the edge in the triangle EdgeEPA();
uint getSourceVertexIndex() const; // Return index of the source vertex of the edge
uint getTargetVertexIndex() const; // Return the index of the target vertex of the edge // Constructor
bool computeSilhouette(const Vector3* vertices, uint index, EdgeEPA(TriangleEPA* ownerTriangle, int index);
TrianglesStore& triangleStore); // Execute the recursive silhouette algorithm from this edge
// Copy-constructor
EdgeEPA(const EdgeEPA& edge);
// Destructor
~EdgeEPA();
// Return the pointer to the owner triangle
TriangleEPA* getOwnerTriangle() const;
// Return the index of the edge in the triangle
int getIndex() const;
// Return index of the source vertex of the edge
uint getSourceVertexIndex() const;
// Return the index of the target vertex of the edge
uint getTargetVertexIndex() const;
// Execute the recursive silhouette algorithm from this edge
bool computeSilhouette(const Vector3* vertices, uint index, TrianglesStore& triangleStore);
// Assignment operator
EdgeEPA& operator=(const EdgeEPA& edge);
}; };
// Return the pointer to the owner triangle // Return the pointer to the owner triangle
inline TriangleEPA* EdgeEPA::getOwnerTriangle() const { inline TriangleEPA* EdgeEPA::getOwnerTriangle() const {
return ownerTriangle; return mOwnerTriangle;
} }
// Return the edge index // Return the edge index
inline int EdgeEPA::getIndex() const { inline int EdgeEPA::getIndex() const {
return index; return mIndex;
}
// Assignment operator
inline EdgeEPA& EdgeEPA::operator=(const EdgeEPA& edge) {
mOwnerTriangle = edge.mOwnerTriangle;
mIndex = edge.mIndex;
} }
// Return the index of the next counter-clockwise edge of the ownver triangle // Return the index of the next counter-clockwise edge of the ownver triangle

View File

@ -39,10 +39,10 @@ TriangleEPA::TriangleEPA() {
// Constructor // Constructor
TriangleEPA::TriangleEPA(uint indexVertex1, uint indexVertex2, uint indexVertex3) TriangleEPA::TriangleEPA(uint indexVertex1, uint indexVertex2, uint indexVertex3)
: isObsolete(false) { : mIsObsolete(false) {
indicesVertices[0] = indexVertex1; mIndicesVertices[0] = indexVertex1;
indicesVertices[1] = indexVertex2; mIndicesVertices[1] = indexVertex2;
indicesVertices[2] = indexVertex3; mIndicesVertices[2] = indexVertex3;
} }
// Destructor // Destructor
@ -52,10 +52,10 @@ TriangleEPA::~TriangleEPA() {
// Compute the point v closest to the origin of this triangle // Compute the point v closest to the origin of this triangle
bool TriangleEPA::computeClosestPoint(const Vector3* vertices) { bool TriangleEPA::computeClosestPoint(const Vector3* vertices) {
const Vector3& p0 = vertices[indicesVertices[0]]; const Vector3& p0 = vertices[mIndicesVertices[0]];
Vector3 v1 = vertices[indicesVertices[1]] - p0; Vector3 v1 = vertices[mIndicesVertices[1]] - p0;
Vector3 v2 = vertices[indicesVertices[2]] - p0; Vector3 v2 = vertices[mIndicesVertices[2]] - p0;
decimal v1Dotv1 = v1.dot(v1); decimal v1Dotv1 = v1.dot(v1);
decimal v1Dotv2 = v1.dot(v2); decimal v1Dotv2 = v1.dot(v2);
decimal v2Dotv2 = v2.dot(v2); decimal v2Dotv2 = v2.dot(v2);
@ -63,19 +63,19 @@ bool TriangleEPA::computeClosestPoint(const Vector3* vertices) {
decimal p0Dotv2 = p0.dot(v2); decimal p0Dotv2 = p0.dot(v2);
// Compute determinant // Compute determinant
det = v1Dotv1 * v2Dotv2 - v1Dotv2 * v1Dotv2; mDet = v1Dotv1 * v2Dotv2 - v1Dotv2 * v1Dotv2;
// Compute lambda values // Compute lambda values
lambda1 = p0Dotv2 * v1Dotv2 - p0Dotv1 * v2Dotv2; mLambda1 = p0Dotv2 * v1Dotv2 - p0Dotv1 * v2Dotv2;
lambda2 = p0Dotv1 * v1Dotv2 - p0Dotv2 * v1Dotv1; mLambda2 = p0Dotv1 * v1Dotv2 - p0Dotv2 * v1Dotv1;
// If the determinant is positive // If the determinant is positive
if (det > 0.0) { if (mDet > 0.0) {
// Compute the closest point v // Compute the closest point v
closestPoint = p0 + 1.0 / det * (lambda1 * v1 + lambda2 * v2); mClosestPoint = p0 + 1.0 / mDet * (mLambda1 * v1 + mLambda2 * v2);
// Compute the square distance of closest point to the origin // Compute the square distance of closest point to the origin
distSquare = closestPoint.dot(closestPoint); mDistSquare = mClosestPoint.dot(mClosestPoint);
return true; return true;
} }
@ -91,8 +91,8 @@ bool reactphysics3d::link(const EdgeEPA& edge0, const EdgeEPA& edge1) {
edge0.getTargetVertexIndex() == edge1.getSourceVertexIndex()); edge0.getTargetVertexIndex() == edge1.getSourceVertexIndex());
if (isPossible) { if (isPossible) {
edge0.getOwnerTriangle()->adjacentEdges[edge0.getIndex()] = edge1; edge0.getOwnerTriangle()->mAdjacentEdges[edge0.getIndex()] = edge1;
edge1.getOwnerTriangle()->adjacentEdges[edge1.getIndex()] = edge0; edge1.getOwnerTriangle()->mAdjacentEdges[edge1.getIndex()] = edge0;
} }
return isPossible; return isPossible;
@ -107,7 +107,7 @@ void reactphysics3d::halfLink(const EdgeEPA& edge0, const EdgeEPA& edge1) {
edge0.getTargetVertexIndex() == edge1.getSourceVertexIndex()); edge0.getTargetVertexIndex() == edge1.getSourceVertexIndex());
// Link // Link
edge0.getOwnerTriangle()->adjacentEdges[edge0.getIndex()] = edge1; edge0.getOwnerTriangle()->mAdjacentEdges[edge0.getIndex()] = edge1;
} }
// Execute the recursive silhouette algorithm from this triangle face // Execute the recursive silhouette algorithm from this triangle face
@ -128,9 +128,9 @@ bool TriangleEPA::computeSilhouette(const Vector3* vertices, uint indexNewVertex
// Execute recursively the silhouette algorithm for the adjacent edges of neighboring // Execute recursively the silhouette algorithm for the adjacent edges of neighboring
// triangles of the current triangle // triangles of the current triangle
bool result = adjacentEdges[0].computeSilhouette(vertices, indexNewVertex, triangleStore) && bool result = mAdjacentEdges[0].computeSilhouette(vertices, indexNewVertex, triangleStore) &&
adjacentEdges[1].computeSilhouette(vertices, indexNewVertex, triangleStore) && mAdjacentEdges[1].computeSilhouette(vertices, indexNewVertex, triangleStore) &&
adjacentEdges[2].computeSilhouette(vertices, indexNewVertex, triangleStore); mAdjacentEdges[2].computeSilhouette(vertices, indexNewVertex, triangleStore);
if (result) { if (result) {
int i,j; int i,j;

View File

@ -47,95 +47,155 @@ void halfLink(const EdgeEPA& edge0, const EdgeEPA& edge1);
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class TriangleEPA { class TriangleEPA {
private: private:
uint indicesVertices[3]; // Indices of the vertices y_i of the triangle
EdgeEPA adjacentEdges[3]; // Three adjacent edges of the triangle (edges of other triangles) // -------------------- Attributes -------------------- //
bool isObsolete; // True if the triangle face is visible from the new support point
decimal det; // Determinant // Indices of the vertices y_i of the triangle
Vector3 closestPoint; // Point v closest to the origin on the affine hull of the triangle uint mIndicesVertices[3];
decimal lambda1; // Lambda1 value such that v = lambda0 * y_0 + lambda1 * y_1 + lambda2 * y_2
decimal lambda2; // Lambda1 value such that v = lambda0 * y_0 + lambda1 * y_1 + lambda2 * y_2 // Three adjacent edges of the triangle (edges of other triangles)
decimal distSquare; // Square distance of the point closest point v to the origin EdgeEPA mAdjacentEdges[3];
// True if the triangle face is visible from the new support point
bool mIsObsolete;
// Determinant
decimal mDet;
// Point v closest to the origin on the affine hull of the triangle
Vector3 mClosestPoint;
// Lambda1 value such that v = lambda0 * y_0 + lambda1 * y_1 + lambda2 * y_2
decimal mLambda1;
// Lambda1 value such that v = lambda0 * y_0 + lambda1 * y_1 + lambda2 * y_2
decimal mLambda2;
// Square distance of the point closest point v to the origin
decimal mDistSquare;
// -------------------- Methods -------------------- //
// Private copy-constructor
TriangleEPA(const TriangleEPA& triangle);
// Private assignment operator
TriangleEPA& operator=(const TriangleEPA& triangle);
public: public:
TriangleEPA(); // Constructor
TriangleEPA(uint v1, uint v2, uint v3); // Constructor
~TriangleEPA(); // Destructor
EdgeEPA& getAdjacentEdge(int index); // Return an adjacent edge of the triangle // -------------------- Methods -------------------- //
void setAdjacentEdge(int index, EdgeEPA& edge); // Set an adjacent edge of the triangle
decimal getDistSquare() const; // Return the square distance of the closest point to origin
void setIsObsolete(bool isObsolete); // Set the isObsolete value
bool getIsObsolete() const; // Return true if the triangle face is obsolete
const Vector3& getClosestPoint() const; // Return the point closest to the origin
bool isClosestPointInternalToTriangle() const; // Return true if the closest point on affine hull is inside the triangle
bool isVisibleFromVertex(const Vector3* vertices, uint index) const; // Return true if the triangle is visible from a given vertex
bool computeClosestPoint(const Vector3* vertices); // Compute the point v closest to the origin of this triangle
Vector3 computeClosestPointOfObject(const Vector3* supportPointsOfObject) const; // Compute the point of an object closest to the origin
bool computeSilhouette(const Vector3* vertices, uint index,
TrianglesStore& triangleStore); // Execute the recursive silhouette algorithm from this triangle face
uint operator[](int i) const; // Access operator // Constructor
friend bool link(const EdgeEPA& edge0, const EdgeEPA& edge1); // Associate two edges TriangleEPA();
friend void halfLink(const EdgeEPA& edge0, const EdgeEPA& edge1); // Make a half-link between two edges
// Constructor
TriangleEPA(uint v1, uint v2, uint v3);
// Destructor
~TriangleEPA();
// Return an adjacent edge of the triangle
EdgeEPA& getAdjacentEdge(int index);
// Set an adjacent edge of the triangle
void setAdjacentEdge(int index, EdgeEPA& edge);
// Return the square distance of the closest point to origin
decimal getDistSquare() const;
// Set the isObsolete value
void setIsObsolete(bool isObsolete);
// Return true if the triangle face is obsolete
bool getIsObsolete() const;
// Return the point closest to the origin
const Vector3& getClosestPoint() const;
// Return true if the closest point on affine hull is inside the triangle
bool isClosestPointInternalToTriangle() const;
// Return true if the triangle is visible from a given vertex
bool isVisibleFromVertex(const Vector3* vertices, uint index) const;
// Compute the point v closest to the origin of this triangle
bool computeClosestPoint(const Vector3* vertices);
// Compute the point of an object closest to the origin
Vector3 computeClosestPointOfObject(const Vector3* supportPointsOfObject) const;
// Execute the recursive silhouette algorithm from this triangle face
bool computeSilhouette(const Vector3* vertices, uint index, TrianglesStore& triangleStore);
// Access operator
uint operator[](int i) const;
// Associate two edges
friend bool link(const EdgeEPA& edge0, const EdgeEPA& edge1);
// Make a half-link between two edges
friend void halfLink(const EdgeEPA& edge0, const EdgeEPA& edge1);
}; };
// Return an edge of the triangle // Return an edge of the triangle
inline EdgeEPA& TriangleEPA::getAdjacentEdge(int index) { inline EdgeEPA& TriangleEPA::getAdjacentEdge(int index) {
assert(index >= 0 && index < 3); assert(index >= 0 && index < 3);
return adjacentEdges[index]; return mAdjacentEdges[index];
} }
// Set an adjacent edge of the triangle // Set an adjacent edge of the triangle
inline void TriangleEPA::setAdjacentEdge(int index, EdgeEPA& edge) { inline void TriangleEPA::setAdjacentEdge(int index, EdgeEPA& edge) {
assert(index >=0 && index < 3); assert(index >=0 && index < 3);
adjacentEdges[index] = edge; mAdjacentEdges[index] = edge;
} }
// Return the square distance of the closest point to origin // Return the square distance of the closest point to origin
inline decimal TriangleEPA::getDistSquare() const { inline decimal TriangleEPA::getDistSquare() const {
return distSquare; return mDistSquare;
} }
// Set the isObsolete value // Set the isObsolete value
inline void TriangleEPA::setIsObsolete(bool isObsolete) { inline void TriangleEPA::setIsObsolete(bool isObsolete) {
this->isObsolete = isObsolete; mIsObsolete = isObsolete;
} }
// Return true if the triangle face is obsolete // Return true if the triangle face is obsolete
inline bool TriangleEPA::getIsObsolete() const { inline bool TriangleEPA::getIsObsolete() const {
return isObsolete; return mIsObsolete;
} }
// Return the point closest to the origin // Return the point closest to the origin
inline const Vector3& TriangleEPA::getClosestPoint() const { inline const Vector3& TriangleEPA::getClosestPoint() const {
return closestPoint; return mClosestPoint;
} }
// Return true if the closest point on affine hull is inside the triangle // Return true if the closest point on affine hull is inside the triangle
inline bool TriangleEPA::isClosestPointInternalToTriangle() const { inline bool TriangleEPA::isClosestPointInternalToTriangle() const {
return (lambda1 >= 0.0 && lambda2 >= 0.0 && (lambda1 + lambda2) <= det); return (mLambda1 >= 0.0 && mLambda2 >= 0.0 && (mLambda1 + mLambda2) <= mDet);
} }
// Return true if the triangle is visible from a given vertex // Return true if the triangle is visible from a given vertex
inline bool TriangleEPA::isVisibleFromVertex(const Vector3* vertices, uint index) const { inline bool TriangleEPA::isVisibleFromVertex(const Vector3* vertices, uint index) const {
Vector3 closestToVert = vertices[index] - closestPoint; Vector3 closestToVert = vertices[index] - mClosestPoint;
return (closestPoint.dot(closestToVert) > 0.0); return (mClosestPoint.dot(closestToVert) > 0.0);
} }
// Compute the point of an object closest to the origin // Compute the point of an object closest to the origin
inline Vector3 TriangleEPA::computeClosestPointOfObject(const Vector3* supportPointsOfObject) const { inline Vector3 TriangleEPA::computeClosestPointOfObject(const Vector3* supportPointsOfObject) const{
const Vector3& p0 = supportPointsOfObject[indicesVertices[0]]; const Vector3& p0 = supportPointsOfObject[mIndicesVertices[0]];
return p0 + 1.0/det * (lambda1 * (supportPointsOfObject[indicesVertices[1]] - p0) + return p0 + 1.0/mDet * (mLambda1 * (supportPointsOfObject[mIndicesVertices[1]] - p0) +
lambda2 * (supportPointsOfObject[indicesVertices[2]] - p0)); mLambda2 * (supportPointsOfObject[mIndicesVertices[2]] - p0));
} }
// Access operator // Access operator
inline uint TriangleEPA::operator[](int i) const { inline uint TriangleEPA::operator[](int i) const {
assert(i >= 0 && i <3); assert(i >= 0 && i <3);
return indicesVertices[i]; return mIndicesVertices[i];
} }
} // End of ReactPhysics3D namespace } // End of ReactPhysics3D namespace
#endif #endif

View File

@ -30,7 +30,7 @@
using namespace reactphysics3d; using namespace reactphysics3d;
// Constructor // Constructor
TrianglesStore::TrianglesStore() : nbTriangles(0) { TrianglesStore::TrianglesStore() : mNbTriangles(0) {
} }

View File

@ -46,55 +46,86 @@ const unsigned int MAX_TRIANGLES = 200; // Maximum number of triangles
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class TrianglesStore { class TrianglesStore {
private: private:
TriangleEPA triangles[MAX_TRIANGLES]; // Triangles
int nbTriangles; // Number of triangles // -------------------- Attributes -------------------- //
// Triangles
TriangleEPA mTriangles[MAX_TRIANGLES];
// Number of triangles
int mNbTriangles;
// -------------------- Methods -------------------- //
// Private copy-constructor
TrianglesStore(const TrianglesStore& triangleStore);
// Private assignment operator
TrianglesStore& operator=(const TrianglesStore& triangleStore);
public: public:
TrianglesStore(); // Constructor
~TrianglesStore(); // Destructor
void clear(); // Clear all the storage // -------------------- Methods -------------------- //
int getNbTriangles() const; // Return the number of triangles
void setNbTriangles(int backup); // Set the number of triangles
TriangleEPA& last(); // Return the last triangle
TriangleEPA* newTriangle(const Vector3* vertices, uint v0, uint v1, uint v2); // Create a new triangle // Constructor
TrianglesStore();
TriangleEPA& operator[](int i); // Access operator // Destructor
~TrianglesStore();
// Clear all the storage
void clear();
// Return the number of triangles
int getNbTriangles() const;
// Set the number of triangles
void setNbTriangles(int backup);
// Return the last triangle
TriangleEPA& last();
// Create a new triangle
TriangleEPA* newTriangle(const Vector3* vertices, uint v0, uint v1, uint v2);
// Access operator
TriangleEPA& operator[](int i);
}; };
// Clear all the storage // Clear all the storage
inline void TrianglesStore::clear() { inline void TrianglesStore::clear() {
nbTriangles = 0; mNbTriangles = 0;
} }
// Return the number of triangles // Return the number of triangles
inline int TrianglesStore::getNbTriangles() const { inline int TrianglesStore::getNbTriangles() const {
return nbTriangles; return mNbTriangles;
} }
inline void TrianglesStore::setNbTriangles(int backup) { inline void TrianglesStore::setNbTriangles(int backup) {
nbTriangles = backup; mNbTriangles = backup;
} }
// Return the last triangle // Return the last triangle
inline TriangleEPA& TrianglesStore::last() { inline TriangleEPA& TrianglesStore::last() {
assert(nbTriangles > 0); assert(mNbTriangles > 0);
return triangles[nbTriangles - 1]; return mTriangles[mNbTriangles - 1];
} }
// Create a new triangle // Create a new triangle
inline TriangleEPA* TrianglesStore::newTriangle(const Vector3* vertices, uint v0, uint v1, uint v2) { inline TriangleEPA* TrianglesStore::newTriangle(const Vector3* vertices,
uint v0,uint v1, uint v2) {
TriangleEPA* newTriangle = 0; TriangleEPA* newTriangle = 0;
// If we have not reached the maximum number of triangles // If we have not reached the maximum number of triangles
if (nbTriangles != MAX_TRIANGLES) { if (mNbTriangles != MAX_TRIANGLES) {
newTriangle = &triangles[nbTriangles++]; newTriangle = &mTriangles[mNbTriangles++];
new (newTriangle) TriangleEPA(v0, v1, v2); new (newTriangle) TriangleEPA(v0, v1, v2);
if (!newTriangle->computeClosestPoint(vertices)) { if (!newTriangle->computeClosestPoint(vertices)) {
nbTriangles--; mNbTriangles--;
newTriangle = 0; newTriangle = 0;
} }
} }
@ -105,9 +136,9 @@ inline TriangleEPA* TrianglesStore::newTriangle(const Vector3* vertices, uint v0
// Access operator // Access operator
inline TriangleEPA& TrianglesStore::operator[](int i) { inline TriangleEPA& TrianglesStore::operator[](int i) {
return triangles[i]; return mTriangles[i];
} }
} // End of ReactPhysics3D namespace } // End of ReactPhysics3D namespace
#endif #endif

View File

@ -32,15 +32,13 @@
#include <cmath> #include <cmath>
#include <cfloat> #include <cfloat>
#include <cassert> #include <cassert>
#include <iostream> // TODO : DELETE THIS
// We want to use the ReactPhysics3D namespace // We want to use the ReactPhysics3D namespace
using namespace reactphysics3d; using namespace reactphysics3d;
// Constructor // Constructor
GJKAlgorithm::GJKAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos) GJKAlgorithm::GJKAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos)
:NarrowPhaseAlgorithm(memoryPoolContactInfos), algoEPA(memoryPoolContactInfos) { :NarrowPhaseAlgorithm(memoryPoolContactInfos), mAlgoEPA(memoryPoolContactInfos) {
} }
@ -59,8 +57,10 @@ GJKAlgorithm::~GJKAlgorithm() {
// algorithm on the enlarged object to obtain a simplex polytope that contains the // algorithm on the enlarged object to obtain a simplex polytope that contains the
// origin, they we give that simplex polytope to the EPA algorithm which will compute // origin, they we give that simplex polytope to the EPA algorithm which will compute
// the correct penetration depth and contact points between the enlarged objects. // the correct penetration depth and contact points between the enlarged objects.
bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Transform& transform1, bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1,
const CollisionShape* collisionShape2, const Transform& transform2, const Transform& transform1,
const CollisionShape* collisionShape2,
const Transform& transform2,
ContactInfo*& contactInfo) { ContactInfo*& contactInfo) {
Vector3 suppA; // Support point of object A Vector3 suppA; // Support point of object A
@ -71,11 +71,14 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
decimal vDotw; decimal vDotw;
decimal prevDistSquare; decimal prevDistSquare;
// Transform a point from local space of body 2 to local space of body 1 (the GJK algorithm is done in local space of body 1) // Transform a point from local space of body 2 to local
// space of body 1 (the GJK algorithm is done in local space of body 1)
Transform body2Tobody1 = transform1.inverse() * transform2; Transform body2Tobody1 = transform1.inverse() * transform2;
// Matrix that transform a direction from local space of body 1 into local space of body 2 // Matrix that transform a direction from local
Matrix3x3 rotateToBody2 = transform2.getOrientation().getMatrix().getTranspose() * transform1.getOrientation().getMatrix(); // space of body 1 into local space of body 2
Matrix3x3 rotateToBody2 = transform2.getOrientation().getMatrix().getTranspose() *
transform1.getOrientation().getMatrix();
// Initialize the margin (sum of margins of both objects) // Initialize the margin (sum of margins of both objects)
decimal margin = 2 * OBJECT_MARGIN; decimal margin = 2 * OBJECT_MARGIN;
@ -86,7 +89,7 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
Simplex simplex; Simplex simplex;
// Get the previous point V (last cached separating axis) // Get the previous point V (last cached separating axis)
Vector3 v = currentOverlappingPair->previousSeparatingAxis; Vector3 v = mCurrentOverlappingPair->previousSeparatingAxis;
// Initialize the upper bound for the square distance // Initialize the upper bound for the square distance
decimal distSquare = DECIMAL_LARGEST; decimal distSquare = DECIMAL_LARGEST;
@ -106,7 +109,7 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
if (vDotw > 0.0 && vDotw * vDotw > distSquare * marginSquare) { if (vDotw > 0.0 && vDotw * vDotw > distSquare * marginSquare) {
// Cache the current separating axis for frame coherence // Cache the current separating axis for frame coherence
currentOverlappingPair->previousSeparatingAxis = v; mCurrentOverlappingPair->previousSeparatingAxis = v;
// No intersection, we return false // No intersection, we return false
return false; return false;
@ -132,7 +135,9 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
if (penetrationDepth <= 0.0) return false; if (penetrationDepth <= 0.0) return false;
// Create the contact info object // Create the contact info object
contactInfo = new (memoryPoolContactInfos.allocateObject()) ContactInfo(normal, penetrationDepth, pA, pB); contactInfo = new (mMemoryPoolContactInfos.allocateObject()) ContactInfo(normal,
penetrationDepth,
pA, pB);
// There is an intersection, therefore we return true // There is an intersection, therefore we return true
return true; return true;
@ -161,7 +166,9 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
if (penetrationDepth <= 0.0) return false; if (penetrationDepth <= 0.0) return false;
// Create the contact info object // Create the contact info object
contactInfo = new (memoryPoolContactInfos.allocateObject()) ContactInfo(normal, penetrationDepth, pA, pB); contactInfo = new (mMemoryPoolContactInfos.allocateObject()) ContactInfo(normal,
penetrationDepth,
pA, pB);
// There is an intersection, therefore we return true // There is an intersection, therefore we return true
return true; return true;
@ -188,7 +195,9 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
if (penetrationDepth <= 0.0) return false; if (penetrationDepth <= 0.0) return false;
// Create the contact info object // Create the contact info object
contactInfo = new (memoryPoolContactInfos.allocateObject()) ContactInfo(normal, penetrationDepth, pA, pB); contactInfo = new (mMemoryPoolContactInfos.allocateObject()) ContactInfo(normal,
penetrationDepth,
pA, pB);
// There is an intersection, therefore we return true // There is an intersection, therefore we return true
return true; return true;
@ -223,18 +232,22 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
if (penetrationDepth <= 0.0) return false; if (penetrationDepth <= 0.0) return false;
// Create the contact info object // Create the contact info object
contactInfo = new (memoryPoolContactInfos.allocateObject()) ContactInfo(normal, penetrationDepth, pA, pB); contactInfo = new (mMemoryPoolContactInfos.allocateObject()) ContactInfo(normal,
penetrationDepth,
pA, pB);
// There is an intersection, therefore we return true // There is an intersection, therefore we return true
return true; return true;
} }
} while(!simplex.isFull() && distSquare > MACHINE_EPSILON * simplex.getMaxLengthSquareOfAPoint()); } while(!simplex.isFull() && distSquare > MACHINE_EPSILON *
simplex.getMaxLengthSquareOfAPoint());
// The objects (without margins) intersect. Therefore, we run the GJK algorithm again but on the // The objects (without margins) intersect. Therefore, we run the GJK algorithm
// enlarged objects to compute a simplex polytope that contains the origin. Then, we give that simplex // again but on the enlarged objects to compute a simplex polytope that contains
// polytope to the EPA algorithm to compute the correct penetration depth and contact points between // the origin. Then, we give that simplex polytope to the EPA algorithm to compute
// the enlarged objects. // the correct penetration depth and contact points between the enlarged objects.
return computePenetrationDepthForEnlargedObjects(collisionShape1, transform1, collisionShape2, transform2, contactInfo, v); return computePenetrationDepthForEnlargedObjects(collisionShape1, transform1, collisionShape2,
transform2, contactInfo, v);
} }
// This method runs the GJK algorithm on the two enlarged objects (with margin) // This method runs the GJK algorithm on the two enlarged objects (with margin)
@ -242,9 +255,12 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
// assumed to intersect in the original objects (without margin). Therefore such // assumed to intersect in the original objects (without margin). Therefore such
// a polytope must exist. Then, we give that polytope to the EPA algorithm to // a polytope must exist. Then, we give that polytope to the EPA algorithm to
// compute the correct penetration depth and contact points of the enlarged objects. // compute the correct penetration depth and contact points of the enlarged objects.
bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShape* const collisionShape1, const Transform& transform1, bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShape* collisionShape1,
const CollisionShape* const collisionShape2, const Transform& transform2, const Transform& transform1,
ContactInfo*& contactInfo, Vector3& v) { const CollisionShape* collisionShape2,
const Transform& transform2,
ContactInfo*& contactInfo,
Vector3& v) {
Simplex simplex; Simplex simplex;
Vector3 suppA; Vector3 suppA;
Vector3 suppB; Vector3 suppB;
@ -253,16 +269,19 @@ bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShap
decimal distSquare = DECIMAL_LARGEST; decimal distSquare = DECIMAL_LARGEST;
decimal prevDistSquare; decimal prevDistSquare;
// Transform a point from local space of body 2 to local space of body 1 (the GJK algorithm is done in local space of body 1) // Transform a point from local space of body 2 to local space
// of body 1 (the GJK algorithm is done in local space of body 1)
Transform body2ToBody1 = transform1.inverse() * transform2; Transform body2ToBody1 = transform1.inverse() * transform2;
// Matrix that transform a direction from local space of body 1 into local space of body 2 // Matrix that transform a direction from local space of body 1 into local space of body 2
Matrix3x3 rotateToBody2 = transform2.getOrientation().getMatrix().getTranspose() * transform1.getOrientation().getMatrix(); Matrix3x3 rotateToBody2 = transform2.getOrientation().getMatrix().getTranspose() *
transform1.getOrientation().getMatrix();
do { do {
// Compute the support points for the enlarged object A and B // Compute the support points for the enlarged object A and B
suppA = collisionShape1->getLocalSupportPoint(-v, OBJECT_MARGIN); suppA = collisionShape1->getLocalSupportPoint(-v, OBJECT_MARGIN);
suppB = body2ToBody1 * collisionShape2->getLocalSupportPoint(rotateToBody2 * v, OBJECT_MARGIN); suppB = body2ToBody1 * collisionShape2->getLocalSupportPoint(rotateToBody2 * v,
OBJECT_MARGIN);
// Compute the support point for the Minkowski difference A-B // Compute the support point for the Minkowski difference A-B
w = suppA - suppB; w = suppA - suppB;
@ -294,9 +313,13 @@ bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShap
return false; return false;
} }
} while(!simplex.isFull() && distSquare > MACHINE_EPSILON * simplex.getMaxLengthSquareOfAPoint()); } while(!simplex.isFull() && distSquare > MACHINE_EPSILON *
simplex.getMaxLengthSquareOfAPoint());
// Give the simplex computed with GJK algorithm to the EPA algorithm which will compute the correct // Give the simplex computed with GJK algorithm to the EPA algorithm
// penetration depth and contact points between the two enlarged objects // which will compute the correct penetration depth and contact points
return algoEPA.computePenetrationDepthAndContactPoints(simplex, collisionShape1, transform1, collisionShape2, transform2, v, contactInfo); // between the two enlarged objects
return mAlgoEPA.computePenetrationDepthAndContactPoints(simplex, collisionShape1,
transform1, collisionShape2, transform2,
v, contactInfo);
} }

View File

@ -58,20 +58,45 @@ const decimal REL_ERROR_SQUARE = REL_ERROR * REL_ERROR;
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class GJKAlgorithm : public NarrowPhaseAlgorithm { class GJKAlgorithm : public NarrowPhaseAlgorithm {
private :
EPAAlgorithm algoEPA; // EPA Algorithm
bool computePenetrationDepthForEnlargedObjects(const CollisionShape* collisionShape1, const Transform& transform1, private :
const CollisionShape* collisionShape2, const Transform& transform2,
ContactInfo*& contactInfo, Vector3& v); // Compute the penetration depth for enlarged objects // -------------------- Attributes -------------------- //
// EPA Algorithm
EPAAlgorithm mAlgoEPA;
// -------------------- Methods -------------------- //
// Private copy-constructor
GJKAlgorithm(const GJKAlgorithm& algorithm);
// Private assignment operator
GJKAlgorithm& operator=(const GJKAlgorithm& algorithm);
// Compute the penetration depth for enlarged objects
bool computePenetrationDepthForEnlargedObjects(const CollisionShape* collisionShape1,
const Transform& transform1,
const CollisionShape* collisionShape2,
const Transform& transform2,
ContactInfo*& contactInfo, Vector3& v);
public : public :
GJKAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos); // Constructor
~GJKAlgorithm(); // Destructor
virtual bool testCollision(const CollisionShape* collisionShape1, const Transform& transform1, // -------------------- Methods -------------------- //
const CollisionShape* collisionShape2, const Transform& transform2,
ContactInfo*& contactInfo); // Return true and compute a contact info if the two bounding volume collide // Constructor
GJKAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos);
// Destructor
~GJKAlgorithm();
// Return true and compute a contact info if the two bounding volume collide
virtual bool testCollision(const CollisionShape* collisionShape1,
const Transform& transform1,
const CollisionShape* collisionShape2,
const Transform& transform2,
ContactInfo*& contactInfo);
}; };
} // End of the ReactPhysics3D namespace } // End of the ReactPhysics3D namespace

View File

@ -31,7 +31,7 @@
using namespace reactphysics3d; using namespace reactphysics3d;
// Constructor // Constructor
Simplex::Simplex() : bitsCurrentSimplex(0x0), allBits(0x0) { Simplex::Simplex() : mBitsCurrentSimplex(0x0), mAllBits(0x0) {
} }
@ -47,22 +47,22 @@ Simplex::~Simplex() {
void Simplex::addPoint(const Vector3& point, const Vector3& suppPointA, const Vector3& suppPointB) { void Simplex::addPoint(const Vector3& point, const Vector3& suppPointA, const Vector3& suppPointB) {
assert(!isFull()); assert(!isFull());
lastFound = 0; mLastFound = 0;
lastFoundBit = 0x1; mLastFoundBit = 0x1;
// Look for the bit corresponding to one of the four point that is not in // Look for the bit corresponding to one of the four point that is not in
// the current simplex // the current simplex
while (overlap(bitsCurrentSimplex, lastFoundBit)) { while (overlap(mBitsCurrentSimplex, mLastFoundBit)) {
lastFound++; mLastFound++;
lastFoundBit <<= 1; mLastFoundBit <<= 1;
} }
assert(lastFound >= 0 && lastFound < 4); assert(mLastFound >= 0 && mLastFound < 4);
// Add the point into the simplex // Add the point into the simplex
points[lastFound] = point; mPoints[mLastFound] = point;
pointsLengthSquare[lastFound] = point.dot(point); mPointsLengthSquare[mLastFound] = point.dot(point);
allBits = bitsCurrentSimplex | lastFoundBit; mAllBits = mBitsCurrentSimplex | mLastFoundBit;
// Update the cached values // Update the cached values
updateCache(); updateCache();
@ -71,8 +71,8 @@ void Simplex::addPoint(const Vector3& point, const Vector3& suppPointA, const Ve
computeDeterminants(); computeDeterminants();
// Add the support points of objects A and B // Add the support points of objects A and B
suppPointsA[lastFound] = suppPointA; mSuppPointsA[mLastFound] = suppPointA;
suppPointsB[lastFound] = suppPointB; mSuppPointsB[mLastFound] = suppPointB;
} }
// Return true if the point is in the simplex // Return true if the point is in the simplex
@ -83,7 +83,7 @@ bool Simplex::isPointInSimplex(const Vector3& point) const {
// For each four possible points in the simplex // For each four possible points in the simplex
for (i=0, bit = 0x1; i<4; i++, bit <<= 1) { for (i=0, bit = 0x1; i<4; i++, bit <<= 1) {
// Check if the current point is in the simplex // Check if the current point is in the simplex
if (overlap(allBits, bit) && point == points[i]) return true; if (overlap(mAllBits, bit) && point == mPoints[i]) return true;
} }
return false; return false;
@ -97,20 +97,23 @@ void Simplex::updateCache() {
// For each of the four possible points of the simplex // For each of the four possible points of the simplex
for (i=0, bit = 0x1; i<4; i++, bit <<= 1) { for (i=0, bit = 0x1; i<4; i++, bit <<= 1) {
// If the current points is in the simplex // If the current points is in the simplex
if (overlap(bitsCurrentSimplex, bit)) { if (overlap(mBitsCurrentSimplex, bit)) {
// Compute the distance between two points in the possible simplex set // Compute the distance between two points in the possible simplex set
diffLength[i][lastFound] = points[i] - points[lastFound]; mDiffLength[i][mLastFound] = mPoints[i] - mPoints[mLastFound];
diffLength[lastFound][i] = -diffLength[i][lastFound]; mDiffLength[mLastFound][i] = -mDiffLength[i][mLastFound];
// Compute the squared length of the vector distances from points in the possible simplex set // Compute the squared length of the vector
normSquare[i][lastFound] = normSquare[lastFound][i] = diffLength[i][lastFound].dot(diffLength[i][lastFound]); // distances from points in the possible simplex set
mNormSquare[i][mLastFound] = mNormSquare[mLastFound][i] =
mDiffLength[i][mLastFound].dot(mDiffLength[i][mLastFound]);
} }
} }
} }
// Return the points of the simplex // Return the points of the simplex
unsigned int Simplex::getSimplex(Vector3* suppPointsA, Vector3* suppPointsB, Vector3* points) const { unsigned int Simplex::getSimplex(Vector3* suppPointsA, Vector3* suppPointsB,
Vector3* points) const {
unsigned int nbVertices = 0; unsigned int nbVertices = 0;
int i; int i;
Bits bit; Bits bit;
@ -118,11 +121,11 @@ unsigned int Simplex::getSimplex(Vector3* suppPointsA, Vector3* suppPointsB, Vec
// For each four point in the possible simplex // For each four point in the possible simplex
for (i=0, bit=0x1; i<4; i++, bit <<=1) { for (i=0, bit=0x1; i<4; i++, bit <<=1) {
// If the current point is in the simplex // If the current point is in the simplex
if (overlap(bitsCurrentSimplex, bit)) { if (overlap(mBitsCurrentSimplex, bit)) {
// Store the points // Store the points
suppPointsA[nbVertices] = this->suppPointsA[nbVertices]; suppPointsA[nbVertices] = this->mSuppPointsA[nbVertices];
suppPointsB[nbVertices] = this->suppPointsB[nbVertices]; suppPointsB[nbVertices] = this->mSuppPointsB[nbVertices];
points[nbVertices] = this->points[nbVertices]; points[nbVertices] = this->mPoints[nbVertices];
nbVertices++; nbVertices++;
} }
@ -134,7 +137,7 @@ unsigned int Simplex::getSimplex(Vector3* suppPointsA, Vector3* suppPointsB, Vec
// Compute the cached determinant values // Compute the cached determinant values
void Simplex::computeDeterminants() { void Simplex::computeDeterminants() {
det[lastFoundBit][lastFound] = 1.0; mDet[mLastFoundBit][mLastFound] = 1.0;
// If the current simplex is not empty // If the current simplex is not empty
if (!isEmpty()) { if (!isEmpty()) {
@ -145,59 +148,72 @@ void Simplex::computeDeterminants() {
for (i=0, bitI = 0x1; i<4; i++, bitI <<= 1) { for (i=0, bitI = 0x1; i<4; i++, bitI <<= 1) {
// If the current point is in the simplex // If the current point is in the simplex
if (overlap(bitsCurrentSimplex, bitI)) { if (overlap(mBitsCurrentSimplex, bitI)) {
Bits bit2 = bitI | lastFoundBit; Bits bit2 = bitI | mLastFoundBit;
det[bit2][i] = diffLength[lastFound][i].dot(points[lastFound]); mDet[bit2][i] = mDiffLength[mLastFound][i].dot(mPoints[mLastFound]);
det[bit2][lastFound] = diffLength[i][lastFound].dot(points[i]); mDet[bit2][mLastFound] = mDiffLength[i][mLastFound].dot(mPoints[i]);
int j; int j;
Bits bitJ; Bits bitJ;
for (j=0, bitJ = 0x1; j<i; j++, bitJ <<= 1) { for (j=0, bitJ = 0x1; j<i; j++, bitJ <<= 1) {
if (overlap(bitsCurrentSimplex, bitJ)) { if (overlap(mBitsCurrentSimplex, bitJ)) {
int k; int k;
Bits bit3 = bitJ | bit2; Bits bit3 = bitJ | bit2;
k = normSquare[i][j] < normSquare[lastFound][j] ? i : lastFound; k = mNormSquare[i][j] < mNormSquare[mLastFound][j] ? i : mLastFound;
det[bit3][j] = det[bit2][i] * diffLength[k][j].dot(points[i]) + mDet[bit3][j] = mDet[bit2][i] * mDiffLength[k][j].dot(mPoints[i]) +
det[bit2][lastFound] * diffLength[k][j].dot(points[lastFound]); mDet[bit2][mLastFound] *
mDiffLength[k][j].dot(mPoints[mLastFound]);
k = normSquare[j][i] < normSquare[lastFound][i] ? j : lastFound; k = mNormSquare[j][i] < mNormSquare[mLastFound][i] ? j : mLastFound;
det[bit3][i] = det[bitJ | lastFoundBit][j] * diffLength[k][i].dot(points[j]) + mDet[bit3][i] = mDet[bitJ | mLastFoundBit][j] *
det[bitJ | lastFoundBit][lastFound] * diffLength[k][i].dot(points[lastFound]); mDiffLength[k][i].dot(mPoints[j]) +
mDet[bitJ | mLastFoundBit][mLastFound] *
mDiffLength[k][i].dot(mPoints[mLastFound]);
k = normSquare[i][lastFound] < normSquare[j][lastFound] ? i : j; k = mNormSquare[i][mLastFound] < mNormSquare[j][mLastFound] ? i : j;
det[bit3][lastFound] = det[bitJ | bitI][j] * diffLength[k][lastFound].dot(points[j]) + mDet[bit3][mLastFound] = mDet[bitJ | bitI][j] *
det[bitJ | bitI][i] * diffLength[k][lastFound].dot(points[i]); mDiffLength[k][mLastFound].dot(mPoints[j]) +
mDet[bitJ | bitI][i] *
mDiffLength[k][mLastFound].dot(mPoints[i]);
} }
} }
} }
} }
if (allBits == 0xf) { if (mAllBits == 0xf) {
int k; int k;
k = normSquare[1][0] < normSquare[2][0] ? (normSquare[1][0] < normSquare[3][0] ? 1 : 3) : (normSquare[2][0] < normSquare[3][0] ? 2 : 3); k = mNormSquare[1][0] < mNormSquare[2][0] ?
det[0xf][0] = det[0xe][1] * diffLength[k][0].dot(points[1]) + (mNormSquare[1][0] < mNormSquare[3][0] ? 1 : 3) :
det[0xe][2] * diffLength[k][0].dot(points[2]) + (mNormSquare[2][0] < mNormSquare[3][0] ? 2 : 3);
det[0xe][3] * diffLength[k][0].dot(points[3]); mDet[0xf][0] = mDet[0xe][1] * mDiffLength[k][0].dot(mPoints[1]) +
mDet[0xe][2] * mDiffLength[k][0].dot(mPoints[2]) +
mDet[0xe][3] * mDiffLength[k][0].dot(mPoints[3]);
k = normSquare[0][1] < normSquare[2][1] ? (normSquare[0][1] < normSquare[3][1] ? 0 : 3) : (normSquare[2][1] < normSquare[3][1] ? 2 : 3); k = mNormSquare[0][1] < mNormSquare[2][1] ?
det[0xf][1] = det[0xd][0] * diffLength[k][1].dot(points[0]) + (mNormSquare[0][1] < mNormSquare[3][1] ? 0 : 3) :
det[0xd][2] * diffLength[k][1].dot(points[2]) + (mNormSquare[2][1] < mNormSquare[3][1] ? 2 : 3);
det[0xd][3] * diffLength[k][1].dot(points[3]); mDet[0xf][1] = mDet[0xd][0] * mDiffLength[k][1].dot(mPoints[0]) +
mDet[0xd][2] * mDiffLength[k][1].dot(mPoints[2]) +
mDet[0xd][3] * mDiffLength[k][1].dot(mPoints[3]);
k = normSquare[0][2] < normSquare[1][2] ? (normSquare[0][2] < normSquare[3][2] ? 0 : 3) : (normSquare[1][2] < normSquare[3][2] ? 1 : 3); k = mNormSquare[0][2] < mNormSquare[1][2] ?
det[0xf][2] = det[0xb][0] * diffLength[k][2].dot(points[0]) + (mNormSquare[0][2] < mNormSquare[3][2] ? 0 : 3) :
det[0xb][1] * diffLength[k][2].dot(points[1]) + (mNormSquare[1][2] < mNormSquare[3][2] ? 1 : 3);
det[0xb][3] * diffLength[k][2].dot(points[3]); mDet[0xf][2] = mDet[0xb][0] * mDiffLength[k][2].dot(mPoints[0]) +
mDet[0xb][1] * mDiffLength[k][2].dot(mPoints[1]) +
mDet[0xb][3] * mDiffLength[k][2].dot(mPoints[3]);
k = normSquare[0][3] < normSquare[1][3] ? (normSquare[0][3] < normSquare[2][3] ? 0 : 2) : (normSquare[1][3] < normSquare[2][3] ? 1 : 2); k = mNormSquare[0][3] < mNormSquare[1][3] ?
det[0xf][3] = det[0x7][0] * diffLength[k][3].dot(points[0]) + (mNormSquare[0][3] < mNormSquare[2][3] ? 0 : 2) :
det[0x7][1] * diffLength[k][3].dot(points[1]) + (mNormSquare[1][3] < mNormSquare[2][3] ? 1 : 2);
det[0x7][2] * diffLength[k][3].dot(points[2]); mDet[0xf][3] = mDet[0x7][0] * mDiffLength[k][3].dot(mPoints[0]) +
mDet[0x7][1] * mDiffLength[k][3].dot(mPoints[1]) +
mDet[0x7][2] * mDiffLength[k][3].dot(mPoints[2]);
} }
} }
} }
@ -211,7 +227,7 @@ bool Simplex::isProperSubset(Bits subset) const {
// For each four point of the possible simplex set // For each four point of the possible simplex set
for (i=0, bit=0x1; i<4; i++, bit <<=1) { for (i=0, bit=0x1; i<4; i++, bit <<=1) {
if (overlap(subset, bit) && det[subset][i] <= 0.0) { if (overlap(subset, bit) && mDet[subset][i] <= 0.0) {
return false; return false;
} }
} }
@ -228,8 +244,8 @@ bool Simplex::isAffinelyDependent() const {
// For each four point of the possible simplex set // For each four point of the possible simplex set
for (i=0, bit=0x1; i<4; i++, bit <<= 1) { for (i=0, bit=0x1; i<4; i++, bit <<= 1) {
if (overlap(allBits, bit)) { if (overlap(mAllBits, bit)) {
sum += det[allBits][i]; sum += mDet[mAllBits][i];
} }
} }
@ -246,18 +262,18 @@ bool Simplex::isValidSubset(Bits subset) const {
// For each four point in the possible simplex set // For each four point in the possible simplex set
for (i=0, bit=0x1; i<4; i++, bit <<= 1) { for (i=0, bit=0x1; i<4; i++, bit <<= 1) {
if (overlap(allBits, bit)) { if (overlap(mAllBits, bit)) {
// If the current point is in the subset // If the current point is in the subset
if (overlap(subset, bit)) { if (overlap(subset, bit)) {
// If one delta(X)_i is smaller or equal to zero // If one delta(X)_i is smaller or equal to zero
if (det[subset][i] <= 0.0) { if (mDet[subset][i] <= 0.0) {
// The subset is not valid // The subset is not valid
return false; return false;
} }
} }
// If the point is not in the subset and the value delta(X U {y_j})_j // If the point is not in the subset and the value delta(X U {y_j})_j
// is bigger than zero // is bigger than zero
else if (det[subset | bit][i] > 0.0) { else if (mDet[subset | bit][i] > 0.0) {
// The subset is not valid // The subset is not valid
return false; return false;
} }
@ -282,10 +298,10 @@ void Simplex::computeClosestPointsOfAandB(Vector3& pA, Vector3& pB) const {
// For each four points in the possible simplex set // For each four points in the possible simplex set
for (i=0, bit=0x1; i<4; i++, bit <<= 1) { for (i=0, bit=0x1; i<4; i++, bit <<= 1) {
// If the current point is part of the simplex // If the current point is part of the simplex
if (overlap(bitsCurrentSimplex, bit)) { if (overlap(mBitsCurrentSimplex, bit)) {
deltaX += det[bitsCurrentSimplex][i]; deltaX += mDet[mBitsCurrentSimplex][i];
pA += det[bitsCurrentSimplex][i] * suppPointsA[i]; pA += mDet[mBitsCurrentSimplex][i] * mSuppPointsA[i];
pB += det[bitsCurrentSimplex][i] * suppPointsB[i]; pB += mDet[mBitsCurrentSimplex][i] * mSuppPointsB[i];
} }
} }
@ -303,21 +319,21 @@ bool Simplex::computeClosestPoint(Vector3& v) {
Bits subset; Bits subset;
// For each possible simplex set // For each possible simplex set
for (subset=bitsCurrentSimplex; subset != 0x0; subset--) { for (subset=mBitsCurrentSimplex; subset != 0x0; subset--) {
// If the simplex is a subset of the current simplex and is valid for the Johnson's // If the simplex is a subset of the current simplex and is valid for the Johnson's
// algorithm test // algorithm test
if (isSubset(subset, bitsCurrentSimplex) && isValidSubset(subset | lastFoundBit)) { if (isSubset(subset, mBitsCurrentSimplex) && isValidSubset(subset | mLastFoundBit)) {
bitsCurrentSimplex = subset | lastFoundBit; // Add the last added point to the current simplex mBitsCurrentSimplex = subset | mLastFoundBit; // Add the last added point to the current simplex
v = computeClosestPointForSubset(bitsCurrentSimplex); // Compute the closest point in the simplex v = computeClosestPointForSubset(mBitsCurrentSimplex); // Compute the closest point in the simplex
return true; return true;
} }
} }
// If the simplex that contains only the last added point is valid for the Johnson's algorithm test // If the simplex that contains only the last added point is valid for the Johnson's algorithm test
if (isValidSubset(lastFoundBit)) { if (isValidSubset(mLastFoundBit)) {
bitsCurrentSimplex = lastFoundBit; // Set the current simplex to the set that contains only the last added point mBitsCurrentSimplex = mLastFoundBit; // Set the current simplex to the set that contains only the last added point
maxLengthSquare = pointsLengthSquare[lastFound]; // Update the maximum square length mMaxLengthSquare = mPointsLengthSquare[mLastFound]; // Update the maximum square length
v = points[lastFound]; // The closest point of the simplex "v" is the last added point v = mPoints[mLastFound]; // The closest point of the simplex "v" is the last added point
return true; return true;
} }
@ -330,13 +346,13 @@ void Simplex::backupClosestPointInSimplex(Vector3& v) {
decimal minDistSquare = DECIMAL_LARGEST; decimal minDistSquare = DECIMAL_LARGEST;
Bits bit; Bits bit;
for (bit = allBits; bit != 0x0; bit--) { for (bit = mAllBits; bit != 0x0; bit--) {
if (isSubset(bit, allBits) && isProperSubset(bit)) { if (isSubset(bit, mAllBits) && isProperSubset(bit)) {
Vector3 u = computeClosestPointForSubset(bit); Vector3 u = computeClosestPointForSubset(bit);
decimal distSquare = u.dot(u); decimal distSquare = u.dot(u);
if (distSquare < minDistSquare) { if (distSquare < minDistSquare) {
minDistSquare = distSquare; minDistSquare = distSquare;
bitsCurrentSimplex = bit; mBitsCurrentSimplex = bit;
v = u; v = u;
} }
} }
@ -347,7 +363,7 @@ void Simplex::backupClosestPointInSimplex(Vector3& v) {
// represented by the bits "subset" // represented by the bits "subset"
Vector3 Simplex::computeClosestPointForSubset(Bits subset) { Vector3 Simplex::computeClosestPointForSubset(Bits subset) {
Vector3 v(0.0, 0.0, 0.0); // Closet point v = sum(lambda_i * points[i]) Vector3 v(0.0, 0.0, 0.0); // Closet point v = sum(lambda_i * points[i])
maxLengthSquare = 0.0; mMaxLengthSquare = 0.0;
decimal deltaX = 0.0; // deltaX = sum of all det[subset][i] decimal deltaX = 0.0; // deltaX = sum of all det[subset][i]
int i; int i;
Bits bit; Bits bit;
@ -357,14 +373,14 @@ Vector3 Simplex::computeClosestPointForSubset(Bits subset) {
// If the current point is in the subset // If the current point is in the subset
if (overlap(subset, bit)) { if (overlap(subset, bit)) {
// deltaX = sum of all det[subset][i] // deltaX = sum of all det[subset][i]
deltaX += det[subset][i]; deltaX += mDet[subset][i];
if (maxLengthSquare < pointsLengthSquare[i]) { if (mMaxLengthSquare < mPointsLengthSquare[i]) {
maxLengthSquare = pointsLengthSquare[i]; mMaxLengthSquare = mPointsLengthSquare[i];
} }
// Closest point v = sum(lambda_i * points[i]) // Closest point v = sum(lambda_i * points[i])
v += det[subset][i] * points[i]; v += mDet[subset][i] * mPoints[i];
} }
} }
@ -372,4 +388,4 @@ Vector3 Simplex::computeClosestPointForSubset(Bits subset) {
// Return the closet point "v" in the convex hull for the given subset // Return the closet point "v" in the convex hull for the given subset
return (1.0 / deltaX) * v; return (1.0 / deltaX) * v;
} }

View File

@ -47,43 +47,117 @@ typedef unsigned int Bits;
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class Simplex { class Simplex {
private:
Vector3 points[4]; // Current points
decimal pointsLengthSquare[4]; // pointsLengthSquare[i] = (points[i].length)^2
decimal maxLengthSquare; // Maximum length of pointsLengthSquare[i]
Vector3 suppPointsA[4]; // Support points of object A in local coordinates
Vector3 suppPointsB[4]; // Support points of object B in local coordinates
Vector3 diffLength[4][4]; // diff[i][j] contains points[i] - points[j]
decimal det[16][4]; // Cached determinant values
decimal normSquare[4][4]; // norm[i][j] = (diff[i][j].length())^2
Bits bitsCurrentSimplex; // 4 bits that identify the current points of the simplex
// For instance, 0101 means that points[1] and points[3] are in the simplex
Bits lastFound; // Number between 1 and 4 that identify the last found support point
Bits lastFoundBit; // Position of the last found support point (lastFoundBit = 0x1 << lastFound)
Bits allBits; // allBits = bitsCurrentSimplex | lastFoundBit;
bool overlap(Bits a, Bits b) const; // Return true if some bits of "a" overlap with bits of "b" private:
bool isSubset(Bits a, Bits b) const; // Return true if the bits of "b" is a subset of the bits of "a"
bool isValidSubset(Bits subset) const; // Return true if the subset is a valid one for the closest point computation // -------------------- Attributes -------------------- //
bool isProperSubset(Bits subset) const; // Return true if the subset is a proper subset
void updateCache(); // Update the cached values used during the GJK algorithm // Current points
void computeDeterminants(); // Compute the cached determinant values Vector3 mPoints[4];
Vector3 computeClosestPointForSubset(Bits subset); // Return the closest point "v" in the convex hull of a subset of points
// pointsLengthSquare[i] = (points[i].length)^2
decimal mPointsLengthSquare[4];
// Maximum length of pointsLengthSquare[i]
decimal mMaxLengthSquare;
// Support points of object A in local coordinates
Vector3 mSuppPointsA[4];
// Support points of object B in local coordinates
Vector3 mSuppPointsB[4];
// diff[i][j] contains points[i] - points[j]
Vector3 mDiffLength[4][4];
// Cached determinant values
decimal mDet[16][4];
// norm[i][j] = (diff[i][j].length())^2
decimal mNormSquare[4][4];
// 4 bits that identify the current points of the simplex
// For instance, 0101 means that points[1] and points[3] are in the simplex
Bits mBitsCurrentSimplex;
// Number between 1 and 4 that identify the last found support point
Bits mLastFound;
// Position of the last found support point (lastFoundBit = 0x1 << lastFound)
Bits mLastFoundBit;
// allBits = bitsCurrentSimplex | lastFoundBit;
Bits mAllBits;
// -------------------- Methods -------------------- //
// Private copy-constructor
Simplex(const Simplex& simplex);
// Private assignment operator
Simplex& operator=(const Simplex& simplex);
// Return true if some bits of "a" overlap with bits of "b"
bool overlap(Bits a, Bits b) const;
// Return true if the bits of "b" is a subset of the bits of "a"
bool isSubset(Bits a, Bits b) const;
// Return true if the subset is a valid one for the closest point computation
bool isValidSubset(Bits subset) const;
// Return true if the subset is a proper subset
bool isProperSubset(Bits subset) const;
// Update the cached values used during the GJK algorithm
void updateCache();
// Compute the cached determinant values
void computeDeterminants();
// Return the closest point "v" in the convex hull of a subset of points
Vector3 computeClosestPointForSubset(Bits subset);
public: public:
Simplex(); // Constructor
~Simplex(); // Destructor
bool isFull() const; // Return true if the simplex contains 4 points // -------------------- Methods -------------------- //
bool isEmpty() const; // Return true if the simple is empty
unsigned int getSimplex(Vector3* suppPointsA, Vector3* suppPointsB, Vector3* points) const; // Return the points of the simplex // Constructor
decimal getMaxLengthSquareOfAPoint() const; // Return the maximum squared length of a point Simplex();
void addPoint(const Vector3& point, const Vector3& suppPointA, const Vector3& suppPointB); // Addd a point to the simplex
bool isPointInSimplex(const Vector3& point) const; // Return true if the point is in the simplex // Destructor
bool isAffinelyDependent() const; // Return true if the set is affinely dependent ~Simplex();
void backupClosestPointInSimplex(Vector3& point); // Backup the closest point
void computeClosestPointsOfAandB(Vector3& pA, Vector3& pB) const; // Compute the closest points of object A and B // Return true if the simplex contains 4 points
bool computeClosestPoint(Vector3& v); // Compute the closest point to the origin of the current simplex bool isFull() const;
// Return true if the simple is empty
bool isEmpty() const;
// Return the points of the simplex
unsigned int getSimplex(Vector3* mSuppPointsA, Vector3* mSuppPointsB,
Vector3* mPoints) const;
// Return the maximum squared length of a point
decimal getMaxLengthSquareOfAPoint() const;
// Addd a point to the simplex
void addPoint(const Vector3& point, const Vector3& suppPointA, const Vector3& suppPointB);
// Return true if the point is in the simplex
bool isPointInSimplex(const Vector3& point) const;
// Return true if the set is affinely dependent
bool isAffinelyDependent() const;
// Backup the closest point
void backupClosestPointInSimplex(Vector3& point);
// Compute the closest points of object A and B
void computeClosestPointsOfAandB(Vector3& pA, Vector3& pB) const;
// Compute the closest point to the origin of the current simplex
bool computeClosestPoint(Vector3& v);
}; };
// Return true if some bits of "a" overlap with bits of "b" // Return true if some bits of "a" overlap with bits of "b"
@ -98,19 +172,19 @@ inline bool Simplex::isSubset(Bits a, Bits b) const {
// Return true if the simplex contains 4 points // Return true if the simplex contains 4 points
inline bool Simplex::isFull() const { inline bool Simplex::isFull() const {
return (bitsCurrentSimplex == 0xf); return (mBitsCurrentSimplex == 0xf);
} }
// Return true if the simple is empty // Return true if the simple is empty
inline bool Simplex::isEmpty() const { inline bool Simplex::isEmpty() const {
return (bitsCurrentSimplex == 0x0); return (mBitsCurrentSimplex == 0x0);
} }
// Return the maximum squared length of a point // Return the maximum squared length of a point
inline decimal Simplex::getMaxLengthSquareOfAPoint() const { inline decimal Simplex::getMaxLengthSquareOfAPoint() const {
return maxLengthSquare; return mMaxLengthSquare;
} }
} // End of the ReactPhysics3D namespace } // End of the ReactPhysics3D namespace
#endif #endif

View File

@ -31,7 +31,7 @@ using namespace reactphysics3d;
// Constructor // Constructor
NarrowPhaseAlgorithm::NarrowPhaseAlgorithm(MemoryPool<ContactInfo>& memoryPool) NarrowPhaseAlgorithm::NarrowPhaseAlgorithm(MemoryPool<ContactInfo>& memoryPool)
:memoryPoolContactInfos(memoryPool), currentOverlappingPair(0) { :mMemoryPoolContactInfos(memoryPool), mCurrentOverlappingPair(0) {
} }

View File

@ -47,23 +47,49 @@ namespace reactphysics3d {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class NarrowPhaseAlgorithm { class NarrowPhaseAlgorithm {
protected : protected :
MemoryPool<ContactInfo>& memoryPoolContactInfos; // Reference to the memory pool for contact infos
BroadPhasePair* currentOverlappingPair; // Overlapping pair of the bodies currently tested for collision // -------------------- Attributes -------------------- //
// Reference to the memory pool
MemoryPool<ContactInfo>& mMemoryPoolContactInfos;
// Overlapping pair of the bodies currently tested for collision
BroadPhasePair* mCurrentOverlappingPair;
// -------------------- Methods -------------------- //
// Private copy-constructor
NarrowPhaseAlgorithm(const NarrowPhaseAlgorithm& algorithm);
// Private assignment operator
NarrowPhaseAlgorithm& operator=(const NarrowPhaseAlgorithm& algorithm);
public : public :
NarrowPhaseAlgorithm(MemoryPool<ContactInfo>& memoryPool); // Constructor
virtual ~NarrowPhaseAlgorithm(); // Destructor // -------------------- Methods -------------------- //
// Constructor
NarrowPhaseAlgorithm(MemoryPool<ContactInfo>& memoryPool);
// Destructor
virtual ~NarrowPhaseAlgorithm();
void setCurrentOverlappingPair(BroadPhasePair* overlappingPair); // Set the current overlapping pair of bodies // Set the current overlapping pair of bodies
virtual bool testCollision(const CollisionShape* collisionShape1, const Transform& transform1, void setCurrentOverlappingPair(BroadPhasePair* overlappingPair);
const CollisionShape* collisionShape2, const Transform& transform2,
ContactInfo*& contactInfo)=0; // Return true and compute a contact info if the two bounding volume collide // Return true and compute a contact info if the two bounding volume collide
virtual bool testCollision(const CollisionShape* collisionShape1,
const Transform& transform1,
const CollisionShape* collisionShape2,
const Transform& transform2,
ContactInfo*& contactInfo)=0;
}; };
// Set the current overlapping pair of bodies // Set the current overlapping pair of bodies
inline void NarrowPhaseAlgorithm::setCurrentOverlappingPair(BroadPhasePair *overlappingPair) { inline void NarrowPhaseAlgorithm::setCurrentOverlappingPair(BroadPhasePair *overlappingPair) {
currentOverlappingPair = overlappingPair; mCurrentOverlappingPair = overlappingPair;
} }
} // End of reactphysics3d namespace } // End of reactphysics3d namespace

View File

@ -41,8 +41,11 @@ SphereVsSphereAlgorithm::~SphereVsSphereAlgorithm() {
} }
bool SphereVsSphereAlgorithm::testCollision(const CollisionShape* collisionShape1, const Transform& transform1, bool SphereVsSphereAlgorithm::testCollision(const CollisionShape* collisionShape1,
const CollisionShape* collisionShape2, const Transform& transform2, ContactInfo*& contactInfo) { const Transform& transform1,
const CollisionShape* collisionShape2,
const Transform& transform2,
ContactInfo*& contactInfo) {
// Get the sphere collision shapes // Get the sphere collision shapes
const SphereShape* sphereShape1 = dynamic_cast<const SphereShape*>(collisionShape1); const SphereShape* sphereShape1 = dynamic_cast<const SphereShape*>(collisionShape1);
@ -59,13 +62,16 @@ bool SphereVsSphereAlgorithm::testCollision(const CollisionShape* collisionShape
if (squaredDistanceBetweenCenters <= sumRadius * sumRadius) { if (squaredDistanceBetweenCenters <= sumRadius * sumRadius) {
Vector3 centerSphere2InBody1LocalSpace = transform1.inverse() * transform2.getPosition(); Vector3 centerSphere2InBody1LocalSpace = transform1.inverse() * transform2.getPosition();
Vector3 centerSphere1InBody2LocalSpace = transform2.inverse() * transform1.getPosition(); Vector3 centerSphere1InBody2LocalSpace = transform2.inverse() * transform1.getPosition();
Vector3 intersectionOnBody1 = sphereShape1->getRadius() * centerSphere2InBody1LocalSpace.getUnit(); Vector3 intersectionOnBody1 = sphereShape1->getRadius() *
Vector3 intersectionOnBody2 = sphereShape2->getRadius() * centerSphere1InBody2LocalSpace.getUnit(); centerSphere2InBody1LocalSpace.getUnit();
Vector3 intersectionOnBody2 = sphereShape2->getRadius() *
centerSphere1InBody2LocalSpace.getUnit();
decimal penetrationDepth = sumRadius - std::sqrt(squaredDistanceBetweenCenters); decimal penetrationDepth = sumRadius - std::sqrt(squaredDistanceBetweenCenters);
// Create the contact info object // Create the contact info object
contactInfo = new (memoryPoolContactInfos.allocateObject()) ContactInfo(vectorBetweenCenters.getUnit(), penetrationDepth, contactInfo = new (mMemoryPoolContactInfos.allocateObject()) ContactInfo(
intersectionOnBody1, intersectionOnBody2); vectorBetweenCenters.getUnit(), penetrationDepth,
intersectionOnBody1, intersectionOnBody2);
return true; return true;
} }

View File

@ -42,15 +42,33 @@ namespace reactphysics3d {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class SphereVsSphereAlgorithm : public NarrowPhaseAlgorithm { class SphereVsSphereAlgorithm : public NarrowPhaseAlgorithm {
protected : protected :
// -------------------- Methods -------------------- //
// Private copy-constructor
SphereVsSphereAlgorithm(const SphereVsSphereAlgorithm& algorithm);
// Private assignment operator
SphereVsSphereAlgorithm& operator=(const SphereVsSphereAlgorithm& algorithm);
public : public :
SphereVsSphereAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos); // Constructor
virtual ~SphereVsSphereAlgorithm(); // Destructor
virtual bool testCollision(const CollisionShape* collisionShape1, const Transform& transform1, // -------------------- Methods -------------------- //
const CollisionShape* collisionShape2, const Transform& transform2,
ContactInfo*& contactInfo); // Return true and compute a contact info if the two bounding volume collide // Constructor
SphereVsSphereAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos);
// Destructor
virtual ~SphereVsSphereAlgorithm();
// Return true and compute a contact info if the two bounding volume collide
virtual bool testCollision(const CollisionShape* collisionShape1,
const Transform& transform1,
const CollisionShape* collisionShape2,
const Transform& transform2,
ContactInfo*& contactInfo);
}; };
} // End of reactphysics3d namespace } // End of reactphysics3d namespace

View File

@ -45,18 +45,18 @@ using namespace reactphysics3d;
using namespace std; using namespace std;
// Constructor // Constructor
AABB::AABB() : bodyPointer(0) { AABB::AABB() : mBodyPointer(0) {
} }
// Constructor // Constructor
AABB::AABB(const Vector3& minCoordinates, const Vector3& maxCoordinates, Body* bodyPointer) AABB::AABB(const Vector3& minCoordinates, const Vector3& maxCoordinates, Body* modyPointer)
:minCoordinates(minCoordinates), maxCoordinates(maxCoordinates), bodyPointer(bodyPointer) { :mMinCoordinates(minCoordinates), mMaxCoordinates(maxCoordinates), mBodyPointer(modyPointer) {
} }
// Constructor // Constructor
AABB::AABB(const Transform& transform, const Vector3& extents) : bodyPointer(0) { AABB::AABB(const Transform& transform, const Vector3& extents) : mBodyPointer(0) {
update(transform, extents); update(transform, extents);
} }
@ -74,41 +74,41 @@ void AABB::draw() const {
// Draw the AABB // Draw the AABB
glBegin(GL_LINES); glBegin(GL_LINES);
glVertex3f(maxCoordinates.getX(), minCoordinates.getY(), minCoordinates.getZ()); glVertex3f(mMaxCoordinates.getX(), mMinCoordinates.getY(), mMinCoordinates.getZ());
glVertex3f(maxCoordinates.getX(), maxCoordinates.getY(), minCoordinates.getZ()); glVertex3f(mMaxCoordinates.getX(), mMaxCoordinates.getY(), mMinCoordinates.getZ());
glVertex3f(maxCoordinates.getX(), minCoordinates.getY(), minCoordinates.getZ()); glVertex3f(mMaxCoordinates.getX(), mMinCoordinates.getY(), mMinCoordinates.getZ());
glVertex3f(maxCoordinates.getX(), minCoordinates.getY(), maxCoordinates.getZ()); glVertex3f(mMaxCoordinates.getX(), mMinCoordinates.getY(), mMaxCoordinates.getZ());
glVertex3f(maxCoordinates.getX(), minCoordinates.getY(), maxCoordinates.getZ()); glVertex3f(mMaxCoordinates.getX(), mMinCoordinates.getY(), mMaxCoordinates.getZ());
glVertex3f(maxCoordinates.getX(), maxCoordinates.getY(), maxCoordinates.getZ()); glVertex3f(mMaxCoordinates.getX(), mMaxCoordinates.getY(), mMaxCoordinates.getZ());
glVertex3f(maxCoordinates.getX(), maxCoordinates.getY(), minCoordinates.getZ()); glVertex3f(mMaxCoordinates.getX(), mMaxCoordinates.getY(), mMinCoordinates.getZ());
glVertex3f(maxCoordinates.getX(), maxCoordinates.getY(), maxCoordinates.getZ()); glVertex3f(mMaxCoordinates.getX(), mMaxCoordinates.getY(), mMaxCoordinates.getZ());
glVertex3f(minCoordinates.getX(), minCoordinates.getY(), minCoordinates.getZ()); glVertex3f(mMinCoordinates.getX(), mMinCoordinates.getY(), mMinCoordinates.getZ());
glVertex3f(minCoordinates.getX(), maxCoordinates.getY(), minCoordinates.getZ()); glVertex3f(mMinCoordinates.getX(), mMaxCoordinates.getY(), mMinCoordinates.getZ());
glVertex3f(minCoordinates.getX(), minCoordinates.getY(), minCoordinates.getZ()); glVertex3f(mMinCoordinates.getX(), mMinCoordinates.getY(), mMinCoordinates.getZ());
glVertex3f(minCoordinates.getX(), minCoordinates.getY(), maxCoordinates.getZ()); glVertex3f(mMinCoordinates.getX(), mMinCoordinates.getY(), mMaxCoordinates.getZ());
glVertex3f(minCoordinates.getX(), minCoordinates.getY(), maxCoordinates.getZ()); glVertex3f(mMinCoordinates.getX(), mMinCoordinates.getY(), mMaxCoordinates.getZ());
glVertex3f(minCoordinates.getX(), maxCoordinates.getY(), maxCoordinates.getZ()); glVertex3f(mMinCoordinates.getX(), mMaxCoordinates.getY(), mMaxCoordinates.getZ());
glVertex3f(minCoordinates.getX(), maxCoordinates.getY(), minCoordinates.getZ()); glVertex3f(mMinCoordinates.getX(), mMaxCoordinates.getY(), mMinCoordinates.getZ());
glVertex3f(minCoordinates.getX(), maxCoordinates.getY(), maxCoordinates.getZ()); glVertex3f(mMinCoordinates.getX(), mMaxCoordinates.getY(), mMaxCoordinates.getZ());
glVertex3f(minCoordinates.getX(), minCoordinates.getY(), minCoordinates.getZ()); glVertex3f(mMinCoordinates.getX(), mMinCoordinates.getY(), mMinCoordinates.getZ());
glVertex3f(maxCoordinates.getX(), minCoordinates.getY(), minCoordinates.getZ()); glVertex3f(mMaxCoordinates.getX(), mMinCoordinates.getY(), mMinCoordinates.getZ());
glVertex3f(minCoordinates.getX(), maxCoordinates.getY(), minCoordinates.getZ()); glVertex3f(mMinCoordinates.getX(), mMaxCoordinates.getY(), mMinCoordinates.getZ());
glVertex3f(maxCoordinates.getX(), maxCoordinates.getY(), minCoordinates.getZ()); glVertex3f(mMaxCoordinates.getX(), mMaxCoordinates.getY(), mMinCoordinates.getZ());
glVertex3f(minCoordinates.getX(), maxCoordinates.getY(), maxCoordinates.getZ()); glVertex3f(mMinCoordinates.getX(), mMaxCoordinates.getY(), mMaxCoordinates.getZ());
glVertex3f(maxCoordinates.getX(), maxCoordinates.getY(), maxCoordinates.getZ()); glVertex3f(mMaxCoordinates.getX(), mMaxCoordinates.getY(), mMaxCoordinates.getZ());
glVertex3f(minCoordinates.getX(), minCoordinates.getY(), maxCoordinates.getZ()); glVertex3f(mMinCoordinates.getX(), mMinCoordinates.getY(), mMaxCoordinates.getZ());
glVertex3f(maxCoordinates.getX(), minCoordinates.getY(), maxCoordinates.getZ()); glVertex3f(mMaxCoordinates.getX(), mMinCoordinates.getY(), mMaxCoordinates.getZ());
glEnd(); glEnd();
} }

View File

@ -44,60 +44,107 @@ class Body;
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class AABB { class AABB {
private : private :
Vector3 minCoordinates; // Minimum world coordinates of the AABB on the x,y and z axis
Vector3 maxCoordinates; // Maximum world coordinates of the AABB on the x,y and z axis // -------------------- Attributes -------------------- //
Body* bodyPointer; // Pointer to the owner body (not the abstract class Body but its derivative which is instanciable)
// Minimum world coordinates of the AABB on the x,y and z axis
Vector3 mMinCoordinates;
// Maximum world coordinates of the AABB on the x,y and z axis
Vector3 mMaxCoordinates;
// Pointer to the owner body (not the abstract class Body
// but its derivative which is instanciable)
Body* mBodyPointer;
// -------------------- Methods -------------------- //
// Private copy-constructor
AABB(const AABB& aabb);
// Private assignment operator
AABB& operator=(const AABB& aabb);
public : public :
AABB(); // Constructor
AABB(const Vector3& minCoordinates, const Vector3& maxCoordinates, Body* bodyPointer); // Constructor
AABB(const Transform& transform, const Vector3& extents); // Constructor
virtual ~AABB(); // Destructor
Vector3 getCenter() const; // Return the center point // -------------------- Methods -------------------- //
const Vector3& getMin() const; // Return the minimum coordinates of the AABB
const Vector3& getMax() const; // Return the maximum coordinates of the AABB // Constructor
Body* getBodyPointer() const; // Return a pointer to the owner body AABB();
void setBodyPointer(Body* bodyPointer); // Set the body pointer
bool testCollision(const AABB& aabb) const; // Return true if the current AABB is overlapping is the AABB in argument // Constructor
virtual void update(const Transform& newTransform, const Vector3& extents); // Update the oriented bounding box orientation according to a new orientation of the rigid body AABB(const Vector3& minCoordinates, const Vector3& maxCoordinates, Body* modyPointer);
// Constructor
AABB(const Transform& transform, const Vector3& extents);
// Destructor
virtual ~AABB();
// Return the center point
Vector3 getCenter() const;
// Return the minimum coordinates of the AABB
const Vector3& getMin() const;
// Return the maximum coordinates of the AABB
const Vector3& getMax() const;
// Return a pointer to the owner body
Body* getBodyPointer() const;
// Set the body pointer
void setBodyPointer(Body* bodyPointer);
// Return true if the current AABB is overlapping is the AABB in argument
bool testCollision(const AABB& aabb) const;
// Update the oriented bounding box orientation
// according to a new orientation of the rigid body
virtual void update(const Transform& newTransform, const Vector3& extents);
#ifdef VISUAL_DEBUG #ifdef VISUAL_DEBUG
virtual void draw() const; // Draw the AABB (only for testing purpose) // Draw the AABB (only for testing purpose)
virtual void draw() const;
#endif #endif
}; };
// Return the center point of the AABB in world coordinates // Return the center point of the AABB in world coordinates
inline Vector3 AABB::getCenter() const { inline Vector3 AABB::getCenter() const {
return (minCoordinates + maxCoordinates) * 0.5; return (mMinCoordinates + mMaxCoordinates) * 0.5;
} }
// Return the minimum coordinates of the AABB // Return the minimum coordinates of the AABB
inline const Vector3& AABB::getMin() const { inline const Vector3& AABB::getMin() const {
return minCoordinates; return mMinCoordinates;
} }
// Return the maximum coordinates of the AABB // Return the maximum coordinates of the AABB
inline const Vector3& AABB::getMax() const { inline const Vector3& AABB::getMax() const {
return maxCoordinates; return mMaxCoordinates;
} }
// Return a pointer to the owner body // Return a pointer to the owner body
inline Body* AABB::getBodyPointer() const { inline Body* AABB::getBodyPointer() const {
return bodyPointer; return mBodyPointer;
} }
// Set the body pointer // Set the body pointer
inline void AABB::setBodyPointer(Body* bodyPointer) { inline void AABB::setBodyPointer(Body* bodyPointer) {
this->bodyPointer = bodyPointer; mBodyPointer = bodyPointer;
} }
// Return true if the current AABB is overlapping with the AABB in argument // Return true if the current AABB is overlapping with the AABB in argument
// Two AABB overlap if they overlap in the three x, y and z axis at the same time // Two AABB overlap if they overlap in the three x, y and z axis at the same time
inline bool AABB::testCollision(const AABB& aabb) const { inline bool AABB::testCollision(const AABB& aabb) const {
if (maxCoordinates.getX() < aabb.minCoordinates.getX() || aabb.maxCoordinates.getX() < minCoordinates.getX()) return false; if (mMaxCoordinates.getX() < aabb.mMinCoordinates.getX() ||
if (maxCoordinates.getY() < aabb.minCoordinates.getY() || aabb.maxCoordinates.getY() < minCoordinates.getY()) return false; aabb.mMaxCoordinates.getX() < mMinCoordinates.getX()) return false;
if (maxCoordinates.getZ() < aabb.minCoordinates.getZ() || aabb.maxCoordinates.getZ() < minCoordinates.getZ()) return false; if (mMaxCoordinates.getY() < aabb.mMinCoordinates.getY() ||
aabb.mMaxCoordinates.getY() < mMinCoordinates.getY()) return false;
if (mMaxCoordinates.getZ() < aabb.mMinCoordinates.getZ() ||
aabb.mMaxCoordinates.getZ() < mMinCoordinates.getZ()) return false;
return true; return true;
} }
@ -107,8 +154,8 @@ inline void AABB::update(const Transform& newTransform, const Vector3& extents)
Vector3 worldExtents = Vector3(worldAxis.getColumn(0).dot(extents), Vector3 worldExtents = Vector3(worldAxis.getColumn(0).dot(extents),
worldAxis.getColumn(1).dot(extents), worldAxis.getColumn(1).dot(extents),
worldAxis.getColumn(2).dot(extents)); worldAxis.getColumn(2).dot(extents));
minCoordinates = newTransform.getPosition() - worldExtents; mMinCoordinates = newTransform.getPosition() - worldExtents;
maxCoordinates = newTransform.getPosition() + worldExtents; mMaxCoordinates = newTransform.getPosition() + worldExtents;
} }
}; // End of the ReactPhysics3D namespace }; // End of the ReactPhysics3D namespace

View File

@ -46,7 +46,7 @@ using namespace reactphysics3d;
using namespace std; using namespace std;
// Constructor // Constructor
BoxShape::BoxShape(const Vector3& extent) : CollisionShape(BOX), extent(extent) { BoxShape::BoxShape(const Vector3& extent) : CollisionShape(BOX), mExtent(extent) {
} }
@ -58,9 +58,9 @@ BoxShape::~BoxShape() {
// Return the local inertia tensor of the collision shape // Return the local inertia tensor of the collision shape
void BoxShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const { void BoxShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const {
decimal factor = (1.0 / 3.0) * mass; decimal factor = (1.0 / 3.0) * mass;
decimal xSquare = extent.getX() * extent.getX(); decimal xSquare = mExtent.getX() * mExtent.getX();
decimal ySquare = extent.getY() * extent.getY(); decimal ySquare = mExtent.getY() * mExtent.getY();
decimal zSquare = extent.getZ() * extent.getZ(); decimal zSquare = mExtent.getZ() * mExtent.getZ();
tensor.setAllValues(factor * (ySquare + zSquare), 0.0, 0.0, tensor.setAllValues(factor * (ySquare + zSquare), 0.0, 0.0,
0.0, factor * (xSquare + zSquare), 0.0, 0.0, factor * (xSquare + zSquare), 0.0,
0.0, 0.0, factor * (xSquare + ySquare)); 0.0, 0.0, factor * (xSquare + ySquare));
@ -69,9 +69,9 @@ void BoxShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const
#ifdef VISUAL_DEBUG #ifdef VISUAL_DEBUG
// Draw the Box (only for testing purpose) // Draw the Box (only for testing purpose)
void BoxShape::draw() const { void BoxShape::draw() const {
decimal e1 = extent.getX(); decimal e1 = mExtent.getX();
decimal e2 = extent.getY(); decimal e2 = mExtent.getY();
decimal e3 = extent.getZ(); decimal e3 = mExtent.getZ();
// Draw in red // Draw in red
glColor3f(1.0, 0.0, 0.0); glColor3f(1.0, 0.0, 0.0);

View File

@ -44,47 +44,76 @@ namespace reactphysics3d {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class BoxShape : public CollisionShape { class BoxShape : public CollisionShape {
private : private :
Vector3 extent; // Extent sizes of the box in the x, y and z direction
// -------------------- Attributes -------------------- //
// Extent sizes of the box in the x, y and z direction
Vector3 mExtent;
// -------------------- Methods -------------------- //
// Private copy-constructor
BoxShape(const BoxShape& shape);
// Private assignment operator
BoxShape& operator=(const BoxShape& shape);
public : public :
BoxShape(const Vector3& extent); // Constructor
virtual ~BoxShape(); // Destructor
const Vector3& getExtent() const; // Return the extents of the box // -------------------- Methods -------------------- //
void setExtent(const Vector3& extent); // Set the extents of the box
virtual Vector3 getLocalExtents(decimal margin=0.0) const; // Return the local extents in x,y and z direction // Constructor
virtual Vector3 getLocalSupportPoint(const Vector3& direction, decimal margin=0.0) const; // Return a local support point in a given direction BoxShape(const Vector3& extent);
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const; // Return the local inertia tensor of the collision shape
// Destructor
virtual ~BoxShape();
// Return the extents of the box
const Vector3& getExtent() const;
// Set the extents of the box
void setExtent(const Vector3& extent);
// Return the local extents in x,y and z direction
virtual Vector3 getLocalExtents(decimal margin=0.0) const;
// Return a local support point in a given direction
virtual Vector3 getLocalSupportPoint(const Vector3& direction, decimal margin=0.0) const;
// Return the local inertia tensor of the collision shape
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const;
#ifdef VISUAL_DEBUG #ifdef VISUAL_DEBUG
virtual void draw() const; // Draw the Box (only for testing purpose) // Draw the Box (only for testing purpose)
virtual void draw() const;
#endif #endif
}; };
// Return the extents of the box // Return the extents of the box
inline const Vector3& BoxShape::getExtent() const { inline const Vector3& BoxShape::getExtent() const {
return extent; return mExtent;
} }
// Set the extents of the box // Set the extents of the box
inline void BoxShape::setExtent(const Vector3& extent) { inline void BoxShape::setExtent(const Vector3& extent) {
this->extent = extent; this->mExtent = extent;
} }
// Return the local extents of the box (half-width) in x,y and z local direction // Return the local extents of the box (half-width) in x,y and z local direction
// This method is used to compute the AABB of the box // This method is used to compute the AABB of the box
inline Vector3 BoxShape::getLocalExtents(decimal margin) const { inline Vector3 BoxShape::getLocalExtents(decimal margin) const {
return extent + Vector3(margin, margin, margin); return mExtent + Vector3(margin, margin, margin);
} }
// Return a local support point in a given direction // Return a local support point in a given direction
inline Vector3 BoxShape::getLocalSupportPoint(const Vector3& direction, decimal margin) const { inline Vector3 BoxShape::getLocalSupportPoint(const Vector3& direction, decimal margin) const {
assert(margin >= 0.0); assert(margin >= 0.0);
return Vector3(direction.getX() < 0.0 ? -extent.getX()-margin : extent.getX()+margin, return Vector3(direction.getX() < 0.0 ? -mExtent.getX()-margin : mExtent.getX()+margin,
direction.getY() < 0.0 ? -extent.getY()-margin : extent.getY()+margin, direction.getY() < 0.0 ? -mExtent.getY()-margin : mExtent.getY()+margin,
direction.getZ() < 0.0 ? -extent.getZ()-margin : extent.getZ()+margin); direction.getZ() < 0.0 ? -mExtent.getZ()-margin : mExtent.getZ()+margin);
} }
}; // End of the ReactPhysics3D namespace }; // End of the ReactPhysics3D namespace

View File

@ -30,7 +30,7 @@
using namespace reactphysics3d; using namespace reactphysics3d;
// Constructor // Constructor
CollisionShape::CollisionShape(CollisionShapeType type) : type(type) { CollisionShape::CollisionShape(CollisionShapeType type) : mType(type) {
} }

View File

@ -49,21 +49,46 @@ class Body;
class CollisionShape { class CollisionShape {
protected : protected :
CollisionShapeType type; // Type of the collision shape
public :
CollisionShape(CollisionShapeType type); // Constructor
virtual ~CollisionShape(); // Destructor
CollisionShapeType getType() const; // Return the type of the collision shapes // -------------------- Attributes -------------------- //
virtual Vector3 getLocalSupportPoint(const Vector3& direction, decimal margin=0.0) const=0; // Return a local support point in a given direction
virtual Vector3 getLocalExtents(decimal margin=0.0) const=0; // Return the local extents in x,y and z direction // Type of the collision shape
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const=0; // Return the local inertia tensor of the collision shapes CollisionShapeType mType;
// -------------------- Methods -------------------- //
// Private copy-constructor
CollisionShape(const CollisionShape& shape);
// Private assignment operator
CollisionShape& operator=(const CollisionShape& shape);
public :
// -------------------- Methods -------------------- //
// Constructor
CollisionShape(CollisionShapeType type);
// Destructor
virtual ~CollisionShape();
// Return the type of the collision shapes
CollisionShapeType getType() const;
// Return a local support point in a given direction
virtual Vector3 getLocalSupportPoint(const Vector3& direction, decimal margin=0.0) const=0;
// Return the local extents in x,y and z direction
virtual Vector3 getLocalExtents(decimal margin=0.0) const=0;
// Return the local inertia tensor of the collision shapes
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const=0;
}; };
// Return the type of the collision shape // Return the type of the collision shape
inline CollisionShapeType CollisionShape::getType() const { inline CollisionShapeType CollisionShape::getType() const {
return type; return mType;
} }
} }

View File

@ -44,12 +44,13 @@
using namespace reactphysics3d; using namespace reactphysics3d;
// Constructor // Constructor
ConeShape::ConeShape(decimal radius, decimal height) : CollisionShape(CONE), radius(radius), halfHeight(height/2.0) { ConeShape::ConeShape(decimal radius, decimal height)
: CollisionShape(CONE), mRadius(radius), mHalfHeight(height/2.0) {
assert(radius > 0.0); assert(radius > 0.0);
assert(halfHeight > 0.0); assert(mHalfHeight > 0.0);
// Compute the sine of the semi-angle at the apex point // Compute the sine of the semi-angle at the apex point
sinTheta = radius / (sqrt(radius * radius + height * height)); mSinTheta = radius / (sqrt(radius * radius + height * height));
} }
// Destructor // Destructor
@ -62,20 +63,20 @@ inline Vector3 ConeShape::getLocalSupportPoint(const Vector3& direction, decimal
assert(margin >= 0.0); assert(margin >= 0.0);
const Vector3& v = direction; const Vector3& v = direction;
decimal sinThetaTimesLengthV = sinTheta * v.length(); decimal sinThetaTimesLengthV = mSinTheta * v.length();
Vector3 supportPoint; Vector3 supportPoint;
if (v.getY() >= sinThetaTimesLengthV) { if (v.getY() >= sinThetaTimesLengthV) {
supportPoint = Vector3(0.0, halfHeight, 0.0); supportPoint = Vector3(0.0, mHalfHeight, 0.0);
} }
else { else {
decimal projectedLength = sqrt(v.getX() * v.getX() + v.getZ() * v.getZ()); decimal projectedLength = sqrt(v.getX() * v.getX() + v.getZ() * v.getZ());
if (projectedLength > MACHINE_EPSILON) { if (projectedLength > MACHINE_EPSILON) {
decimal d = radius / projectedLength; decimal d = mRadius / projectedLength;
supportPoint = Vector3(v.getX() * d, -halfHeight, v.getZ() * d); supportPoint = Vector3(v.getX() * d, -mHalfHeight, v.getZ() * d);
} }
else { else {
supportPoint = Vector3(radius, -halfHeight, 0.0); supportPoint = Vector3(mRadius, -mHalfHeight, 0.0);
} }
} }
@ -99,6 +100,6 @@ void ConeShape::draw() const {
glColor3f(1.0, 0.0, 0.0); glColor3f(1.0, 0.0, 0.0);
// Draw the sphere // Draw the sphere
glutWireCone(radius, 2.0 * halfHeight, 50, 50); glutWireCone(mRadius, 2.0 * mHalfHeight, 50, 50);
} }
#endif #endif

View File

@ -44,64 +44,100 @@ namespace reactphysics3d {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class ConeShape : public CollisionShape { class ConeShape : public CollisionShape {
private : private :
decimal radius; // Radius of the base
decimal halfHeight; // Half height of the cone // -------------------- Attributes -------------------- //
decimal sinTheta; // sine of the semi angle at the apex point
// Radius of the base
decimal mRadius;
// Half height of the cone
decimal mHalfHeight;
// sine of the semi angle at the apex point
decimal mSinTheta;
// -------------------- Methods -------------------- //
// Private copy-constructor
ConeShape(const ConeShape& shape);
// Private assignment operator
ConeShape& operator=(const ConeShape& shape);
public : public :
ConeShape(decimal radius, decimal height); // Constructor
virtual ~ConeShape(); // Destructor
decimal getRadius() const; // Return the radius // -------------------- Methods -------------------- //
void setRadius(decimal radius); // Set the radius
decimal getHeight() const; // Return the height
void setHeight(decimal height); // Set the height
virtual Vector3 getLocalSupportPoint(const Vector3& direction, decimal margin=0.0) const; // Return a support point in a given direction
virtual Vector3 getLocalExtents(decimal margin=0.0) const; // Return the local extents in x,y and z direction
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const; // Return the local inertia tensor of the collision shape
// Constructor
ConeShape(decimal mRadius, decimal height);
// Destructor
virtual ~ConeShape();
// Return the radius
decimal getRadius() const;
// Set the radius
void setRadius(decimal radius);
// Return the height
decimal getHeight() const;
// Set the height
void setHeight(decimal height);
// Return a support point in a given direction
virtual Vector3 getLocalSupportPoint(const Vector3& direction, decimal margin=0.0) const;
// Return the local extents in x,y and z direction
virtual Vector3 getLocalExtents(decimal margin=0.0) const;
// Return the local inertia tensor of the collision shape
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const;
#ifdef VISUAL_DEBUG #ifdef VISUAL_DEBUG
virtual void draw() const; // Draw the sphere (only for testing purpose) // Draw the sphere (only for testing purpose)
virtual void draw() const;
#endif #endif
}; };
// Return the radius // Return the radius
inline decimal ConeShape::getRadius() const { inline decimal ConeShape::getRadius() const {
return radius; return mRadius;
} }
// Set the radius // Set the radius
inline void ConeShape::setRadius(decimal radius) { inline void ConeShape::setRadius(decimal radius) {
this->radius = radius; mRadius = radius;
// Update sine of the semi-angle at the apex point // Update sine of the semi-angle at the apex point
sinTheta = radius / (sqrt(radius * radius + 4 * halfHeight * halfHeight)); mSinTheta = radius / (sqrt(radius * radius + 4 * mHalfHeight * mHalfHeight));
} }
// Return the height // Return the height
inline decimal ConeShape::getHeight() const { inline decimal ConeShape::getHeight() const {
return 2.0 * halfHeight; return 2.0 * mHalfHeight;
} }
// Set the height // Set the height
inline void ConeShape::setHeight(decimal height) { inline void ConeShape::setHeight(decimal height) {
this->halfHeight = height / 2.0; mHalfHeight = height / 2.0;
// Update the sine of the semi-angle at the apex point // Update the sine of the semi-angle at the apex point
sinTheta = radius / (sqrt(radius * radius + height * height)); mSinTheta = mRadius / (sqrt(mRadius * mRadius + height * height));
} }
// Return the local extents in x,y and z direction // Return the local extents in x,y and z direction
inline Vector3 ConeShape::getLocalExtents(decimal margin) const { inline Vector3 ConeShape::getLocalExtents(decimal margin) const {
return Vector3(radius + margin, halfHeight + margin, radius + margin); return Vector3(mRadius + margin, mHalfHeight + margin, mRadius + margin);
} }
// Return the local inertia tensor of the collision shape // Return the local inertia tensor of the collision shape
inline void ConeShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const { inline void ConeShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const {
decimal rSquare = radius * radius; decimal rSquare = mRadius * mRadius;
decimal diagXZ = 0.15 * mass * (rSquare + halfHeight); decimal diagXZ = 0.15 * mass * (rSquare + mHalfHeight);
tensor.setAllValues(diagXZ, 0.0, 0.0, 0.0, 0.3 * mass * rSquare, 0.0, 0.0, 0.0, diagXZ); tensor.setAllValues(diagXZ, 0.0, 0.0, 0.0, 0.3 * mass * rSquare, 0.0, 0.0, 0.0, diagXZ);
} }

View File

@ -44,7 +44,7 @@ using namespace reactphysics3d;
// Constructor // Constructor
CylinderShape::CylinderShape(decimal radius, decimal height) CylinderShape::CylinderShape(decimal radius, decimal height)
: CollisionShape(CYLINDER), radius(radius), halfHeight(height/2.0) { : CollisionShape(CYLINDER), mRadius(radius), mHalfHeight(height/2.0) {
} }
@ -63,13 +63,13 @@ Vector3 CylinderShape::getLocalSupportPoint(const Vector3& direction, decimal ma
decimal lengthW = sqrt(direction.getX() * direction.getX() + direction.getZ() * direction.getZ()); decimal lengthW = sqrt(direction.getX() * direction.getX() + direction.getZ() * direction.getZ());
if (lengthW != 0.0) { if (lengthW != 0.0) {
if (uDotv < 0.0) supportPoint.setY(-halfHeight); if (uDotv < 0.0) supportPoint.setY(-mHalfHeight);
else supportPoint.setY(halfHeight); else supportPoint.setY(mHalfHeight);
supportPoint += (radius / lengthW) * w; supportPoint += (mRadius / lengthW) * w;
} }
else { else {
if (uDotv < 0.0) supportPoint.setY(-halfHeight); if (uDotv < 0.0) supportPoint.setY(-mHalfHeight);
else supportPoint.setY(halfHeight); else supportPoint.setY(mHalfHeight);
} }
// Add the margin to the support point // Add the margin to the support point
@ -92,6 +92,6 @@ void CylinderShape::draw() const {
glColor3f(1.0, 0.0, 0.0); glColor3f(1.0, 0.0, 0.0);
// Draw the sphere // Draw the sphere
glutWireSphere(radius, 50, 50); glutWireSphere(mRadius, 50, 50);
} }
#endif #endif

View File

@ -43,57 +43,92 @@ namespace reactphysics3d {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class CylinderShape : public CollisionShape { class CylinderShape : public CollisionShape {
private : private :
decimal radius; // Radius of the base
decimal halfHeight; // Half height of the cone // -------------------- Attributes -------------------- //
// Radius of the base
decimal mRadius;
// Half height of the cone
decimal mHalfHeight;
// -------------------- Methods -------------------- //
// Private copy-constructor
CylinderShape(const CylinderShape& shape);
// Private assignment operator
CylinderShape& operator=(const CylinderShape& shape);
public : public :
CylinderShape(decimal radius, decimal height); // Constructor
virtual ~CylinderShape(); // Destructor
decimal getRadius() const; // Return the radius // -------------------- Methods -------------------- //
void setRadius(decimal radius); // Set the radius
decimal getHeight() const; // Return the height // Constructor
void setHeight(decimal height); // Set the height CylinderShape(decimal radius, decimal height);
virtual Vector3 getLocalSupportPoint(const Vector3& direction, decimal margin=0.0) const; // Return a support point in a given direction
virtual Vector3 getLocalExtents(decimal margin=0.0) const; // Return the local extents in x,y and z direction // Destructor
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const; // Return the local inertia tensor of the collision shape virtual ~CylinderShape();
// Return the radius
decimal getRadius() const;
// Set the radius
void setRadius(decimal mRadius);
// Return the height
decimal getHeight() const;
// Set the height
void setHeight(decimal height);
// Return a support point in a given direction
virtual Vector3 getLocalSupportPoint(const Vector3& direction, decimal margin=0.0) const;
// Return the local extents in x,y and z direction
virtual Vector3 getLocalExtents(decimal margin=0.0) const;
// Return the local inertia tensor of the collision shape
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const;
#ifdef VISUAL_DEBUG #ifdef VISUAL_DEBUG
virtual void draw() const; // Draw the sphere (only for testing purpose) // Draw the sphere (only for testing purpose)
virtual void draw() const;
#endif #endif
}; };
// Return the radius // Return the radius
inline decimal CylinderShape::getRadius() const { inline decimal CylinderShape::getRadius() const {
return radius; return mRadius;
} }
// Set the radius // Set the radius
inline void CylinderShape::setRadius(decimal radius) { inline void CylinderShape::setRadius(decimal radius) {
this->radius = radius; this->mRadius = radius;
} }
// Return the height // Return the height
inline decimal CylinderShape::getHeight() const { inline decimal CylinderShape::getHeight() const {
return halfHeight * 2.0; return mHalfHeight * 2.0;
} }
// Set the height // Set the height
inline void CylinderShape::setHeight(decimal height) { inline void CylinderShape::setHeight(decimal height) {
this->halfHeight = height / 2.0; this->mHalfHeight = height / 2.0;
} }
// Return the local extents in x,y and z direction // Return the local extents in x,y and z direction
inline Vector3 CylinderShape::getLocalExtents(decimal margin) const { inline Vector3 CylinderShape::getLocalExtents(decimal margin) const {
return Vector3(radius + margin, halfHeight + margin, radius + margin); return Vector3(mRadius + margin, mHalfHeight + margin, mRadius + margin);
} }
// Return the local inertia tensor of the cylinder // Return the local inertia tensor of the cylinder
inline void CylinderShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const { inline void CylinderShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const {
decimal height = 2.0 * halfHeight; decimal height = 2.0 * mHalfHeight;
decimal diag = (1.0 / 12.0) * mass * (3 * radius * radius + height * height); decimal diag = (1.0 / 12.0) * mass * (3 * mRadius * mRadius + height * height);
tensor.setAllValues(diag, 0.0, 0.0, 0.0, 0.5 * mass * radius * radius, 0.0, 0.0, 0.0, diag); tensor.setAllValues(diag, 0.0, 0.0, 0.0, 0.5 * mass * mRadius * mRadius, 0.0, 0.0, 0.0, diag);
} }
}; // End of the ReactPhysics3D namespace }; // End of the ReactPhysics3D namespace

View File

@ -45,7 +45,7 @@ using namespace reactphysics3d;
using namespace std; using namespace std;
// Constructor // Constructor
SphereShape::SphereShape(decimal radius) : CollisionShape(SPHERE), radius(radius) { SphereShape::SphereShape(decimal radius) : CollisionShape(SPHERE), mRadius(radius) {
} }
@ -62,6 +62,6 @@ void SphereShape::draw() const {
glColor3f(1.0, 0.0, 0.0); glColor3f(1.0, 0.0, 0.0);
// Draw the sphere // Draw the sphere
glutWireSphere(radius, 50, 50); glutWireSphere(mRadius, 50, 50);
} }
#endif #endif

View File

@ -40,32 +40,61 @@ namespace reactphysics3d {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class SphereShape : public CollisionShape { class SphereShape : public CollisionShape {
private : private :
decimal radius; // Radius of the sphere
// -------------------- Attributes -------------------- //
// Radius of the sphere
decimal mRadius;
// -------------------- Methods -------------------- //
// Private copy-constructor
SphereShape(const SphereShape& shape);
// Private assignment operator
SphereShape& operator=(const SphereShape& shape);
public : public :
SphereShape(decimal radius); // Constructor
virtual ~SphereShape(); // Destructor
decimal getRadius() const; // Return the radius of the sphere // -------------------- Methods -------------------- //
void setRadius(decimal radius); // Set the radius of the sphere
virtual Vector3 getLocalSupportPoint(const Vector3& direction, decimal margin=0.0) const; // Return a local support point in a given direction // Constructor
virtual Vector3 getLocalExtents(decimal margin=0.0) const; // Return the local extents in x,y and z direction SphereShape(decimal radius);
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const; // Return the local inertia tensor of the collision shape
// Destructor
virtual ~SphereShape();
// Return the radius of the sphere
decimal getRadius() const;
// Set the radius of the sphere
void setRadius(decimal radius);
// Return a local support point in a given direction
virtual Vector3 getLocalSupportPoint(const Vector3& direction, decimal margin=0.0) const;
// Return the local extents in x,y and z direction
virtual Vector3 getLocalExtents(decimal margin=0.0) const;
// Return the local inertia tensor of the collision shape
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const;
#ifdef VISUAL_DEBUG #ifdef VISUAL_DEBUG
virtual void draw() const; // Draw the sphere (only for testing purpose) // Draw the sphere (only for testing purpose)
virtual void draw() const;
#endif #endif
}; };
// Get the radius of the sphere // Get the radius of the sphere
inline decimal SphereShape::getRadius() const { inline decimal SphereShape::getRadius() const {
return radius; return mRadius;
} }
// Set the radius of the sphere // Set the radius of the sphere
inline void SphereShape::setRadius(decimal radius) { inline void SphereShape::setRadius(decimal radius) {
this->radius = radius; mRadius = radius;
} }
// Return a local support point in a given direction // Return a local support point in a given direction
@ -76,23 +105,23 @@ inline Vector3 SphereShape::getLocalSupportPoint(const Vector3& direction, decim
// If the direction vector is not the zero vector // If the direction vector is not the zero vector
if (length > 0.0) { if (length > 0.0) {
// Return the support point of the sphere in the given direction // Return the support point of the sphere in the given direction
return (radius + margin) * direction.getUnit(); return (mRadius + margin) * direction.getUnit();
} }
// If the direction vector is the zero vector we return a point on the // If the direction vector is the zero vector we return a point on the
// boundary of the sphere // boundary of the sphere
return Vector3(0, radius + margin, 0); return Vector3(0, mRadius + margin, 0);
} }
// Return the local extents of the collision shape (half-width) in x,y and z local direction // Return the local extents of the collision shape (half-width) in x,y and z local direction
// This method is used to compute the AABB of the box // This method is used to compute the AABB of the box
inline Vector3 SphereShape::getLocalExtents(decimal margin) const { inline Vector3 SphereShape::getLocalExtents(decimal margin) const {
return Vector3(radius + margin, radius + margin, radius + margin); return Vector3(mRadius + margin, mRadius + margin, mRadius + margin);
} }
// Return the local inertia tensor of the sphere // Return the local inertia tensor of the sphere
inline void SphereShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const { inline void SphereShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const {
decimal diag = 0.4 * mass * radius * radius; decimal diag = 0.4 * mass * mRadius * mRadius;
tensor.setAllValues(diag, 0.0, 0.0, 0.0, diag, 0.0, 0.0, 0.0, diag); tensor.setAllValues(diag, 0.0, 0.0, 0.0, diag, 0.0, 0.0, 0.0, diag);
} }

View File

@ -33,7 +33,7 @@
#include "decimal.h" #include "decimal.h"
// Windows platform // Windows platform
#if defined(WIN32) || defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__WINDOWS__) #if defined(WIN32) ||defined(_WIN32) || defined(_WIN64) ||defined(__WIN32__) || defined(__WINDOWS__)
#define WINDOWS_OS #define WINDOWS_OS
#elif defined(__APPLE__) // Apple platform #elif defined(__APPLE__) // Apple platform
#define APPLE_OS #define APPLE_OS
@ -44,40 +44,61 @@
// Namespace reactphysics3d // Namespace reactphysics3d
namespace reactphysics3d { namespace reactphysics3d {
// Type definitions // ------------------- Type definitions ------------------- //
typedef unsigned int uint; typedef unsigned int uint;
typedef long unsigned int luint; typedef long unsigned int luint;
typedef short unsigned int bodyindex; // TODO : Replace whenever possible using the bodyindex type typedef short unsigned int bodyindex;
typedef std::pair<bodyindex, bodyindex> bodyindexpair; typedef std::pair<bodyindex, bodyindex> bodyindexpair;
// Mathematical constants // ------------------- Constants ------------------- //
const reactphysics3d::decimal DECIMAL_SMALLEST = - std::numeric_limits<reactphysics3d::decimal>::max(); // Minimun decimal value
const reactphysics3d::decimal DECIMAL_LARGEST = std::numeric_limits<reactphysics3d::decimal>::max(); // Maximum decimal value
const reactphysics3d::decimal MACHINE_EPSILON = std::numeric_limits<reactphysics3d::decimal>::epsilon(); // Machine epsilon
const reactphysics3d::decimal DECIMAL_INFINITY = std::numeric_limits<reactphysics3d::decimal>::infinity(); // Infinity
const reactphysics3d::decimal PI = 3.14159265; // Pi constant
// Physics Engine constants const reactphysics3d::decimal DECIMAL_SMALLEST = - std::numeric_limits<decimal>::max();
const reactphysics3d::decimal DEFAULT_TIMESTEP = 1.0 / 60.0; // Default internal constant timestep in seconds
const bool DEACTIVATION_ENABLED = true; // True if the deactivation (sleeping) of inactive bodies is enabled
// GJK Algorithm parameters // Maximum decimal value
const reactphysics3d::decimal OBJECT_MARGIN = 0.04; // Object margin for collision detection in cm const reactphysics3d::decimal DECIMAL_LARGEST = std::numeric_limits<decimal>::max();
// Contact constants // Machine epsilon
const reactphysics3d::decimal FRICTION_COEFFICIENT = 0.4; // Friction coefficient const reactphysics3d::decimal MACHINE_EPSILON = std::numeric_limits<decimal>::epsilon();
const reactphysics3d::decimal PERSISTENT_CONTACT_DIST_THRESHOLD = 0.02; // Distance threshold for two contact points for a valid persistent contact
// Constraint solver constants // Infinity
const int NB_MAX_BODIES = 100000; // Maximum number of bodies const reactphysics3d::decimal DECIMAL_INFINITY = std::numeric_limits<decimal>::infinity();
const int NB_MAX_CONTACTS = 100000; // Maximum number of contacts (for memory pool allocation)
const int NB_MAX_CONSTRAINTS = 100000; // Maximum number of constraints
// Constraint solver constants // Pi constant
const uint DEFAULT_LCP_ITERATIONS = 15; // Number of iterations when solving a LCP problem const reactphysics3d::decimal PI = 3.14159265;
const uint DEFAULT_LCP_ITERATIONS_ERROR_CORRECTION = 5; // Number of iterations when solving a LCP problem for error correction
const bool ERROR_CORRECTION_PROJECTION_ENABLED = true; // True if the error correction projection (first order world) is active in the constraint solver // Default internal constant timestep in seconds
const reactphysics3d::decimal PENETRATION_DEPTH_THRESHOLD_ERROR_CORRECTION = 0.20; // Contacts with penetration depth (in meters) larger that this use error correction with projection const reactphysics3d::decimal DEFAULT_TIMESTEP = 1.0 / 60.0;
// True if the deactivation (sleeping) of inactive bodies is enabled
const bool DEACTIVATION_ENABLED = true;
// // Object margin for collision detection in cm (For GJK-EPA Algorithm)
const reactphysics3d::decimal OBJECT_MARGIN = 0.04;
// Friction coefficient
const reactphysics3d::decimal FRICTION_COEFFICIENT = 0.4;
// Distance threshold for two contact points for a valid persistent contact
const reactphysics3d::decimal PERSISTENT_CONTACT_DIST_THRESHOLD = 0.02;
// Maximum number of bodies
const int NB_MAX_BODIES = 100000;
// Maximum number of constraints
const int NB_MAX_CONSTRAINTS = 100000;
// Number of iterations when solving a LCP problem
const uint DEFAULT_LCP_ITERATIONS = 15;
// Number of iterations when solving a LCP problem for error correction
const uint DEFAULT_LCP_ITERATIONS_ERROR_CORRECTION = 5;
// True if the error correction projection (first order world) is active in the constraint solver
const bool ERROR_CORRECTION_PROJECTION_ENABLED = true;
// Contacts with penetration depth (in meters) larger that this use error correction with projection
const reactphysics3d::decimal PENETRATION_DEPTH_THRESHOLD_ERROR_CORRECTION = 0.20;
} }

View File

@ -30,12 +30,14 @@
using namespace reactphysics3d; using namespace reactphysics3d;
// Constructor // Constructor
Constraint::Constraint(RigidBody* const body1, RigidBody* const body2, uint nbConstraints, bool active, ConstraintType type) Constraint::Constraint(RigidBody* const body1, RigidBody* const body2,
:body1(body1), body2(body2), active(active), nbConstraints(nbConstraints), type(type) { uint nbConstraints, bool active, ConstraintType type)
:mBody1(body1), mBody2(body2), mActive(active),
mNbConstraints(nbConstraints), mType(type) {
// Initialize the cached lambda values // Initialize the cached lambda values
for (int i=0; i<nbConstraints; i++) { for (int i=0; i<nbConstraints; i++) {
cachedLambdas.push_back(0.0); mCachedLambdas.push_back(0.0);
} }
} }

View File

@ -45,67 +45,122 @@ enum ConstraintType {CONTACT};
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class Constraint { class Constraint {
protected : protected :
RigidBody* const body1; // Pointer to the first body of the constraint
RigidBody* const body2; // Pointer to the second body of the constraint // -------------------- Attributes -------------------- //
bool active; // True if the constraint is active
uint nbConstraints; // Number mathematical constraints associated with this Constraint // Pointer to the first body of the constraint
const ConstraintType type; // Type of the constraint RigidBody* const mBody1;
std::vector<decimal> cachedLambdas; // Cached lambda values of each mathematical constraint for more precise initializaton of LCP solver
// Pointer to the second body of the constraint
RigidBody* const mBody2;
// True if the constraint is active
bool mActive;
// Number mathematical constraints associated with this Constraint
uint mNbConstraints;
// Type of the constraint
const ConstraintType mType;
// Cached lambda values of each mathematical constraint for
// more precise initializaton of LCP solver
std::vector<decimal> mCachedLambdas;
// -------------------- Methods -------------------- //
// Private copy-constructor
Constraint(const Constraint& constraint);
// Private assignment operator
Constraint& operator=(const Constraint& constraint);
public : public :
// -------------------- Methods -------------------- //
// Constructor
Constraint(RigidBody* const body1, RigidBody* const body2, uint nbConstraints, Constraint(RigidBody* const body1, RigidBody* const body2, uint nbConstraints,
bool active, ConstraintType type); // Constructor // Constructor bool active, ConstraintType type);
virtual ~Constraint(); // Destructor
RigidBody* const getBody1() const; // Return the reference to the body 1 // Destructor
RigidBody* const getBody2() const; // Return the reference to the body 2 // Evaluate the constraint virtual ~Constraint();
bool isActive() const; // Return true if the constraint is active // Return the jacobian matrix of body 2
ConstraintType getType() const; // Return the type of the constraint // Return the reference to the body 1
virtual void computeJacobian(int noConstraint, decimal J_sp[NB_MAX_CONSTRAINTS][2*6]) const=0; // Compute the jacobian matrix for all mathematical constraints RigidBody* const getBody1() const;
virtual void computeLowerBound(int noConstraint, decimal lowerBounds[NB_MAX_CONSTRAINTS]) const=0; // Compute the lowerbounds values for all the mathematical constraints
virtual void computeUpperBound(int noConstraint, decimal upperBounds[NB_MAX_CONSTRAINTS]) const=0; // Compute the upperbounds values for all the mathematical constraints // Return the reference to the body 2
virtual void computeErrorValue(int noConstraint, decimal errorValues[]) const=0; // Compute the error values for all the mathematical constraints RigidBody* const getBody2() const;
unsigned int getNbConstraints() const; // Return the number of mathematical constraints // Return the number of auxiliary constraints
decimal getCachedLambda(int index) const; // Get one cached lambda value // Return true if the constraint is active
void setCachedLambda(int index, decimal lambda); // Set on cached lambda value bool isActive() const;
// Return the type of the constraint
ConstraintType getType() const;
// Compute the jacobian matrix for all mathematical constraints
virtual void computeJacobian(int noConstraint,
decimal J_sp[NB_MAX_CONSTRAINTS][2*6]) const=0;
// Compute the lowerbounds values for all the mathematical constraints
virtual void computeLowerBound(int noConstraint,
decimal lowerBounds[NB_MAX_CONSTRAINTS]) const=0;
// Compute the upperbounds values for all the mathematical constraints
virtual void computeUpperBound(int noConstraint,
decimal upperBounds[NB_MAX_CONSTRAINTS]) const=0;
// Compute the error values for all the mathematical constraints
virtual void computeErrorValue(int noConstraint, decimal errorValues[]) const=0;
// Return the number of mathematical constraints
unsigned int getNbConstraints() const;
// Get one cached lambda value
decimal getCachedLambda(int index) const;
// Set on cached lambda value
void setCachedLambda(int index, decimal lambda);
}; };
// Return the reference to the body 1 // Return the reference to the body 1
inline RigidBody* const Constraint::getBody1() const { inline RigidBody* const Constraint::getBody1() const {
return body1; return mBody1;
} }
// Return the reference to the body 2 // Return the reference to the body 2
inline RigidBody* const Constraint::getBody2() const { inline RigidBody* const Constraint::getBody2() const {
return body2; return mBody2;
} }
// Return true if the constraint is active // Return true if the constraint is active
inline bool Constraint::isActive() const { inline bool Constraint::isActive() const {
return active; return mActive;
} }
// Return the type of the constraint // Return the type of the constraint
inline ConstraintType Constraint::getType() const { inline ConstraintType Constraint::getType() const {
return type; return mType;
} }
// Return the number auxiliary constraints // Return the number auxiliary constraints
inline uint Constraint::getNbConstraints() const { inline uint Constraint::getNbConstraints() const {
return nbConstraints; return mNbConstraints;
} }
// Get one previous lambda value // Get one previous lambda value
inline decimal Constraint::getCachedLambda(int index) const { inline decimal Constraint::getCachedLambda(int index) const {
assert(index >= 0 && index < nbConstraints); assert(index >= 0 && index < mNbConstraints);
return cachedLambdas[index]; return mCachedLambdas[index];
} }
// Set on cached lambda value // Set on cached lambda value
inline void Constraint::setCachedLambda(int index, decimal lambda) { inline void Constraint::setCachedLambda(int index, decimal lambda) {
assert(index >= 0 && index < nbConstraints); assert(index >= 0 && index < mNbConstraints);
cachedLambdas[index] = lambda; mCachedLambdas[index] = lambda;
} }

View File

@ -31,15 +31,18 @@ using namespace std;
// Constructor // Constructor
Contact::Contact(RigidBody* const body1, RigidBody* const body2, const ContactInfo* contactInfo) Contact::Contact(RigidBody* const body1, RigidBody* const body2, const ContactInfo* contactInfo)
: Constraint(body1, body2, 3, true, CONTACT), normal(contactInfo->normal), penetrationDepth(contactInfo->penetrationDepth), : Constraint(body1, body2, 3, true, CONTACT), mNormal(contactInfo->normal),
localPointOnBody1(contactInfo->localPoint1), localPointOnBody2(contactInfo->localPoint2), mPenetrationDepth(contactInfo->penetrationDepth),
worldPointOnBody1(body1->getTransform() * contactInfo->localPoint1), worldPointOnBody2(body2->getTransform() * contactInfo->localPoint2) { mLocalPointOnBody1(contactInfo->localPoint1),
assert(penetrationDepth > 0.0); mLocalPointOnBody2(contactInfo->localPoint2),
mWorldPointOnBody1(body1->getTransform() * contactInfo->localPoint1),
mWorldPointOnBody2(body2->getTransform() * contactInfo->localPoint2) {
assert(mPenetrationDepth > 0.0);
// Compute the auxiliary lower and upper bounds // Compute the auxiliary lower and upper bounds
// TODO : Now mC is only the mass of the first body but it is probably wrong // TODO : Now mC is only the mass of the first body but it is probably wrong
// TODO : Now g is 9.81 but we should use the true gravity value of the physics world. // TODO : Now g is 9.81 but we should use the true gravity value of the physics world.
mu_mc_g = FRICTION_COEFFICIENT * body1->getMass() * 9.81; mMu_mc_g = FRICTION_COEFFICIENT * body1->getMass() * 9.81;
// Compute the friction vectors that span the tangential friction plane // Compute the friction vectors that span the tangential friction plane
computeFrictionVectors(); computeFrictionVectors();
@ -56,30 +59,30 @@ Contact::~Contact() {
// of the contact. The argument "noConstraint", is the row were the method have // of the contact. The argument "noConstraint", is the row were the method have
// to start to fill in the J_sp matrix. // to start to fill in the J_sp matrix.
void Contact::computeJacobian(int noConstraint, decimal J_sp[NB_MAX_CONSTRAINTS][2*6]) const { void Contact::computeJacobian(int noConstraint, decimal J_sp[NB_MAX_CONSTRAINTS][2*6]) const {
assert(body1); assert(mBody1);
assert(body2); assert(mBody2);
Vector3 body1Position = body1->getTransform().getPosition(); Vector3 body1Position = mBody1->getTransform().getPosition();
Vector3 body2Position = body2->getTransform().getPosition(); Vector3 body2Position = mBody2->getTransform().getPosition();
int currentIndex = noConstraint; // Current constraint index int currentIndex = noConstraint; // Current constraint index
Vector3 r1 = worldPointOnBody1 - body1Position; Vector3 r1 = mWorldPointOnBody1 - body1Position;
Vector3 r2 = worldPointOnBody2 - body2Position; Vector3 r2 = mWorldPointOnBody2 - body2Position;
Vector3 r1CrossN = r1.cross(normal); Vector3 r1CrossN = r1.cross(mNormal);
Vector3 r2CrossN = r2.cross(normal); Vector3 r2CrossN = r2.cross(mNormal);
// Compute the jacobian matrix for the body 1 for the contact constraint // Compute the jacobian matrix for the body 1 for the contact constraint
J_sp[currentIndex][0] = -normal.getX(); J_sp[currentIndex][0] = -mNormal.getX();
J_sp[currentIndex][1] = -normal.getY(); J_sp[currentIndex][1] = -mNormal.getY();
J_sp[currentIndex][2] = -normal.getZ(); J_sp[currentIndex][2] = -mNormal.getZ();
J_sp[currentIndex][3] = -r1CrossN.getX(); J_sp[currentIndex][3] = -r1CrossN.getX();
J_sp[currentIndex][4] = -r1CrossN.getY(); J_sp[currentIndex][4] = -r1CrossN.getY();
J_sp[currentIndex][5] = -r1CrossN.getZ(); J_sp[currentIndex][5] = -r1CrossN.getZ();
// Compute the jacobian matrix for the body 2 for the contact constraint // Compute the jacobian matrix for the body 2 for the contact constraint
J_sp[currentIndex][6] = normal.getX(); J_sp[currentIndex][6] = mNormal.getX();
J_sp[currentIndex][7] = normal.getY(); J_sp[currentIndex][7] = mNormal.getY();
J_sp[currentIndex][8] = normal.getZ(); J_sp[currentIndex][8] = mNormal.getZ();
J_sp[currentIndex][9] = r2CrossN.getX(); J_sp[currentIndex][9] = r2CrossN.getX();
J_sp[currentIndex][10] = r2CrossN.getY(); J_sp[currentIndex][10] = r2CrossN.getY();
J_sp[currentIndex][11] = r2CrossN.getZ(); J_sp[currentIndex][11] = r2CrossN.getZ();
@ -87,21 +90,21 @@ void Contact::computeJacobian(int noConstraint, decimal J_sp[NB_MAX_CONSTRAINTS]
currentIndex++; currentIndex++;
// Compute the jacobian matrix for the body 1 for the first friction constraint // Compute the jacobian matrix for the body 1 for the first friction constraint
Vector3 r1CrossU1 = r1.cross(frictionVectors[0]); Vector3 r1CrossU1 = r1.cross(mFrictionVectors[0]);
Vector3 r2CrossU1 = r2.cross(frictionVectors[0]); Vector3 r2CrossU1 = r2.cross(mFrictionVectors[0]);
Vector3 r1CrossU2 = r1.cross(frictionVectors[1]); Vector3 r1CrossU2 = r1.cross(mFrictionVectors[1]);
Vector3 r2CrossU2 = r2.cross(frictionVectors[1]); Vector3 r2CrossU2 = r2.cross(mFrictionVectors[1]);
J_sp[currentIndex][0] = -frictionVectors[0].getX(); J_sp[currentIndex][0] = -mFrictionVectors[0].getX();
J_sp[currentIndex][1] = -frictionVectors[0].getY(); J_sp[currentIndex][1] = -mFrictionVectors[0].getY();
J_sp[currentIndex][2] = -frictionVectors[0].getZ(); J_sp[currentIndex][2] = -mFrictionVectors[0].getZ();
J_sp[currentIndex][3] = -r1CrossU1.getX(); J_sp[currentIndex][3] = -r1CrossU1.getX();
J_sp[currentIndex][4] = -r1CrossU1.getY(); J_sp[currentIndex][4] = -r1CrossU1.getY();
J_sp[currentIndex][5] = -r1CrossU1.getZ(); J_sp[currentIndex][5] = -r1CrossU1.getZ();
// Compute the jacobian matrix for the body 2 for the first friction constraint // Compute the jacobian matrix for the body 2 for the first friction constraint
J_sp[currentIndex][6] = frictionVectors[0].getX(); J_sp[currentIndex][6] = mFrictionVectors[0].getX();
J_sp[currentIndex][7] = frictionVectors[0].getY(); J_sp[currentIndex][7] = mFrictionVectors[0].getY();
J_sp[currentIndex][8] = frictionVectors[0].getZ(); J_sp[currentIndex][8] = mFrictionVectors[0].getZ();
J_sp[currentIndex][9] = r2CrossU1.getX(); J_sp[currentIndex][9] = r2CrossU1.getX();
J_sp[currentIndex][10] = r2CrossU1.getY(); J_sp[currentIndex][10] = r2CrossU1.getY();
J_sp[currentIndex][11] = r2CrossU1.getZ(); J_sp[currentIndex][11] = r2CrossU1.getZ();
@ -109,17 +112,17 @@ void Contact::computeJacobian(int noConstraint, decimal J_sp[NB_MAX_CONSTRAINTS]
currentIndex++; currentIndex++;
// Compute the jacobian matrix for the body 1 for the second friction constraint // Compute the jacobian matrix for the body 1 for the second friction constraint
J_sp[currentIndex][0] = -frictionVectors[1].getX(); J_sp[currentIndex][0] = -mFrictionVectors[1].getX();
J_sp[currentIndex][1] = -frictionVectors[1].getY(); J_sp[currentIndex][1] = -mFrictionVectors[1].getY();
J_sp[currentIndex][2] = -frictionVectors[1].getZ(); J_sp[currentIndex][2] = -mFrictionVectors[1].getZ();
J_sp[currentIndex][3] = -r1CrossU2.getX(); J_sp[currentIndex][3] = -r1CrossU2.getX();
J_sp[currentIndex][4] = -r1CrossU2.getY(); J_sp[currentIndex][4] = -r1CrossU2.getY();
J_sp[currentIndex][5] = -r1CrossU2.getZ(); J_sp[currentIndex][5] = -r1CrossU2.getZ();
// Compute the jacobian matrix for the body 2 for the second friction constraint // Compute the jacobian matrix for the body 2 for the second friction constraint
J_sp[currentIndex][6] = frictionVectors[1].getX(); J_sp[currentIndex][6] = mFrictionVectors[1].getX();
J_sp[currentIndex][7] = frictionVectors[1].getY(); J_sp[currentIndex][7] = mFrictionVectors[1].getY();
J_sp[currentIndex][8] = frictionVectors[1].getZ(); J_sp[currentIndex][8] = mFrictionVectors[1].getZ();
J_sp[currentIndex][9] = r2CrossU2.getX(); J_sp[currentIndex][9] = r2CrossU2.getX();
J_sp[currentIndex][10] = r2CrossU2.getY(); J_sp[currentIndex][10] = r2CrossU2.getY();
J_sp[currentIndex][11] = r2CrossU2.getZ(); J_sp[currentIndex][11] = r2CrossU2.getZ();
@ -129,42 +132,42 @@ void Contact::computeJacobian(int noConstraint, decimal J_sp[NB_MAX_CONSTRAINTS]
// argument "lowerBounds" is the lowerbounds values vector of the constraint solver and // argument "lowerBounds" is the lowerbounds values vector of the constraint solver and
// this methods has to fill in this vector starting from the row "noConstraint" // this methods has to fill in this vector starting from the row "noConstraint"
void Contact::computeLowerBound(int noConstraint, decimal lowerBounds[NB_MAX_CONSTRAINTS]) const { void Contact::computeLowerBound(int noConstraint, decimal lowerBounds[NB_MAX_CONSTRAINTS]) const {
assert(noConstraint >= 0 && noConstraint + nbConstraints <= NB_MAX_CONSTRAINTS); assert(noConstraint >= 0 && noConstraint + mNbConstraints <= NB_MAX_CONSTRAINTS);
lowerBounds[noConstraint] = 0.0; // Lower bound for the contact constraint lowerBounds[noConstraint] = 0.0; // Lower bound for the contact constraint
lowerBounds[noConstraint + 1] = -mu_mc_g; // Lower bound for the first friction constraint lowerBounds[noConstraint + 1] = -mMu_mc_g; // Lower bound for the first friction constraint
lowerBounds[noConstraint + 2] = -mu_mc_g; // Lower bound for the second friction constraint lowerBounds[noConstraint + 2] = -mMu_mc_g; // Lower bound for the second friction constraint
} }
// Compute the upperbounds values for all the mathematical constraints. The // Compute the upperbounds values for all the mathematical constraints. The
// argument "upperBounds" is the upperbounds values vector of the constraint solver and // argument "upperBounds" is the upperbounds values vector of the constraint solver and
// this methods has to fill in this vector starting from the row "noConstraint" // this methods has to fill in this vector starting from the row "noConstraint"
void Contact::computeUpperBound(int noConstraint, decimal upperBounds[NB_MAX_CONSTRAINTS]) const { void Contact::computeUpperBound(int noConstraint, decimal upperBounds[NB_MAX_CONSTRAINTS]) const {
assert(noConstraint >= 0 && noConstraint + nbConstraints <= NB_MAX_CONSTRAINTS); assert(noConstraint >= 0 && noConstraint + mNbConstraints <= NB_MAX_CONSTRAINTS);
upperBounds[noConstraint] = DECIMAL_INFINITY; // Upper bound for the contact constraint upperBounds[noConstraint] = DECIMAL_INFINITY; // Upper bound for the contact constraint
upperBounds[noConstraint + 1] = mu_mc_g; // Upper bound for the first friction constraint upperBounds[noConstraint + 1] = mMu_mc_g; // Upper bound for the first friction constraint
upperBounds[noConstraint + 2] = mu_mc_g; // Upper bound for the second friction constraint upperBounds[noConstraint + 2] = mMu_mc_g; // Upper bound for the second friction constraint
} }
// Compute the error values for all the mathematical constraints. The argument // Compute the error values for all the mathematical constraints. The argument
// "errorValues" is the error values vector of the constraint solver and this // "errorValues" is the error values vector of the constraint solver and this
// method has to fill in this vector starting from the row "noConstraint" // method has to fill in this vector starting from the row "noConstraint"
void Contact::computeErrorValue(int noConstraint, decimal errorValues[]) const { void Contact::computeErrorValue(int noConstraint, decimal errorValues[]) const {
assert(body1); assert(mBody1);
assert(body2); assert(mBody2);
// TODO : Do we need this casting anymore ? // TODO : Do we need this casting anymore ?
RigidBody* rigidBody1 = dynamic_cast<RigidBody*>(body1); RigidBody* rigidBody1 = dynamic_cast<RigidBody*>(mBody1);
RigidBody* rigidBody2 = dynamic_cast<RigidBody*>(body2); RigidBody* rigidBody2 = dynamic_cast<RigidBody*>(mBody2);
assert(noConstraint >= 0 && noConstraint + nbConstraints <= NB_MAX_CONSTRAINTS); assert(noConstraint >= 0 && noConstraint + mNbConstraints <= NB_MAX_CONSTRAINTS);
// Compute the error value for the contact constraint // Compute the error value for the contact constraint
Vector3 velocity1 = rigidBody1->getLinearVelocity(); Vector3 velocity1 = rigidBody1->getLinearVelocity();
Vector3 velocity2 = rigidBody2->getLinearVelocity(); Vector3 velocity2 = rigidBody2->getLinearVelocity();
decimal restitutionCoeff = rigidBody1->getRestitution() * rigidBody2->getRestitution(); decimal restitutionCoeff = rigidBody1->getRestitution() * rigidBody2->getRestitution();
decimal errorValue = restitutionCoeff * (normal.dot(velocity1) - normal.dot(velocity2)); decimal errorValue = restitutionCoeff * (mNormal.dot(velocity1) - mNormal.dot(velocity2));
// Assign the error value to the vector of error values // Assign the error value to the vector of error values
errorValues[noConstraint] = errorValue; // Error value for contact constraint errorValues[noConstraint] = errorValue; // Error value for contact constraint

View File

@ -64,36 +64,98 @@ namespace reactphysics3d {
class Contact : public Constraint { class Contact : public Constraint {
protected : protected :
const Vector3 normal; // Normal vector of the contact (From body1 toward body2) in world space
decimal penetrationDepth; // Penetration depth // -------------------- Attributes -------------------- //
const Vector3 localPointOnBody1; // Contact point on body 1 in local space of body 1
const Vector3 localPointOnBody2; // Contact point on body 2 in local space of body 2 // Normal vector of the contact (From body1 toward body2) in world space
Vector3 worldPointOnBody1; // Contact point on body 1 in world space const Vector3 mNormal;
Vector3 worldPointOnBody2; // Contact point on body 2 in world space
std::vector<Vector3> frictionVectors; // Two orthogonal vectors that span the tangential friction plane // Penetration depth
decimal mu_mc_g; decimal mPenetrationDepth;
// Contact point on body 1 in local space of body 1
const Vector3 mLocalPointOnBody1;
// Contact point on body 2 in local space of body 2
const Vector3 mLocalPointOnBody2;
// Contact point on body 1 in world space
Vector3 mWorldPointOnBody1;
// Contact point on body 2 in world space
Vector3 mWorldPointOnBody2;
// Two orthogonal vectors that span the tangential friction plane
std::vector<Vector3> mFrictionVectors;
decimal mMu_mc_g;
void computeFrictionVectors(); // Compute the two friction vectors that span the tangential friction plane // -------------------- Methods -------------------- //
// Private copy-constructor
Contact(const Contact& contact);
// Private assignment operator
Contact& operator=(const Contact& contact);
// Compute the two friction vectors that span the tangential friction plane
void computeFrictionVectors();
public : public :
Contact(RigidBody* const body1, RigidBody* const body2, const ContactInfo* contactInfo); // Constructor
virtual ~Contact(); // Destructor
Vector3 getNormal() const; // Return the normal vector of the contact // -------------------- Methods -------------------- //
void setPenetrationDepth(decimal penetrationDepth); // Set the penetration depth of the contact
Vector3 getLocalPointOnBody1() const; // Return the contact local point on body 1 // Constructor
Vector3 getLocalPointOnBody2() const; // Return the contact local point on body 2 Contact(RigidBody* const body1, RigidBody* const body2, const ContactInfo* contactInfo);
Vector3 getWorldPointOnBody1() const; // Return the contact world point on body 1
Vector3 getWorldPointOnBody2() const; // Return the contact world point on body 2 // Destructor
void setWorldPointOnBody1(const Vector3& worldPoint); // Set the contact world point on body 1 virtual ~Contact();
void setWorldPointOnBody2(const Vector3& worldPoint); // Set the contact world point on body 2
virtual void computeJacobian(int noConstraint, decimal J_SP[NB_MAX_CONSTRAINTS][2*6]) const; // Compute the jacobian matrix for all mathematical constraints // Return the normal vector of the contact
virtual void computeLowerBound(int noConstraint, decimal lowerBounds[NB_MAX_CONSTRAINTS]) const; // Compute the lowerbounds values for all the mathematical constraints Vector3 getNormal() const;
virtual void computeUpperBound(int noConstraint, decimal upperBounds[NB_MAX_CONSTRAINTS]) const; // Compute the upperbounds values for all the mathematical constraints
virtual void computeErrorValue(int noConstraint, decimal errorValues[]) const; // Compute the error values for all the mathematical constraints // Set the penetration depth of the contact
decimal getPenetrationDepth() const; // Return the penetration depth void setPenetrationDepth(decimal penetrationDepth);
// Return the contact local point on body 1
Vector3 getLocalPointOnBody1() const;
// Return the contact local point on body 2
Vector3 getLocalPointOnBody2() const;
// Return the contact world point on body 1
Vector3 getWorldPointOnBody1() const;
// Return the contact world point on body 2
Vector3 getWorldPointOnBody2() const;
// Set the contact world point on body 1
void setWorldPointOnBody1(const Vector3& worldPoint);
// Set the contact world point on body 2
void setWorldPointOnBody2(const Vector3& worldPoint);
// Compute the jacobian matrix for all mathematical constraints
virtual void computeJacobian(int noConstraint,
decimal J_SP[NB_MAX_CONSTRAINTS][2*6]) const;
// Compute the lowerbounds values for all the mathematical constraints
virtual void computeLowerBound(int noConstraint,
decimal lowerBounds[NB_MAX_CONSTRAINTS]) const;
// Compute the upperbounds values for all the mathematical constraints
virtual void computeUpperBound(int noConstraint,
decimal upperBounds[NB_MAX_CONSTRAINTS]) const;
// Compute the error values for all the mathematical constraints
virtual void computeErrorValue(int noConstraint, decimal errorValues[]) const;
// Return the penetration depth
decimal getPenetrationDepth() const;
#ifdef VISUAL_DEBUG #ifdef VISUAL_DEBUG
void draw() const; // Draw the contact (for debugging) // Draw the contact (for debugging)
void draw() const;
#endif #endif
}; };
@ -101,59 +163,59 @@ class Contact : public Constraint {
// The two vectors have to be such that : v1 x v2 = contactNormal // The two vectors have to be such that : v1 x v2 = contactNormal
inline void Contact::computeFrictionVectors() { inline void Contact::computeFrictionVectors() {
// Delete the current friction vectors // Delete the current friction vectors
frictionVectors.clear(); mFrictionVectors.clear();
// Compute the first orthogonal vector // Compute the first orthogonal vector
Vector3 vector1 = normal.getOneOrthogonalVector(); Vector3 vector1 = mNormal.getOneOrthogonalVector();
frictionVectors.push_back(vector1); mFrictionVectors.push_back(vector1);
// Compute the second orthogonal vector using the cross product // Compute the second orthogonal vector using the cross product
frictionVectors.push_back(normal.cross(vector1)); mFrictionVectors.push_back(mNormal.cross(vector1));
} }
// Return the normal vector of the contact // Return the normal vector of the contact
inline Vector3 Contact::getNormal() const { inline Vector3 Contact::getNormal() const {
return normal; return mNormal;
} }
// Set the penetration depth of the contact // Set the penetration depth of the contact
inline void Contact::setPenetrationDepth(decimal penetrationDepth) { inline void Contact::setPenetrationDepth(decimal penetrationDepth) {
this->penetrationDepth = penetrationDepth; this->mPenetrationDepth = penetrationDepth;
} }
// Return the contact point on body 1 // Return the contact point on body 1
inline Vector3 Contact::getLocalPointOnBody1() const { inline Vector3 Contact::getLocalPointOnBody1() const {
return localPointOnBody1; return mLocalPointOnBody1;
} }
// Return the contact point on body 2 // Return the contact point on body 2
inline Vector3 Contact::getLocalPointOnBody2() const { inline Vector3 Contact::getLocalPointOnBody2() const {
return localPointOnBody2; return mLocalPointOnBody2;
} }
// Return the contact world point on body 1 // Return the contact world point on body 1
inline Vector3 Contact::getWorldPointOnBody1() const { inline Vector3 Contact::getWorldPointOnBody1() const {
return worldPointOnBody1; return mWorldPointOnBody1;
} }
// Return the contact world point on body 2 // Return the contact world point on body 2
inline Vector3 Contact::getWorldPointOnBody2() const { inline Vector3 Contact::getWorldPointOnBody2() const {
return worldPointOnBody2; return mWorldPointOnBody2;
} }
// Set the contact world point on body 1 // Set the contact world point on body 1
inline void Contact::setWorldPointOnBody1(const Vector3& worldPoint) { inline void Contact::setWorldPointOnBody1(const Vector3& worldPoint) {
worldPointOnBody1 = worldPoint; mWorldPointOnBody1 = worldPoint;
} }
// Set the contact world point on body 2 // Set the contact world point on body 2
inline void Contact::setWorldPointOnBody2(const Vector3& worldPoint) { inline void Contact::setWorldPointOnBody2(const Vector3& worldPoint) {
worldPointOnBody2 = worldPoint; mWorldPointOnBody2 = worldPoint;
} }
// Return the penetration depth of the contact // Return the penetration depth of the contact
inline decimal Contact::getPenetrationDepth() const { inline decimal Contact::getPenetrationDepth() const {
return penetrationDepth; return mPenetrationDepth;
} }

View File

@ -32,7 +32,7 @@ using namespace reactphysics3d;
using namespace std; using namespace std;
// Constructor // Constructor
CollisionWorld::CollisionWorld() : collisionDetection(this), currentBodyID(0) { CollisionWorld::CollisionWorld() : mCollisionDetection(this), mCurrentBodyID(0) {
} }
// Destructor // Destructor
@ -53,7 +53,8 @@ void CollisionWorld::notifyRemovedOverlappingPair(const BroadPhasePair* removedP
} }
// Notify the world about a new narrow-phase contact // Notify the world about a new narrow-phase contact
void CollisionWorld::notifyNewContact(const BroadPhasePair* broadPhasePair, const ContactInfo* contactInfo) { void CollisionWorld::notifyNewContact(const BroadPhasePair* broadPhasePair,
const ContactInfo* contactInfo) {
// TODO : Implement this method // TODO : Implement this method
} }
@ -64,7 +65,8 @@ inline void CollisionWorld::updateOverlappingPair(const BroadPhasePair* pair) {
} }
// Create a collision body and add it to the world // Create a collision body and add it to the world
CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform, CollisionShape* collisionShape) { CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform,
CollisionShape* collisionShape) {
// Get the next available body ID // Get the next available body ID
bodyindex bodyID = computeNextAvailableBodyID(); bodyindex bodyID = computeNextAvailableBodyID();
@ -73,13 +75,14 @@ CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform, C
assert(bodyID < std::numeric_limits<reactphysics3d::bodyindex>::max()); assert(bodyID < std::numeric_limits<reactphysics3d::bodyindex>::max());
// Create the collision body // Create the collision body
CollisionBody* collisionBody = new (memoryPoolCollisionBodies.allocateObject()) CollisionBody(transform, collisionShape, bodyID); CollisionBody* collisionBody = new (mMemoryPoolCollisionBodies.allocateObject())
CollisionBody(transform, collisionShape, bodyID);
// Add the collision body to the world // Add the collision body to the world
bodies.insert(collisionBody); mBodies.insert(collisionBody);
// Add the collision body to the collision detection // Add the collision body to the collision detection
collisionDetection.addBody(collisionBody); mCollisionDetection.addBody(collisionBody);
// Return the pointer to the rigid body // Return the pointer to the rigid body
return collisionBody; return collisionBody;
@ -89,19 +92,19 @@ CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform, C
void CollisionWorld::destroyCollisionBody(CollisionBody* collisionBody) { void CollisionWorld::destroyCollisionBody(CollisionBody* collisionBody) {
// Remove the body from the collision detection // Remove the body from the collision detection
collisionDetection.removeBody(collisionBody); mCollisionDetection.removeBody(collisionBody);
// Add the body ID to the list of free IDs // Add the body ID to the list of free IDs
freeBodiesIDs.push_back(collisionBody->getID()); mFreeBodiesIDs.push_back(collisionBody->getID());
// Call the constructor of the collision body // Call the constructor of the collision body
collisionBody->CollisionBody::~CollisionBody(); collisionBody->CollisionBody::~CollisionBody();
// Remove the collision body from the list of bodies // Remove the collision body from the list of bodies
bodies.erase(collisionBody); // TOOD : Maybe use a set to make this faster mBodies.erase(collisionBody); // TOOD : Maybe use a set to make this faster
// Free the object from the memory pool // Free the object from the memory pool
memoryPoolCollisionBodies.freeObject(collisionBody); mMemoryPoolCollisionBodies.freeObject(collisionBody);
} }
// Return the next available body ID // Return the next available body ID
@ -109,13 +112,13 @@ bodyindex CollisionWorld::computeNextAvailableBodyID() {
// Compute the body ID // Compute the body ID
bodyindex bodyID; bodyindex bodyID;
if (!freeBodiesIDs.empty()) { if (!mFreeBodiesIDs.empty()) {
bodyID = freeBodiesIDs.back(); bodyID = mFreeBodiesIDs.back();
freeBodiesIDs.pop_back(); mFreeBodiesIDs.pop_back();
} }
else { else {
bodyID = currentBodyID; bodyID = mCurrentBodyID;
currentBodyID++; mCurrentBodyID++;
} }
return bodyID; return bodyID;

View File

@ -51,41 +51,86 @@ namespace reactphysics3d {
class CollisionWorld { class CollisionWorld {
protected : protected :
CollisionDetection collisionDetection; // Reference to the collision detection
std::set<CollisionBody*> bodies; // All the bodies (rigid and soft) of the physics world
std::map<std::pair<bodyindex, bodyindex>, OverlappingPair*> overlappingPairs; // Broad-phase overlapping pairs of bodies
bodyindex currentBodyID; // Current body ID
MemoryPool<CollisionBody> memoryPoolCollisionBodies; // Memory pool for rigid bodies memory allocation
std::vector<luint> freeBodiesIDs; // List of free ID for rigid bodies
virtual void notifyAddedOverlappingPair(const BroadPhasePair* addedPair); // Notify the world about a new broad-phase overlapping pair // -------------------- Attributes -------------------- //
virtual void notifyRemovedOverlappingPair(const BroadPhasePair* removedPair); // Notify the world about a removed broad-phase overlapping pair
virtual void notifyNewContact(const BroadPhasePair* pair, const ContactInfo* contactInfo); // Notify the world about a new narrow-phase contact
virtual void updateOverlappingPair(const BroadPhasePair* pair); // Update the overlapping pair
bodyindex computeNextAvailableBodyID(); // Return the next available body ID
// Reference to the collision detection
CollisionDetection mCollisionDetection;
// All the bodies (rigid and soft) of the world
std::set<CollisionBody*> mBodies;
// Broad-phase overlapping pairs of bodies
std::map<bodyindexpair, OverlappingPair*> mOverlappingPairs;
// Current body ID
bodyindex mCurrentBodyID;
// Memory pool
MemoryPool<CollisionBody> mMemoryPoolCollisionBodies;
// List of free ID for rigid bodies
std::vector<luint> mFreeBodiesIDs;
// -------------------- Methods -------------------- //
// Private copy-constructor
CollisionWorld(const CollisionWorld& world);
// Private assignment operator
CollisionWorld& operator=(const CollisionWorld& world);
// Notify the world about a new broad-phase overlapping pair
virtual void notifyAddedOverlappingPair(const BroadPhasePair* addedPair);
// Notify the world about a removed broad-phase overlapping pair
virtual void notifyRemovedOverlappingPair(const BroadPhasePair* removedPair);
// Notify the world about a new narrow-phase contact
virtual void notifyNewContact(const BroadPhasePair* pair, const ContactInfo* contactInfo);
// Update the overlapping pair
virtual void updateOverlappingPair(const BroadPhasePair* pair);
// Return the next available body ID
bodyindex computeNextAvailableBodyID();
public : public :
CollisionWorld(); // Constructor
virtual ~CollisionWorld(); // Destructor
std::set<CollisionBody*>::iterator getBodiesBeginIterator(); // Return an iterator to the beginning of the bodies of the physics world
std::set<CollisionBody*>::iterator getBodiesEndIterator(); // Return an iterator to the end of the bodies of the physics world
CollisionBody* createCollisionBody(const Transform& transform,
CollisionShape* collisionShape); // Create a collision body
void destroyCollisionBody(CollisionBody* collisionBody); // Destroy a collision body
// Friends // ----- Methods ----- //
// Constructor
CollisionWorld();
// Destructor
virtual ~CollisionWorld();
// Return an iterator to the beginning of the bodies of the physics world
std::set<CollisionBody*>::iterator getBodiesBeginIterator();
// Return an iterator to the end of the bodies of the physics world
std::set<CollisionBody*>::iterator getBodiesEndIterator();
// Create a collision body
CollisionBody* createCollisionBody(const Transform& transform,
CollisionShape* collisionShape);
// Destroy a collision body
void destroyCollisionBody(CollisionBody* collisionBody);
// ----- Friends ----- //
friend class CollisionDetection; friend class CollisionDetection;
}; };
// Return an iterator to the beginning of the bodies of the physics world // Return an iterator to the beginning of the bodies of the physics world
inline std::set<CollisionBody*>::iterator CollisionWorld::getBodiesBeginIterator() { inline std::set<CollisionBody*>::iterator CollisionWorld::getBodiesBeginIterator() {
return bodies.begin(); return mBodies.begin();
} }
// Return an iterator to the end of the bodies of the physics world // Return an iterator to the end of the bodies of the physics world
inline std::set<CollisionBody*>::iterator CollisionWorld::getBodiesEndIterator() { inline std::set<CollisionBody*>::iterator CollisionWorld::getBodiesEndIterator() {
return bodies.end(); return mBodies.end();
} }
} // End of the ReactPhysics3D namespace } // End of the ReactPhysics3D namespace

View File

@ -32,8 +32,8 @@ using namespace std;
// Constructor // Constructor
DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_TIMESTEP) DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_TIMESTEP)
: CollisionWorld(), timer(timeStep), gravity(gravity), isGravityOn(true), constraintSolver(this), : CollisionWorld(), mTimer(timeStep), mGravity(gravity), mIsGravityOn(true), mConstraintSolver(this),
isDeactivationActive(DEACTIVATION_ENABLED) { mIsDeactivationActive(DEACTIVATION_ENABLED) {
} }
@ -41,10 +41,10 @@ DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_
DynamicsWorld::~DynamicsWorld() { DynamicsWorld::~DynamicsWorld() {
// Delete the remaining overlapping pairs // Delete the remaining overlapping pairs
for (map<std::pair<bodyindex, bodyindex>, OverlappingPair*>::iterator it=overlappingPairs.begin(); it != overlappingPairs.end(); it++) { for (map<std::pair<bodyindex, bodyindex>, OverlappingPair*>::iterator it=mOverlappingPairs.begin(); it != mOverlappingPairs.end(); it++) {
// Delete the overlapping pair // Delete the overlapping pair
(*it).second->OverlappingPair::~OverlappingPair(); (*it).second->OverlappingPair::~OverlappingPair();
memoryPoolOverlappingPairs.freeObject((*it).second); mMemoryPoolOverlappingPairs.freeObject((*it).second);
} }
} }
@ -52,31 +52,31 @@ DynamicsWorld::~DynamicsWorld() {
void DynamicsWorld::update() { void DynamicsWorld::update() {
bool existCollision = false; bool existCollision = false;
assert(timer.getIsRunning()); assert(mTimer.getIsRunning());
// Compute the time since the last update() call and update the timer // Compute the time since the last update() call and update the timer
timer.update(); mTimer.update();
// Apply the gravity force to all bodies // Apply the gravity force to all bodies
applyGravity(); applyGravity();
// While the time accumulator is not empty // While the time accumulator is not empty
while(timer.isPossibleToTakeStep()) { while(mTimer.isPossibleToTakeStep()) {
existCollision = false; existCollision = false;
removeAllContactConstraints(); removeAllContactConstraints();
// Compute the collision detection // Compute the collision detection
if (collisionDetection.computeCollisionDetection()) { if (mCollisionDetection.computeCollisionDetection()) {
existCollision = true; existCollision = true;
// Solve constraints // Solve constraints
constraintSolver.solve(timer.getTimeStep()); mConstraintSolver.solve(mTimer.getTimeStep());
} }
// Update the timer // Update the timer
timer.nextStep(); mTimer.nextStep();
// Reset the movement boolean variable of each body to false // Reset the movement boolean variable of each body to false
resetBodiesMovementVariable(); resetBodiesMovementVariable();
@ -86,7 +86,7 @@ void DynamicsWorld::update() {
// Cleanup of the constraint solver // Cleanup of the constraint solver
if (existCollision) { if (existCollision) {
constraintSolver.cleanup(); mConstraintSolver.cleanup();
} }
} }
@ -104,7 +104,7 @@ void DynamicsWorld::update() {
// This method uses the semi-implicit Euler method to update the position and // This method uses the semi-implicit Euler method to update the position and
// orientation of the body // orientation of the body
void DynamicsWorld::updateAllBodiesMotion() { void DynamicsWorld::updateAllBodiesMotion() {
decimal dt = timer.getTimeStep(); decimal dt = mTimer.getTimeStep();
Vector3 newLinearVelocity; Vector3 newLinearVelocity;
Vector3 newAngularVelocity; Vector3 newAngularVelocity;
Vector3 linearVelocityErrorCorrection; Vector3 linearVelocityErrorCorrection;
@ -124,13 +124,13 @@ void DynamicsWorld::updateAllBodiesMotion() {
angularVelocityErrorCorrection.setAllValues(0.0, 0.0, 0.0); angularVelocityErrorCorrection.setAllValues(0.0, 0.0, 0.0);
// If it's a constrained body // If it's a constrained body
if (constraintSolver.isConstrainedBody(*it)) { if (mConstraintSolver.isConstrainedBody(*it)) {
// Get the constrained linear and angular velocities from the constraint solver // Get the constrained linear and angular velocities from the constraint solver
newLinearVelocity = constraintSolver.getConstrainedLinearVelocityOfBody(*it); newLinearVelocity = mConstraintSolver.getConstrainedLinearVelocityOfBody(*it);
newAngularVelocity = constraintSolver.getConstrainedAngularVelocityOfBody(*it); newAngularVelocity = mConstraintSolver.getConstrainedAngularVelocityOfBody(*it);
linearVelocityErrorCorrection = constraintSolver.getErrorConstrainedLinearVelocityOfBody(rigidBody); linearVelocityErrorCorrection = mConstraintSolver.getErrorConstrainedLinearVelocityOfBody(rigidBody);
angularVelocityErrorCorrection = constraintSolver.getErrorConstrainedAngularVelocityOfBody(rigidBody); angularVelocityErrorCorrection = mConstraintSolver.getErrorConstrainedAngularVelocityOfBody(rigidBody);
} }
// Compute V_forces = dt * (M^-1 * F_ext) which is the velocity of the body due to the // Compute V_forces = dt * (M^-1 * F_ext) which is the velocity of the body due to the
@ -157,7 +157,7 @@ void DynamicsWorld::updateAllBodiesMotion() {
// orientation of the body // orientation of the body
void DynamicsWorld::updatePositionAndOrientationOfBody(RigidBody* rigidBody, const Vector3& newLinVelocity, const Vector3& newAngVelocity, void DynamicsWorld::updatePositionAndOrientationOfBody(RigidBody* rigidBody, const Vector3& newLinVelocity, const Vector3& newAngVelocity,
const Vector3& linearVelocityErrorCorrection, const Vector3& angularVelocityErrorCorrection) { const Vector3& linearVelocityErrorCorrection, const Vector3& angularVelocityErrorCorrection) {
decimal dt = timer.getTimeStep(); decimal dt = mTimer.getTimeStep();
assert(rigidBody); assert(rigidBody);
@ -187,7 +187,7 @@ void DynamicsWorld::updatePositionAndOrientationOfBody(RigidBody* rigidBody, con
void DynamicsWorld::setInterpolationFactorToAllBodies() { void DynamicsWorld::setInterpolationFactorToAllBodies() {
// Compute the interpolation factor // Compute the interpolation factor
decimal factor = timer.computeInterpolationFactor(); decimal factor = mTimer.computeInterpolationFactor();
assert(factor >= 0.0 && factor <= 1.0); assert(factor >= 0.0 && factor <= 1.0);
// Set the factor to all bodies // Set the factor to all bodies
@ -210,9 +210,9 @@ void DynamicsWorld::applyGravity() {
assert(rigidBody); assert(rigidBody);
// If the gravity force is on // If the gravity force is on
if(isGravityOn) { if(mIsGravityOn) {
// Apply the current gravity force to the body // Apply the current gravity force to the body
rigidBody->setExternalForce(rigidBody->getMass() * gravity); rigidBody->setExternalForce(rigidBody->getMass() * mGravity);
} }
} }
} }
@ -229,14 +229,14 @@ RigidBody* DynamicsWorld::createRigidBody(const Transform& transform, decimal ma
assert(bodyID < std::numeric_limits<reactphysics3d::bodyindex>::max()); assert(bodyID < std::numeric_limits<reactphysics3d::bodyindex>::max());
// Create the rigid body // Create the rigid body
RigidBody* rigidBody = new (memoryPoolRigidBodies.allocateObject()) RigidBody(transform, mass, inertiaTensorLocal, collisionShape, bodyID); RigidBody* rigidBody = new (mMemoryPoolRigidBodies.allocateObject()) RigidBody(transform, mass, inertiaTensorLocal, collisionShape, bodyID);
// Add the rigid body to the physics world // Add the rigid body to the physics world
bodies.insert(rigidBody); mBodies.insert(rigidBody);
rigidBodies.insert(rigidBody); mRigidBodies.insert(rigidBody);
// Add the rigid body to the collision detection // Add the rigid body to the collision detection
collisionDetection.addBody(rigidBody); mCollisionDetection.addBody(rigidBody);
// Return the pointer to the rigid body // Return the pointer to the rigid body
return rigidBody; return rigidBody;
@ -246,27 +246,27 @@ RigidBody* DynamicsWorld::createRigidBody(const Transform& transform, decimal ma
void DynamicsWorld::destroyRigidBody(RigidBody* rigidBody) { void DynamicsWorld::destroyRigidBody(RigidBody* rigidBody) {
// Remove the body from the collision detection // Remove the body from the collision detection
collisionDetection.removeBody(rigidBody); mCollisionDetection.removeBody(rigidBody);
// Add the body ID to the list of free IDs // Add the body ID to the list of free IDs
freeBodiesIDs.push_back(rigidBody->getID()); mFreeBodiesIDs.push_back(rigidBody->getID());
// Call the constructor of the rigid body // Call the constructor of the rigid body
rigidBody->RigidBody::~RigidBody(); rigidBody->RigidBody::~RigidBody();
// Remove the rigid body from the list of rigid bodies // Remove the rigid body from the list of rigid bodies
bodies.erase(rigidBody); // TOOD : Maybe use a set to make this faster mBodies.erase(rigidBody); // TOOD : Maybe use a set to make this faster
rigidBodies.erase(rigidBody); // TOOD : Maybe use a set to make this faster mRigidBodies.erase(rigidBody); // TOOD : Maybe use a set to make this faster
// Free the object from the memory pool // Free the object from the memory pool
memoryPoolRigidBodies.freeObject(rigidBody); mMemoryPoolRigidBodies.freeObject(rigidBody);
} }
// Remove all collision contacts constraints // Remove all collision contacts constraints
// TODO : This method should be in the collision detection class // TODO : This method should be in the collision detection class
void DynamicsWorld::removeAllContactConstraints() { void DynamicsWorld::removeAllContactConstraints() {
// For all constraints // For all constraints
for (vector<Constraint*>::iterator it = constraints.begin(); it != constraints.end(); ) { for (vector<Constraint*>::iterator it = mConstraints.begin(); it != mConstraints.end(); ) {
// Try a downcasting // Try a downcasting
Contact* contact = dynamic_cast<Contact*>(*it); Contact* contact = dynamic_cast<Contact*>(*it);
@ -274,7 +274,7 @@ void DynamicsWorld::removeAllContactConstraints() {
// If the constraint is a contact // If the constraint is a contact
if (contact) { if (contact) {
// Remove it from the constraints of the physics world // Remove it from the constraints of the physics world
it = constraints.erase(it); it = mConstraints.erase(it);
} }
else { else {
++it; ++it;
@ -284,7 +284,7 @@ void DynamicsWorld::removeAllContactConstraints() {
// Remove all constraints in the physics world // Remove all constraints in the physics world
void DynamicsWorld::removeAllConstraints() { void DynamicsWorld::removeAllConstraints() {
constraints.clear(); mConstraints.clear();
} }
// Notify the world about a new broad-phase overlapping pair // Notify the world about a new broad-phase overlapping pair
@ -294,8 +294,8 @@ void DynamicsWorld::notifyAddedOverlappingPair(const BroadPhasePair* addedPair)
std::pair<bodyindex, bodyindex> indexPair = addedPair->getBodiesIndexPair(); std::pair<bodyindex, bodyindex> indexPair = addedPair->getBodiesIndexPair();
// Add the pair into the set of overlapping pairs (if not there yet) // Add the pair into the set of overlapping pairs (if not there yet)
OverlappingPair* newPair = new (memoryPoolOverlappingPairs.allocateObject()) OverlappingPair(addedPair->body1, addedPair->body2, memoryPoolContacts); OverlappingPair* newPair = new (mMemoryPoolOverlappingPairs.allocateObject()) OverlappingPair(addedPair->body1, addedPair->body2, mMemoryPoolContacts);
std::pair<map<std::pair<bodyindex, bodyindex>, OverlappingPair*>::iterator, bool> check = overlappingPairs.insert(make_pair(indexPair, newPair)); std::pair<map<std::pair<bodyindex, bodyindex>, OverlappingPair*>::iterator, bool> check = mOverlappingPairs.insert(make_pair(indexPair, newPair));
assert(check.second); assert(check.second);
} }
@ -306,9 +306,9 @@ void DynamicsWorld::notifyRemovedOverlappingPair(const BroadPhasePair* removedPa
std::pair<bodyindex, bodyindex> indexPair = removedPair->getBodiesIndexPair(); std::pair<bodyindex, bodyindex> indexPair = removedPair->getBodiesIndexPair();
// Remove the overlapping pair from the memory pool // Remove the overlapping pair from the memory pool
overlappingPairs[indexPair]->OverlappingPair::~OverlappingPair(); mOverlappingPairs[indexPair]->OverlappingPair::~OverlappingPair();
memoryPoolOverlappingPairs.freeObject(overlappingPairs[indexPair]); mMemoryPoolOverlappingPairs.freeObject(mOverlappingPairs[indexPair]);
overlappingPairs.erase(indexPair); mOverlappingPairs.erase(indexPair);
} }
// Notify the world about a new narrow-phase contact // Notify the world about a new narrow-phase contact
@ -321,12 +321,12 @@ void DynamicsWorld::notifyNewContact(const BroadPhasePair* broadPhasePair, const
assert(rigidBody2); assert(rigidBody2);
// Create a new contact // Create a new contact
Contact* contact = new (memoryPoolContacts.allocateObject()) Contact(rigidBody1, rigidBody2, contactInfo); Contact* contact = new (mMemoryPoolContacts.allocateObject()) Contact(rigidBody1, rigidBody2, contactInfo);
assert(contact); assert(contact);
// Get the corresponding overlapping pair // Get the corresponding overlapping pair
pair<bodyindex, bodyindex> indexPair = broadPhasePair->getBodiesIndexPair(); pair<bodyindex, bodyindex> indexPair = broadPhasePair->getBodiesIndexPair();
OverlappingPair* overlappingPair = overlappingPairs[indexPair]; OverlappingPair* overlappingPair = mOverlappingPairs[indexPair];
assert(overlappingPair); assert(overlappingPair);
// Add the contact to the contact cache of the corresponding overlapping pair // Add the contact to the contact cache of the corresponding overlapping pair

View File

@ -47,82 +47,172 @@ namespace reactphysics3d {
class DynamicsWorld : public CollisionWorld { class DynamicsWorld : public CollisionWorld {
protected : protected :
Timer timer; // Timer of the physics engine
ConstraintSolver constraintSolver; // Constraint solver
bool isDeactivationActive; // True if the deactivation (sleeping) of inactive bodies is enabled
std::set<RigidBody*> rigidBodies; // All the rigid bodies of the physics world
std::vector<Constraint*> constraints; // List that contains all the current constraints
Vector3 gravity; // Gravity vector of the world
bool isGravityOn; // True if the gravity force is on
MemoryPool<OverlappingPair> memoryPoolOverlappingPairs; // Memory pool for the overlapping pairs
MemoryPool<RigidBody> memoryPoolRigidBodies; // Memory pool for rigid bodies memory allocation
MemoryPool<Contact> memoryPoolContacts; // Memory pool for the contacts
void updateAllBodiesMotion(); // Compute the motion of all bodies and update their positions and orientations // -------------------- Attributes -------------------- //
void updatePositionAndOrientationOfBody(RigidBody* body, const Vector3& newLinVelocity, const Vector3& newAngVelocity,
const Vector3& linearVelocityErrorCorrection, const Vector3& angularVelocityErrorCorrection); // Update the position and orientation of a body // Timer of the physics engine
void setInterpolationFactorToAllBodies(); // Compute and set the interpolation factor to all bodies Timer mTimer;
void applyGravity(); // Apply the gravity force to all bodies
void resetBodiesMovementVariable(); // Reset the boolean movement variable of each body // Constraint solver
virtual void updateOverlappingPair(const BroadPhasePair* pair); // Update the overlapping pair ConstraintSolver mConstraintSolver;
virtual void notifyAddedOverlappingPair(const BroadPhasePair* addedPair); // Notify the world about a new broad-phase overlapping pair
virtual void notifyRemovedOverlappingPair(const BroadPhasePair* removedPair); // Notify the world about a removed broad-phase overlapping pair // True if the deactivation (sleeping) of inactive bodies is enabled
virtual void notifyNewContact(const BroadPhasePair* pair, bool mIsDeactivationActive;
const ContactInfo* contactInfo); // Notify the world about a new narrow-phase contact
// All the rigid bodies of the physics world
std::set<RigidBody*> mRigidBodies;
// List that contains all the current constraints
std::vector<Constraint*> mConstraints;
// Gravity vector of the world
Vector3 mGravity;
// True if the gravity force is on
bool mIsGravityOn;
// Memory pool for the overlapping pairs
MemoryPool<OverlappingPair> mMemoryPoolOverlappingPairs;
// Memory pool for rigid bodies memory allocation
MemoryPool<RigidBody> mMemoryPoolRigidBodies;
// Memory pool for the contacts
MemoryPool<Contact> mMemoryPoolContacts;
// -------------------- Methods -------------------- //
// Private copy-constructor
DynamicsWorld(const DynamicsWorld& world);
// Private assignment operator
DynamicsWorld& operator=(const DynamicsWorld& world);
// Compute the motion of all bodies and update their positions and orientations
void updateAllBodiesMotion();
// Update the position and orientation of a body
void updatePositionAndOrientationOfBody(RigidBody* body, const Vector3& newLinVelocity,
const Vector3& newAngVelocity,
const Vector3& linearVelocityErrorCorrection,
const Vector3& angularVelocityErrorCorrection);
// Compute and set the interpolation factor to all bodies
void setInterpolationFactorToAllBodies();
// Apply the gravity force to all bodies
void applyGravity();
// Reset the boolean movement variable of each body
void resetBodiesMovementVariable();
// Update the overlapping pair
virtual void updateOverlappingPair(const BroadPhasePair* pair);
// Notify the world about a new broad-phase overlapping pair
virtual void notifyAddedOverlappingPair(const BroadPhasePair* addedPair);
// Notify the world about a removed broad-phase overlapping pair
virtual void notifyRemovedOverlappingPair(const BroadPhasePair* removedPair);
// Notify the world about a new narrow-phase contact
virtual void notifyNewContact(const BroadPhasePair* pair, const ContactInfo* contactInfo);
public : public :
DynamicsWorld(const Vector3& gravity, decimal timeStep); // Constructor
virtual ~DynamicsWorld(); // Destructor
Timer& getTimer() {return timer;} // -------------------- Methods -------------------- //
void start(); // Start the physics simulation
void stop(); // Stop the physics simulation // Constructor
void update(); // Update the physics simulation DynamicsWorld(const Vector3& mGravity, decimal timeStep);
void setNbLCPIterations(uint nbIterations); // Set the number of iterations of the LCP solver
void setIsErrorCorrectionActive(bool isErrorCorrectionActive); // Set the isErrorCorrectionActive value // Destructor
virtual ~DynamicsWorld();
// Start the physics simulation
void start();
// Stop the physics simulation
void stop();
// Update the physics simulation
void update();
// Set the number of iterations of the LCP solver
void setNbLCPIterations(uint nbIterations);
// Set the isErrorCorrectionActive value
void setIsErrorCorrectionActive(bool isErrorCorrectionActive);
// Create a rigid body into the physics world
RigidBody* createRigidBody(const Transform& transform, decimal mass, RigidBody* createRigidBody(const Transform& transform, decimal mass,
const Matrix3x3& inertiaTensorLocal, CollisionShape* collisionShape); // Create a rigid body into the physics world const Matrix3x3& inertiaTensorLocal,
void destroyRigidBody(RigidBody* rigidBody); // Destroy a rigid body CollisionShape* collisionShape);
Vector3 getGravity() const; // Return the gravity vector of the world
bool getIsGravityOn() const; // Return if the gravity is on // Destroy a rigid body
void setIsGratityOn(bool isGravityOn); // Set the isGravityOn attribute void destroyRigidBody(RigidBody* rigidBody);
void addConstraint(Constraint* constraint); // Add a constraint
void removeConstraint(Constraint* constraint); // Remove a constraint // Return the gravity vector of the world
void removeAllContactConstraints(); // Remove all collision contacts constraints Vector3 getGravity() const;
void removeAllConstraints(); // Remove all constraints and delete them (free their memory)
std::vector<Constraint*>::iterator getConstraintsBeginIterator(); // Return a start iterator on the constraint list // Return if the gravity is on
std::vector<Constraint*>::iterator getConstraintsEndIterator(); // Return a end iterator on the constraint list bool getIsGravityOn() const;
std::set<RigidBody*>::iterator getRigidBodiesBeginIterator(); // Return an iterator to the beginning of the rigid bodies of the physics world
std::set<RigidBody*>::iterator getRigidBodiesEndIterator(); // Return an iterator to the end of the rigid bodies of the physics world // Set the isGravityOn attribute
void setIsGratityOn(bool isGravityOn);
// Add a constraint
void addConstraint(Constraint* constraint);
// Remove a constraint
void removeConstraint(Constraint* constraint);
// Remove all collision contacts constraints
void removeAllContactConstraints();
// Remove all constraints and delete them (free their memory)
void removeAllConstraints();
// Return a start iterator on the constraint list
std::vector<Constraint*>::iterator getConstraintsBeginIterator();
// Return a end iterator on the constraint list
std::vector<Constraint*>::iterator getConstraintsEndIterator();
// Return an iterator to the beginning of the rigid bodies of the physics world
std::set<RigidBody*>::iterator getRigidBodiesBeginIterator();
// Return an iterator to the end of the rigid bodies of the physics world
std::set<RigidBody*>::iterator getRigidBodiesEndIterator();
}; };
// --- Inline functions --- // // --- Inline functions --- //
// Start the physics simulation // Start the physics simulation
inline void DynamicsWorld::start() { inline void DynamicsWorld::start() {
timer.start(); mTimer.start();
} }
inline void DynamicsWorld::stop() { inline void DynamicsWorld::stop() {
std::cout << "Stop Simulation" << std::endl; std::cout << "Stop Simulation" << std::endl;
timer.stop(); mTimer.stop();
} }
// Set the number of iterations of the LCP solver // Set the number of iterations of the LCP solver
inline void DynamicsWorld::setNbLCPIterations(uint nbIterations) { inline void DynamicsWorld::setNbLCPIterations(uint nbIterations) {
constraintSolver.setNbLCPIterations(nbIterations); mConstraintSolver.setNbLCPIterations(nbIterations);
} }
// Set the isErrorCorrectionActive value // Set the isErrorCorrectionActive value
inline void DynamicsWorld::setIsErrorCorrectionActive(bool isErrorCorrectionActive) { inline void DynamicsWorld::setIsErrorCorrectionActive(bool isErrorCorrectionActive) {
constraintSolver.setIsErrorCorrectionActive(isErrorCorrectionActive); mConstraintSolver.setIsErrorCorrectionActive(isErrorCorrectionActive);
} }
// Reset the boolean movement variable of each body // Reset the boolean movement variable of each body
inline void DynamicsWorld::resetBodiesMovementVariable() { inline void DynamicsWorld::resetBodiesMovementVariable() {
// For each rigid body // For each rigid body
for (std::set<RigidBody*>::iterator it = getRigidBodiesBeginIterator(); it != getRigidBodiesEndIterator(); it++) { for (std::set<RigidBody*>::iterator it = getRigidBodiesBeginIterator();
it != getRigidBodiesEndIterator(); it++) {
// Set the hasMoved variable to false // Set the hasMoved variable to false
(*it)->setHasMoved(false); (*it)->setHasMoved(false);
@ -136,7 +226,7 @@ inline void DynamicsWorld::updateOverlappingPair(const BroadPhasePair* pair) {
std::pair<bodyindex, bodyindex> indexPair = pair->getBodiesIndexPair(); std::pair<bodyindex, bodyindex> indexPair = pair->getBodiesIndexPair();
// Get the corresponding overlapping pair // Get the corresponding overlapping pair
OverlappingPair* overlappingPair = overlappingPairs[indexPair]; OverlappingPair* overlappingPair = mOverlappingPairs[indexPair];
// Update the contact cache of the overlapping pair // Update the contact cache of the overlapping pair
overlappingPair->update(); overlappingPair->update();
@ -146,7 +236,7 @@ inline void DynamicsWorld::updateOverlappingPair(const BroadPhasePair* pair) {
// Add a constraint into the physics world // Add a constraint into the physics world
inline void DynamicsWorld::addConstraint(Constraint* constraint) { inline void DynamicsWorld::addConstraint(Constraint* constraint) {
assert(constraint != 0); assert(constraint != 0);
constraints.push_back(constraint); mConstraints.push_back(constraint);
} }
// Remove a constraint and free its memory // Remove a constraint and free its memory
@ -154,45 +244,45 @@ inline void DynamicsWorld::removeConstraint(Constraint* constraint) {
std::vector<Constraint*>::iterator it; std::vector<Constraint*>::iterator it;
assert(constraint); assert(constraint);
it = std::find(constraints.begin(), constraints.end(), constraint); it = std::find(mConstraints.begin(), mConstraints.end(), constraint);
assert(*it == constraint); assert(*it == constraint);
delete *it; delete *it;
constraints.erase(it); mConstraints.erase(it);
} }
// Return the gravity vector of the world // Return the gravity vector of the world
inline Vector3 DynamicsWorld::getGravity() const { inline Vector3 DynamicsWorld::getGravity() const {
return gravity; return mGravity;
} }
// Return if the gravity is on // Return if the gravity is on
inline bool DynamicsWorld::getIsGravityOn() const { inline bool DynamicsWorld::getIsGravityOn() const {
return isGravityOn; return mIsGravityOn;
} }
// Set the isGravityOn attribute // Set the isGravityOn attribute
inline void DynamicsWorld::setIsGratityOn(bool isGravityOn) { inline void DynamicsWorld::setIsGratityOn(bool isGravityOn) {
this->isGravityOn = isGravityOn; mIsGravityOn = isGravityOn;
} }
// Return an iterator to the beginning of the bodies of the physics world // Return an iterator to the beginning of the bodies of the physics world
inline std::set<RigidBody*>::iterator DynamicsWorld::getRigidBodiesBeginIterator() { inline std::set<RigidBody*>::iterator DynamicsWorld::getRigidBodiesBeginIterator() {
return rigidBodies.begin(); return mRigidBodies.begin();
} }
// Return an iterator to the end of the bodies of the physics world // Return an iterator to the end of the bodies of the physics world
inline std::set<RigidBody*>::iterator DynamicsWorld::getRigidBodiesEndIterator() { inline std::set<RigidBody*>::iterator DynamicsWorld::getRigidBodiesEndIterator() {
return rigidBodies.end(); return mRigidBodies.end();
} }
// Return a start iterator on the constraint list // Return a start iterator on the constraint list
inline std::vector<Constraint*>::iterator DynamicsWorld::getConstraintsBeginIterator() { inline std::vector<Constraint*>::iterator DynamicsWorld::getConstraintsBeginIterator() {
return constraints.begin(); return mConstraints.begin();
} }
// Return a end iterator on the constraint list // Return a end iterator on the constraint list
inline std::vector<Constraint*>::iterator DynamicsWorld::getConstraintsEndIterator() { inline std::vector<Constraint*>::iterator DynamicsWorld::getConstraintsEndIterator() {
return constraints.end(); return mConstraints.end();
} }
} }

View File

@ -30,8 +30,10 @@ using namespace reactphysics3d;
// Constructor // Constructor
OverlappingPair::OverlappingPair(CollisionBody* body1, CollisionBody* body2, MemoryPool<Contact>& memoryPoolContacts) OverlappingPair::OverlappingPair(CollisionBody* body1, CollisionBody* body2,
: body1(body1), body2(body2), contactsCache(body1, body2, memoryPoolContacts), cachedSeparatingAxis(1.0, 1.0, 1.0) { MemoryPool<Contact>& memoryPoolContacts)
: mBody1(body1), mBody2(body2), mContactsCache(body1, body2, memoryPoolContacts),
mCachedSeparatingAxis(1.0, 1.0, 1.0) {
} }

View File

@ -42,65 +42,106 @@ namespace reactphysics3d {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class OverlappingPair { class OverlappingPair {
private: private:
CollisionBody* const body1; // Pointer to the first body of the contact
CollisionBody* const body2; // Pointer to the second body of the contact // -------------------- Attributes -------------------- //
PersistentContactCache contactsCache; // Persistent contact cache
Vector3 cachedSeparatingAxis; // Cached previous separating axis // Pointer to the first body of the contact
CollisionBody* const mBody1;
// Pointer to the second body of the contact
CollisionBody* const mBody2;
// Persistent contact cache
PersistentContactCache mContactsCache;
// Cached previous separating axis
Vector3 mCachedSeparatingAxis;
// -------------------- Methods -------------------- //
// Private copy-constructor
OverlappingPair(const OverlappingPair& pair);
// Private assignment operator
OverlappingPair& operator=(const OverlappingPair& pair);
public: public:
OverlappingPair(CollisionBody* body1, CollisionBody* body2, MemoryPool<Contact>& memoryPoolContacts); // Constructor
~OverlappingPair(); // Destructor // -------------------- Methods -------------------- //
// Constructor
OverlappingPair(CollisionBody* body1, CollisionBody* body2,
MemoryPool<Contact>& memoryPoolContacts);
// Destructor
~OverlappingPair();
CollisionBody* const getBody1() const; // Return the pointer to first body // Return the pointer to first body
CollisionBody* const getBody2() const; // Return the pointer to second body CollisionBody* const getBody1() const;
void addContact(Contact* contact); // Add a contact to the contact cache
void update(); // Update the contact cache // Return the pointer to second body
Vector3 getCachedSeparatingAxis() const; // Return the cached separating axis CollisionBody* const getBody2() const;
void setCachedSeparatingAxis(const Vector3& axis); // Set the cached separating axis
uint getNbContacts() const; // Return the number of contacts in the cache // Add a contact to the contact cache
Contact* getContact(uint index) const; // Return a contact of the cache void addContact(Contact* contact);
// Update the contact cache
void update();
// Return the cached separating axis
Vector3 getCachedSeparatingAxis() const;
// Set the cached separating axis
void setCachedSeparatingAxis(const Vector3& axis);
// Return the number of contacts in the cache
uint getNbContacts() const;
// Return a contact of the cache
Contact* getContact(uint index) const;
}; };
// Return the pointer to first body // Return the pointer to first body
inline CollisionBody* const OverlappingPair::getBody1() const { inline CollisionBody* const OverlappingPair::getBody1() const {
return body1; return mBody1;
} }
// Return the pointer to second body // Return the pointer to second body
inline CollisionBody* const OverlappingPair::getBody2() const { inline CollisionBody* const OverlappingPair::getBody2() const {
return body2; return mBody2;
} }
// Add a contact to the contact cache // Add a contact to the contact cache
inline void OverlappingPair::addContact(Contact* contact) { inline void OverlappingPair::addContact(Contact* contact) {
contactsCache.addContact(contact); mContactsCache.addContact(contact);
} }
// Update the contact cache // Update the contact cache
inline void OverlappingPair::update() { inline void OverlappingPair::update() {
contactsCache.update(body1->getTransform(), body2->getTransform()); mContactsCache.update(mBody1->getTransform(), mBody2->getTransform());
} }
// Return the cached separating axis // Return the cached separating axis
inline Vector3 OverlappingPair::getCachedSeparatingAxis() const { inline Vector3 OverlappingPair::getCachedSeparatingAxis() const {
return cachedSeparatingAxis; return mCachedSeparatingAxis;
} }
// Set the cached separating axis // Set the cached separating axis
inline void OverlappingPair::setCachedSeparatingAxis(const Vector3& axis) { inline void OverlappingPair::setCachedSeparatingAxis(const Vector3& axis) {
cachedSeparatingAxis = axis; mCachedSeparatingAxis = axis;
} }
// Return the number of contacts in the cache // Return the number of contacts in the cache
inline uint OverlappingPair::getNbContacts() const { inline uint OverlappingPair::getNbContacts() const {
return contactsCache.getNbContacts(); return mContactsCache.getNbContacts();
} }
// Return a contact of the cache // Return a contact of the cache
inline Contact* OverlappingPair::getContact(uint index) const { inline Contact* OverlappingPair::getContact(uint index) const {
return contactsCache.getContact(index); return mContactsCache.getContact(index);
} }
} // End of the ReactPhysics3D namespace } // End of the ReactPhysics3D namespace

View File

@ -30,7 +30,7 @@ using namespace reactphysics3d;
// Constructor // Constructor
PersistentContactCache::PersistentContactCache(Body* const body1, Body* const body2, MemoryPool<Contact>& memoryPoolContacts) PersistentContactCache::PersistentContactCache(Body* const body1, Body* const body2, MemoryPool<Contact>& memoryPoolContacts)
: body1(body1), body2(body2), nbContacts(0), memoryPoolContacts(memoryPoolContacts) { : mBody1(body1), mBody2(body2), mNbContacts(0), mMemoryPoolContacts(memoryPoolContacts) {
} }
@ -42,23 +42,23 @@ PersistentContactCache::~PersistentContactCache() {
// Add a contact in the cache // Add a contact in the cache
void PersistentContactCache::addContact(Contact* contact) { void PersistentContactCache::addContact(Contact* contact) {
int indexNewContact = nbContacts; int indexNewContact = mNbContacts;
// For contact already in the cache // For contact already in the cache
for (uint i=0; i<nbContacts; i++) { for (uint i=0; i<mNbContacts; i++) {
// Check if the new point point does not correspond to a same contact point // Check if the new point point does not correspond to a same contact point
// already in the cache. If it's the case, we do not add the new contact // already in the cache. If it's the case, we do not add the new contact
if (isApproxEqual(contact->getLocalPointOnBody1(), contacts[i]->getLocalPointOnBody1())) { if (isApproxEqual(contact->getLocalPointOnBody1(), mContacts[i]->getLocalPointOnBody1())) {
// Delete the new contact // Delete the new contact
contact->Contact::~Contact(); contact->Contact::~Contact();
memoryPoolContacts.freeObject(contact); mMemoryPoolContacts.freeObject(contact);
return; return;
} }
} }
// If the contact cache is full // If the contact cache is full
if (nbContacts == MAX_CONTACTS_IN_CACHE) { if (mNbContacts == MAX_CONTACTS_IN_CACHE) {
int indexMaxPenetration = getIndexOfDeepestPenetration(contact); int indexMaxPenetration = getIndexOfDeepestPenetration(contact);
int indexToRemove = getIndexToRemove(indexMaxPenetration, contact->getLocalPointOnBody1()); int indexToRemove = getIndexToRemove(indexMaxPenetration, contact->getLocalPointOnBody1());
removeContact(indexToRemove); removeContact(indexToRemove);
@ -66,26 +66,26 @@ void PersistentContactCache::addContact(Contact* contact) {
} }
// Add the new contact in the cache // Add the new contact in the cache
contacts[indexNewContact] = contact; mContacts[indexNewContact] = contact;
nbContacts++; mNbContacts++;
} }
// Remove a contact from the cache // Remove a contact from the cache
void PersistentContactCache::removeContact(int index) { void PersistentContactCache::removeContact(int index) {
assert(index >= 0 && index < nbContacts); assert(index >= 0 && index < mNbContacts);
assert(nbContacts > 0); assert(mNbContacts > 0);
// Call the destructor explicitly and tell the memory pool that // Call the destructor explicitly and tell the memory pool that
// the corresponding memory block is now free // the corresponding memory block is now free
contacts[index]->Contact::~Contact(); mContacts[index]->Contact::~Contact();
memoryPoolContacts.freeObject(contacts[index]); mMemoryPoolContacts.freeObject(mContacts[index]);
// If we don't remove the last index // If we don't remove the last index
if (index < nbContacts - 1) { if (index < mNbContacts - 1) {
contacts[index] = contacts[nbContacts - 1]; mContacts[index] = mContacts[mNbContacts - 1];
} }
nbContacts--; mNbContacts--;
} }
// Update the contact cache // Update the contact cache
@ -95,27 +95,27 @@ void PersistentContactCache::removeContact(int index) {
// the contacts with a too large distance between the contact points in the plane orthogonal to the // the contacts with a too large distance between the contact points in the plane orthogonal to the
// contact normal // contact normal
void PersistentContactCache::update(const Transform& transform1, const Transform& transform2) { void PersistentContactCache::update(const Transform& transform1, const Transform& transform2) {
if (nbContacts == 0) return; if (mNbContacts == 0) return;
// Update the world coordinates and penetration depth of the contacts in the cache // Update the world coordinates and penetration depth of the contacts in the cache
for (int i=0; i<nbContacts; i++) { for (int i=0; i<mNbContacts; i++) {
contacts[i]->setWorldPointOnBody1(transform1 * contacts[i]->getLocalPointOnBody1()); mContacts[i]->setWorldPointOnBody1(transform1 * mContacts[i]->getLocalPointOnBody1());
contacts[i]->setWorldPointOnBody2(transform2 * contacts[i]->getLocalPointOnBody2()); mContacts[i]->setWorldPointOnBody2(transform2 * mContacts[i]->getLocalPointOnBody2());
contacts[i]->setPenetrationDepth((contacts[i]->getWorldPointOnBody1() - contacts[i]->getWorldPointOnBody2()).dot(contacts[i]->getNormal())); mContacts[i]->setPenetrationDepth((mContacts[i]->getWorldPointOnBody1() - mContacts[i]->getWorldPointOnBody2()).dot(mContacts[i]->getNormal()));
} }
// Remove the contacts that don't represent very well the persistent contact // Remove the contacts that don't represent very well the persistent contact
for (int i=nbContacts-1; i>=0; i--) { for (int i=mNbContacts-1; i>=0; i--) {
assert(i>= 0 && i < nbContacts); assert(i>= 0 && i < mNbContacts);
// Remove the contacts with a negative penetration depth (meaning that the bodies are not penetrating anymore) // Remove the contacts with a negative penetration depth (meaning that the bodies are not penetrating anymore)
if (contacts[i]->getPenetrationDepth() <= 0.0) { if (mContacts[i]->getPenetrationDepth() <= 0.0) {
removeContact(i); removeContact(i);
} }
else { else {
// Compute the distance of the two contact points in the place orthogonal to the contact normal // Compute the distance of the two contact points in the place orthogonal to the contact normal
Vector3 projOfPoint1 = contacts[i]->getWorldPointOnBody1() - contacts[i]->getNormal() * contacts[i]->getPenetrationDepth(); Vector3 projOfPoint1 = mContacts[i]->getWorldPointOnBody1() - mContacts[i]->getNormal() * mContacts[i]->getPenetrationDepth();
Vector3 projDifference = contacts[i]->getWorldPointOnBody2() - projOfPoint1; Vector3 projDifference = mContacts[i]->getWorldPointOnBody2() - projOfPoint1;
// If the orthogonal distance is larger than the valid distance threshold, we remove the contact // If the orthogonal distance is larger than the valid distance threshold, we remove the contact
if (projDifference.lengthSquare() > PERSISTENT_CONTACT_DIST_THRESHOLD * PERSISTENT_CONTACT_DIST_THRESHOLD) { if (projDifference.lengthSquare() > PERSISTENT_CONTACT_DIST_THRESHOLD * PERSISTENT_CONTACT_DIST_THRESHOLD) {
@ -129,15 +129,15 @@ void PersistentContactCache::update(const Transform& transform1, const Transform
// corresponding contact will be kept in the cache. The method returns -1 is // corresponding contact will be kept in the cache. The method returns -1 is
// the new contact is the deepest. // the new contact is the deepest.
int PersistentContactCache::getIndexOfDeepestPenetration(Contact* newContact) const { int PersistentContactCache::getIndexOfDeepestPenetration(Contact* newContact) const {
assert(nbContacts == MAX_CONTACTS_IN_CACHE); assert(mNbContacts == MAX_CONTACTS_IN_CACHE);
int indexMaxPenetrationDepth = -1; int indexMaxPenetrationDepth = -1;
decimal maxPenetrationDepth = newContact->getPenetrationDepth(); decimal maxPenetrationDepth = newContact->getPenetrationDepth();
// For each contact in the cache // For each contact in the cache
for (uint i=0; i<nbContacts; i++) { for (uint i=0; i<mNbContacts; i++) {
// If the current contact has a larger penetration depth // If the current contact has a larger penetration depth
if (contacts[i]->getPenetrationDepth() > maxPenetrationDepth) { if (mContacts[i]->getPenetrationDepth() > maxPenetrationDepth) {
maxPenetrationDepth = contacts[i]->getPenetrationDepth(); maxPenetrationDepth = mContacts[i]->getPenetrationDepth();
indexMaxPenetrationDepth = i; indexMaxPenetrationDepth = i;
} }
} }
@ -151,7 +151,7 @@ int PersistentContactCache::getIndexOfDeepestPenetration(Contact* newContact) co
// the different area and we want to keep the contacts with the largest area. The new point is also // the different area and we want to keep the contacts with the largest area. The new point is also
// kept. // kept.
int PersistentContactCache::getIndexToRemove(int indexMaxPenetration, const Vector3& newPoint) const { int PersistentContactCache::getIndexToRemove(int indexMaxPenetration, const Vector3& newPoint) const {
assert(nbContacts == MAX_CONTACTS_IN_CACHE); assert(mNbContacts == MAX_CONTACTS_IN_CACHE);
decimal area0 = 0.0; // Area with contact 1,2,3 and newPoint decimal area0 = 0.0; // Area with contact 1,2,3 and newPoint
decimal area1 = 0.0; // Area with contact 0,2,3 and newPoint decimal area1 = 0.0; // Area with contact 0,2,3 and newPoint
decimal area2 = 0.0; // Area with contact 0,1,3 and newPoint decimal area2 = 0.0; // Area with contact 0,1,3 and newPoint
@ -159,29 +159,29 @@ int PersistentContactCache::getIndexToRemove(int indexMaxPenetration, const Vect
if (indexMaxPenetration != 0) { if (indexMaxPenetration != 0) {
// Compute the area // Compute the area
Vector3 vector1 = newPoint - contacts[1]->getLocalPointOnBody1(); Vector3 vector1 = newPoint - mContacts[1]->getLocalPointOnBody1();
Vector3 vector2 = contacts[3]->getLocalPointOnBody1() - contacts[2]->getLocalPointOnBody1(); Vector3 vector2 = mContacts[3]->getLocalPointOnBody1() - mContacts[2]->getLocalPointOnBody1();
Vector3 crossProduct = vector1.cross(vector2); Vector3 crossProduct = vector1.cross(vector2);
area0 = crossProduct.lengthSquare(); area0 = crossProduct.lengthSquare();
} }
if (indexMaxPenetration != 1) { if (indexMaxPenetration != 1) {
// Compute the area // Compute the area
Vector3 vector1 = newPoint - contacts[0]->getLocalPointOnBody1(); Vector3 vector1 = newPoint - mContacts[0]->getLocalPointOnBody1();
Vector3 vector2 = contacts[3]->getLocalPointOnBody1() - contacts[2]->getLocalPointOnBody1(); Vector3 vector2 = mContacts[3]->getLocalPointOnBody1() - mContacts[2]->getLocalPointOnBody1();
Vector3 crossProduct = vector1.cross(vector2); Vector3 crossProduct = vector1.cross(vector2);
area1 = crossProduct.lengthSquare(); area1 = crossProduct.lengthSquare();
} }
if (indexMaxPenetration != 2) { if (indexMaxPenetration != 2) {
// Compute the area // Compute the area
Vector3 vector1 = newPoint - contacts[0]->getLocalPointOnBody1(); Vector3 vector1 = newPoint - mContacts[0]->getLocalPointOnBody1();
Vector3 vector2 = contacts[3]->getLocalPointOnBody1() - contacts[1]->getLocalPointOnBody1(); Vector3 vector2 = mContacts[3]->getLocalPointOnBody1() - mContacts[1]->getLocalPointOnBody1();
Vector3 crossProduct = vector1.cross(vector2); Vector3 crossProduct = vector1.cross(vector2);
area2 = crossProduct.lengthSquare(); area2 = crossProduct.lengthSquare();
} }
if (indexMaxPenetration != 3) { if (indexMaxPenetration != 3) {
// Compute the area // Compute the area
Vector3 vector1 = newPoint - contacts[0]->getLocalPointOnBody1(); Vector3 vector1 = newPoint - mContacts[0]->getLocalPointOnBody1();
Vector3 vector2 = contacts[2]->getLocalPointOnBody1() - contacts[1]->getLocalPointOnBody1(); Vector3 vector2 = mContacts[2]->getLocalPointOnBody1() - mContacts[1]->getLocalPointOnBody1();
Vector3 crossProduct = vector1.cross(vector2); Vector3 crossProduct = vector1.cross(vector2);
area3 = crossProduct.lengthSquare(); area3 = crossProduct.lengthSquare();
} }
@ -216,12 +216,12 @@ int PersistentContactCache::getMaxArea(decimal area0, decimal area1, decimal are
// Clear the cache // Clear the cache
void PersistentContactCache::clear() { void PersistentContactCache::clear() {
for (uint i=0; i<nbContacts; i++) { for (uint i=0; i<mNbContacts; i++) {
// Call the destructor explicitly and tell the memory pool that // Call the destructor explicitly and tell the memory pool that
// the corresponding memory block is now free // the corresponding memory block is now free
contacts[i]->Contact::~Contact(); mContacts[i]->Contact::~Contact();
memoryPoolContacts.freeObject(contacts[i]); mMemoryPoolContacts.freeObject(mContacts[i]);
} }
nbContacts = 0; mNbContacts = 0;
} }

View File

@ -35,7 +35,7 @@
namespace reactphysics3d { namespace reactphysics3d {
// Constants // Constants
const uint MAX_CONTACTS_IN_CACHE = 4; // Maximum number of contacts in the persistent cache const uint MAX_CONTACTS_IN_CACHE = 4; // Maximum number of contacts in the persistent cache
/* ------------------------------------------------------------------- /* -------------------------------------------------------------------
@ -52,42 +52,90 @@ const uint MAX_CONTACTS_IN_CACHE = 4; // Maximum number of contacts in
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class PersistentContactCache { class PersistentContactCache {
private:
Body* const body1; // Pointer to the first body
Body* const body2; // Pointer to the second body
Contact* contacts[MAX_CONTACTS_IN_CACHE]; // Contacts in the cache
uint nbContacts; // Number of contacts in the cache
MemoryPool<Contact>& memoryPoolContacts; // Reference to the memory pool with the contacts
int getMaxArea(decimal area0, decimal area1, decimal area2, decimal area3) const; // Return the index of maximum area private:
int getIndexOfDeepestPenetration(Contact* newContact) const; // Return the index of the contact with the larger penetration depth
int getIndexToRemove(int indexMaxPenetration, const Vector3& newPoint) const; // Return the index that will be removed // -------------------- Attributes -------------------- //
void removeContact(int index); // Remove a contact from the cache
bool isApproxEqual(const Vector3& vector1, const Vector3& vector2) const; // Return true if two vectors are approximatively equal // Pointer to the first body
Body* const mBody1;
// Pointer to the second body
Body* const mBody2;
// Contacts in the cache
Contact* mContacts[MAX_CONTACTS_IN_CACHE];
// Number of contacts in the cache
uint mNbContacts;
// Reference to the memory pool with the contacts
MemoryPool<Contact>& mMemoryPoolContacts;
// -------------------- Methods -------------------- //
// Private copy-constructor
PersistentContactCache(const PersistentContactCache& persistentContactCache);
// Private assignment operator
PersistentContactCache& operator=(const PersistentContactCache& persistentContactCache);
// Return the index of maximum area
int getMaxArea(decimal area0, decimal area1, decimal area2, decimal area3) const;
// Return the index of the contact with the larger penetration depth
int getIndexOfDeepestPenetration(Contact* newContact) const;
// Return the index that will be removed
int getIndexToRemove(int indexMaxPenetration, const Vector3& newPoint) const;
// Remove a contact from the cache
void removeContact(int index);
// Return true if two vectors are approximatively equal
bool isApproxEqual(const Vector3& vector1, const Vector3& vector2) const;
public: public:
PersistentContactCache(Body* const body1, Body* const body2, MemoryPool<Contact>& memoryPoolContacts); // Constructor
~PersistentContactCache(); // Destructor // -------------------- Methods -------------------- //
void addContact(Contact* contact); // Add a contact
void update(const Transform& transform1, const Transform& transform2); // Update the contact cache // Constructor
void clear(); // Clear the cache PersistentContactCache(Body* const mBody1, Body* const mBody2,
uint getNbContacts() const; // Return the number of contacts in the cache MemoryPool<Contact>& mMemoryPoolContacts);
Contact* getContact(uint index) const; // Return a contact of the cache
// Destructor
~PersistentContactCache();
// Add a contact
void addContact(Contact* contact);
// Update the contact cache
void update(const Transform& transform1, const Transform& transform2);
// Clear the cache
void clear();
// Return the number of contacts in the cache
uint getNbContacts() const;
// Return a contact of the cache
Contact* getContact(uint index) const;
}; };
// Return the number of contacts in the cache // Return the number of contacts in the cache
inline uint PersistentContactCache::getNbContacts() const { inline uint PersistentContactCache::getNbContacts() const {
return nbContacts; return mNbContacts;
} }
// Return a contact of the cache // Return a contact of the cache
inline Contact* PersistentContactCache::getContact(uint index) const { inline Contact* PersistentContactCache::getContact(uint index) const {
assert(index >= 0 && index < nbContacts); assert(index >= 0 && index < mNbContacts);
return contacts[index]; return mContacts[index];
} }
// Return true if two vectors are approximatively equal // Return true if two vectors are approximatively equal
inline bool PersistentContactCache::isApproxEqual(const Vector3& vector1, const Vector3& vector2) const { inline bool PersistentContactCache::isApproxEqual(const Vector3& vector1,
const Vector3& vector2) const {
const decimal epsilon = 0.1; const decimal epsilon = 0.1;
return (approxEqual(vector1.getX(), vector2.getX(), epsilon) && return (approxEqual(vector1.getX(), vector2.getX(), epsilon) &&
approxEqual(vector1.getY(), vector2.getY(), epsilon) && approxEqual(vector1.getY(), vector2.getY(), epsilon) &&

View File

@ -30,7 +30,7 @@
using namespace reactphysics3d; using namespace reactphysics3d;
// Constructor // Constructor
Timer::Timer(double timeStep) : timeStep(timeStep), isRunning(false) { Timer::Timer(double timeStep) : mTimeStep(timeStep), mIsRunning(false) {
assert(timeStep > 0.0); assert(timeStep > 0.0);
} }

View File

@ -51,60 +51,102 @@ namespace reactphysics3d {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class Timer { class Timer {
private : private :
double timeStep; // Timestep dt of the physics engine (timestep > 0.0)
long double time; // Current time of the physics engine // -------------------- Attributes -------------------- //
long double lastUpdateTime; // Last time the timer has been updated
long double deltaTime; // Time difference between the two last timer update() calls // Timestep dt of the physics engine (timestep > 0.0)
double accumulator; // Used to fix the time step and avoid strange time effects double mTimeStep;
bool isRunning; // True if the timer is running
// Current time of the physics engine
long double mTime;
// Last time the timer has been updated
long double mLastUpdateTime;
// Time difference between the two last timer update() calls
long double mDeltaTime;
// Used to fix the time step and avoid strange time effects
double mAccumulator;
// True if the timer is running
bool mIsRunning;
// -------------------- Methods -------------------- //
// Private copy-constructor
Timer(const Timer& timer);
// Private assignment operator
Timer& operator=(const Timer& timer);
public : public :
Timer(double timeStep); // Constructor
virtual ~Timer(); // Destructor
double getTimeStep() const; // Return the timestep of the physics engine // -------------------- Methods -------------------- //
void setTimeStep(double timeStep) throw(std::invalid_argument); // Set the timestep of the physics engine
long double getTime() const; // Return the current time // Constructor
void start(); // Start the timer Timer(double timeStep);
void stop(); // Stop the timer
bool getIsRunning() const; // Return true if the timer is running // Destructor
bool isPossibleToTakeStep() const; // True if it's possible to take a new step virtual ~Timer();
void update(); // Compute the time since the last update() call and add it to the accumulator
void nextStep(); // Take a new step => update the timer by adding the timeStep value to the current time // Return the timestep of the physics engine
double computeInterpolationFactor(); // Compute the interpolation factor double getTimeStep() const;
// Set the timestep of the physics engine
void setTimeStep(double timeStep);
// Return the current time
long double getTime() const;
// Start the timer
void start();
// Stop the timer
void stop();
// Return true if the timer is running
bool getIsRunning() const;
// True if it's possible to take a new step
bool isPossibleToTakeStep() const;
// Compute the time since the last update() call and add it to the accumulator
void update();
// Take a new step => update the timer by adding the timeStep value to the current time
void nextStep();
// Compute the interpolation factor
double computeInterpolationFactor();
}; };
// Return the timestep of the physics engine // Return the timestep of the physics engine
inline double Timer::getTimeStep() const { inline double Timer::getTimeStep() const {
return timeStep; return mTimeStep;
} }
// Set the timestep of the physics engine // Set the timestep of the physics engine
inline void Timer::setTimeStep(double timeStep) throw(std::invalid_argument) { inline void Timer::setTimeStep(double timeStep) {
// Check if the timestep is different from zero assert(timeStep > 0.0f);
if (timeStep != 0.0) { mTimeStep = timeStep;
this->timeStep = timeStep;
}
else {
// We throw an exception
throw std::invalid_argument("Exception in Timer : the timestep has to be different from zero");
}
} }
// Return the current time // Return the current time
inline long double Timer::getTime() const { inline long double Timer::getTime() const {
return time; return mTime;
} }
// Return if the timer is running // Return if the timer is running
inline bool Timer::getIsRunning() const { inline bool Timer::getIsRunning() const {
return isRunning; return mIsRunning;
} }
// Start the timer // Start the timer
inline void Timer::start() { inline void Timer::start() {
if (!isRunning) { if (!mIsRunning) {
#if defined(WINDOWS_OS) #if defined(WINDOWS_OS)
LARGE_INTEGER ticksPerSecond; LARGE_INTEGER ticksPerSecond;
@ -116,39 +158,39 @@ inline void Timer::start() {
// Initialize the lastUpdateTime with the current time in seconds // Initialize the lastUpdateTime with the current time in seconds
timeval timeValue; timeval timeValue;
gettimeofday(&timeValue, NULL); gettimeofday(&timeValue, NULL);
lastUpdateTime = timeValue.tv_sec + (timeValue.tv_usec / 1000000.0); mLastUpdateTime = timeValue.tv_sec + (timeValue.tv_usec / 1000000.0);
#endif #endif
accumulator = 0.0; mAccumulator = 0.0;
isRunning = true; mIsRunning = true;
} }
} }
// Stop the timer // Stop the timer
inline void Timer::stop() { inline void Timer::stop() {
std::cout << "Timer stop" << std::endl; std::cout << "Timer stop" << std::endl;
isRunning = false; mIsRunning = false;
} }
// True if it's possible to take a new step // True if it's possible to take a new step
inline bool Timer::isPossibleToTakeStep() const { inline bool Timer::isPossibleToTakeStep() const {
return (accumulator >= timeStep); return (mAccumulator >= mTimeStep);
} }
// Take a new step => update the timer by adding the timeStep value to the current time // Take a new step => update the timer by adding the timeStep value to the current time
inline void Timer::nextStep() { inline void Timer::nextStep() {
assert(isRunning); assert(mIsRunning);
// Update the current time of the physics engine // Update the current time of the physics engine
time += timeStep; mTime += mTimeStep;
// Update the accumulator value // Update the accumulator value
accumulator -= timeStep; mAccumulator -= mTimeStep;
} }
// Compute the interpolation factor // Compute the interpolation factor
inline double Timer::computeInterpolationFactor() { inline double Timer::computeInterpolationFactor() {
return (accumulator / timeStep); return (mAccumulator / mTimeStep);
} }
// Compute the time since the last update() call and add it to the accumulator // Compute the time since the last update() call and add it to the accumulator
@ -169,13 +211,13 @@ inline void Timer::update() {
#endif #endif
// Compute the delta display time between two display frames // Compute the delta display time between two display frames
deltaTime = currentTime - lastUpdateTime; mDeltaTime = currentTime - mLastUpdateTime;
// Update the current display time // Update the current display time
lastUpdateTime = currentTime; mLastUpdateTime = currentTime;
// Update the accumulator value // Update the accumulator value
accumulator += deltaTime; mAccumulator += mDeltaTime;
} }
} // End of the ReactPhysics3D namespace } // End of the ReactPhysics3D namespace

View File

@ -52,6 +52,25 @@ Matrix3x3::~Matrix3x3() {
} }
// Copy-constructor
Matrix3x3::Matrix3x3(const Matrix3x3& matrix) {
setAllValues(matrix.mArray[0][0], matrix.mArray[0][1], matrix.mArray[0][2],
matrix.mArray[1][0], matrix.mArray[1][1], matrix.mArray[1][2],
matrix.mArray[2][0], matrix.mArray[2][1], matrix.mArray[2][2]);
}
// Assignment operator
Matrix3x3& Matrix3x3::operator=(const Matrix3x3& matrix) {
// Check for self-assignment
if (&matrix != this) {
setAllValues(matrix.mArray[0][0], matrix.mArray[0][1], matrix.mArray[0][2],
matrix.mArray[1][0], matrix.mArray[1][1], matrix.mArray[1][2],
matrix.mArray[2][0], matrix.mArray[2][1], matrix.mArray[2][2]);
}
return *this;
}
// Return the inverse matrix // Return the inverse matrix
Matrix3x3 Matrix3x3::getInverse() const { Matrix3x3 Matrix3x3::getInverse() const {
// Compute the determinant of the matrix // Compute the determinant of the matrix
@ -63,9 +82,9 @@ Matrix3x3 Matrix3x3::getInverse() const {
Matrix3x3 tempMatrix; Matrix3x3 tempMatrix;
// Compute the inverse of the matrix // Compute the inverse of the matrix
tempMatrix.setAllValues((array[1][1]*array[2][2]-array[2][1]*array[1][2]), -(array[1][0]*array[2][2]-array[2][0]*array[1][2]), (array[1][0]*array[2][1]-array[2][0]*array[1][1]), tempMatrix.setAllValues((mArray[1][1]*mArray[2][2]-mArray[2][1]*mArray[1][2]), -(mArray[1][0]*mArray[2][2]-mArray[2][0]*mArray[1][2]), (mArray[1][0]*mArray[2][1]-mArray[2][0]*mArray[1][1]),
-(array[0][1]*array[2][2]-array[2][1]*array[0][2]), (array[0][0]*array[2][2]-array[2][0]*array[0][2]), -(array[0][0]*array[2][1]-array[2][0]*array[0][1]), -(mArray[0][1]*mArray[2][2]-mArray[2][1]*mArray[0][2]), (mArray[0][0]*mArray[2][2]-mArray[2][0]*mArray[0][2]), -(mArray[0][0]*mArray[2][1]-mArray[2][0]*mArray[0][1]),
(array[0][1]*array[1][2]-array[0][2]*array[1][1]), -(array[0][0]*array[1][2]-array[1][0]*array[0][2]), (array[0][0]*array[1][1]-array[0][1]*array[1][0])); (mArray[0][1]*mArray[1][2]-mArray[0][2]*mArray[1][1]), -(mArray[0][0]*mArray[1][2]-mArray[1][0]*mArray[0][2]), (mArray[0][0]*mArray[1][1]-mArray[0][1]*mArray[1][0]));
// Return the inverse matrix // Return the inverse matrix
return (invDeterminant * tempMatrix.getTranspose()); return (invDeterminant * tempMatrix.getTranspose());

View File

@ -41,98 +41,163 @@ namespace reactphysics3d {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class Matrix3x3 { class Matrix3x3 {
private : private :
decimal array[3][3]; // Array with the values of the matrix
// -------------------- Attributes -------------------- //
// Array with the values of the matrix
decimal mArray[3][3];
public : public :
Matrix3x3(); // Constructor
Matrix3x3(decimal value); // Constructor // -------------------- Methods -------------------- //
// Constructor
Matrix3x3();
// Constructor
Matrix3x3(decimal value);
// Constructor
Matrix3x3(decimal a1, decimal a2, decimal a3, decimal b1, decimal b2, decimal b3, Matrix3x3(decimal a1, decimal a2, decimal a3, decimal b1, decimal b2, decimal b3,
decimal c1, decimal c2, decimal c3); // Constructor decimal c1, decimal c2, decimal c3);
virtual ~Matrix3x3(); // Destructor
decimal getValue(int i, int j) const; // Get a value in the matrix // Destructor
void setValue(int i, int j, decimal value); // Set a value in the matrix virtual ~Matrix3x3();
// Copy-constructor
Matrix3x3(const Matrix3x3& matrix);
// Assignment operator
Matrix3x3& operator=(const Matrix3x3& matrix);
// Get a value in the matrix
decimal getValue(int i, int j) const;
// Set a value in the matrix
void setValue(int i, int j, decimal value);
// Set all the values in the matrix
void setAllValues(decimal a1, decimal a2, decimal a3, decimal b1, decimal b2, decimal b3, void setAllValues(decimal a1, decimal a2, decimal a3, decimal b1, decimal b2, decimal b3,
decimal c1, decimal c2, decimal c3); // Set all the values in the matrix decimal c1, decimal c2, decimal c3);
Vector3 getColumn(int i) const; // Return a column
Matrix3x3 getTranspose() const; // Return the transpose matrix
decimal getDeterminant() const; // Return the determinant of the matrix
decimal getTrace() const; // Return the trace of the matrix
Matrix3x3 getInverse() const; // Return the inverse matrix
Matrix3x3 getAbsoluteMatrix() const; // Return the matrix with absolute values
void setToIdentity(); // Set the matrix to the identity matrix
static Matrix3x3 identity(); // Return the 3x3 identity matrix
// --- Overloaded operators --- // // Return a column
friend Matrix3x3 operator+(const Matrix3x3& matrix1, const Matrix3x3& matrix2); // Overloaded operator for addition Vector3 getColumn(int i) const;
friend Matrix3x3 operator-(const Matrix3x3& matrix1, const Matrix3x3& matrix2); // Overloaded operator for substraction
friend Matrix3x3 operator-(const Matrix3x3& matrix); // Overloaded operator for the negative of the matrix
friend Matrix3x3 operator*(decimal nb, const Matrix3x3& matrix); // Overloaded operator for multiplication with a number
friend Matrix3x3 operator*(const Matrix3x3& matrix, decimal nb); // Overloaded operator for multiplication with a matrix
friend Matrix3x3 operator*(const Matrix3x3& matrix1, const Matrix3x3& matrix2); // Overloaded operator for matrix multiplication
friend Vector3 operator*(const Matrix3x3& matrix, const Vector3& vector); // Overloaded operator for multiplication with a vector
bool operator==(const Matrix3x3& matrix) const; // Overloaded operator for equality condition // Return the transpose matrix
bool operator!= (const Matrix3x3& matrix) const; // Overloaded operator for the is different condition Matrix3x3 getTranspose() const;
Matrix3x3& operator+=(const Matrix3x3& matrix); // Overloaded operator for addition with assignment
Matrix3x3& operator-=(const Matrix3x3& matrix); // Overloaded operator for substraction with assignment // Return the determinant of the matrix
Matrix3x3& operator*=(decimal nb); // Overloaded operator for multiplication with a number with assignment decimal getDeterminant() const;
// Return the trace of the matrix
decimal getTrace() const;
// Return the inverse matrix
Matrix3x3 getInverse() const;
// Return the matrix with absolute values
Matrix3x3 getAbsoluteMatrix() const;
// Set the matrix to the identity matrix
void setToIdentity();
// Return the 3x3 identity matrix
static Matrix3x3 identity();
// Overloaded operator for addition
friend Matrix3x3 operator+(const Matrix3x3& matrix1, const Matrix3x3& matrix2);
// Overloaded operator for substraction
friend Matrix3x3 operator-(const Matrix3x3& matrix1, const Matrix3x3& matrix2);
// Overloaded operator for the negative of the matrix
friend Matrix3x3 operator-(const Matrix3x3& matrix);
// Overloaded operator for multiplication with a number
friend Matrix3x3 operator*(decimal nb, const Matrix3x3& matrix);
// Overloaded operator for multiplication with a matrix
friend Matrix3x3 operator*(const Matrix3x3& matrix, decimal nb);
// Overloaded operator for matrix multiplication
friend Matrix3x3 operator*(const Matrix3x3& matrix1, const Matrix3x3& matrix2);
// Overloaded operator for multiplication with a vector
friend Vector3 operator*(const Matrix3x3& matrix, const Vector3& vector);
// Overloaded operator for equality condition
bool operator==(const Matrix3x3& matrix) const;
// Overloaded operator for the is different condition
bool operator!= (const Matrix3x3& matrix) const;
// Overloaded operator for addition with assignment
Matrix3x3& operator+=(const Matrix3x3& matrix);
// Overloaded operator for substraction with assignment
Matrix3x3& operator-=(const Matrix3x3& matrix);
// Overloaded operator for multiplication with a number with assignment
Matrix3x3& operator*=(decimal nb);
}; };
// Method to get a value in the matrix (inline) // Method to get a value in the matrix (inline)
inline decimal Matrix3x3::getValue(int i, int j) const { inline decimal Matrix3x3::getValue(int i, int j) const {
assert(i>=0 && i<3 && j>=0 && j<3); assert(i>=0 && i<3 && j>=0 && j<3);
return array[i][j]; return mArray[i][j];
} }
// Method to set a value in the matrix (inline) // Method to set a value in the matrix (inline)
inline void Matrix3x3::setValue(int i, int j, decimal value) { inline void Matrix3x3::setValue(int i, int j, decimal value) {
assert(i>=0 && i<3 && j>=0 && j<3); assert(i>=0 && i<3 && j>=0 && j<3);
array[i][j] = value; mArray[i][j] = value;
} }
// Method to set all the values in the matrix // Method to set all the values in the matrix
inline void Matrix3x3::setAllValues(decimal a1, decimal a2, decimal a3, decimal b1, decimal b2, decimal b3, inline void Matrix3x3::setAllValues(decimal a1, decimal a2, decimal a3,
decimal b1, decimal b2, decimal b3,
decimal c1, decimal c2, decimal c3) { decimal c1, decimal c2, decimal c3) {
array[0][0] = a1; array[0][1] = a2; array[0][2] = a3; mArray[0][0] = a1; mArray[0][1] = a2; mArray[0][2] = a3;
array[1][0] = b1; array[1][1] = b2; array[1][2] = b3; mArray[1][0] = b1; mArray[1][1] = b2; mArray[1][2] = b3;
array[2][0] = c1; array[2][1] = c2; array[2][2] = c3; mArray[2][0] = c1; mArray[2][1] = c2; mArray[2][2] = c3;
} }
// Return a column // Return a column
inline Vector3 Matrix3x3::getColumn(int i) const { inline Vector3 Matrix3x3::getColumn(int i) const {
assert(i>= 0 && i<3); assert(i>= 0 && i<3);
return Vector3(array[0][i], array[1][i], array[2][i]); return Vector3(mArray[0][i], mArray[1][i], mArray[2][i]);
} }
// Return the transpose matrix // Return the transpose matrix
inline Matrix3x3 Matrix3x3::getTranspose() const { inline Matrix3x3 Matrix3x3::getTranspose() const {
// Return the transpose matrix // Return the transpose matrix
return Matrix3x3(array[0][0], array[1][0], array[2][0], return Matrix3x3(mArray[0][0], mArray[1][0], mArray[2][0],
array[0][1], array[1][1], array[2][1], mArray[0][1], mArray[1][1], mArray[2][1],
array[0][2], array[1][2], array[2][2]); mArray[0][2], mArray[1][2], mArray[2][2]);
} }
// Return the determinant of the matrix // Return the determinant of the matrix
inline decimal Matrix3x3::getDeterminant() const { inline decimal Matrix3x3::getDeterminant() const {
// Compute and return the determinant of the matrix // Compute and return the determinant of the matrix
return (array[0][0]*(array[1][1]*array[2][2]-array[2][1]*array[1][2]) - array[0][1]*(array[1][0]*array[2][2]-array[2][0]*array[1][2]) + return (mArray[0][0]*(mArray[1][1]*mArray[2][2]-mArray[2][1]*mArray[1][2]) -
array[0][2]*(array[1][0]*array[2][1]-array[2][0]*array[1][1])); mArray[0][1]*(mArray[1][0]*mArray[2][2]-mArray[2][0]*mArray[1][2]) +
mArray[0][2]*(mArray[1][0]*mArray[2][1]-mArray[2][0]*mArray[1][1]));
} }
// Return the trace of the matrix // Return the trace of the matrix
inline decimal Matrix3x3::getTrace() const { inline decimal Matrix3x3::getTrace() const {
// Compute and return the trace // Compute and return the trace
return (array[0][0] + array[1][1] + array[2][2]); return (mArray[0][0] + mArray[1][1] + mArray[2][2]);
} }
// Set the matrix to the identity matrix // Set the matrix to the identity matrix
inline void Matrix3x3::setToIdentity() { inline void Matrix3x3::setToIdentity() {
array[0][0] = 1.0; array[0][1] = 0.0; array[0][2] = 0.0; mArray[0][0] = 1.0; mArray[0][1] = 0.0; mArray[0][2] = 0.0;
array[1][0] = 0.0; array[1][1] = 1.0; array[1][2] = 0.0; mArray[1][0] = 0.0; mArray[1][1] = 1.0; mArray[1][2] = 0.0;
array[2][0] = 0.0; array[2][1] = 0.0; array[2][2] = 1.0; mArray[2][0] = 0.0; mArray[2][1] = 0.0; mArray[2][2] = 1.0;
} }
// Return the 3x3 identity matrix // Return the 3x3 identity matrix
@ -143,37 +208,43 @@ inline Matrix3x3 Matrix3x3::identity() {
// Return the matrix with absolute values // Return the matrix with absolute values
inline Matrix3x3 Matrix3x3::getAbsoluteMatrix() const { inline Matrix3x3 Matrix3x3::getAbsoluteMatrix() const {
return Matrix3x3(fabs(array[0][0]), fabs(array[0][1]), fabs(array[0][2]), return Matrix3x3(fabs(mArray[0][0]), fabs(mArray[0][1]), fabs(mArray[0][2]),
fabs(array[1][0]), fabs(array[1][1]), fabs(array[1][2]), fabs(mArray[1][0]), fabs(mArray[1][1]), fabs(mArray[1][2]),
fabs(array[2][0]), fabs(array[2][1]), fabs(array[2][2])); fabs(mArray[2][0]), fabs(mArray[2][1]), fabs(mArray[2][2]));
} }
// Overloaded operator for addition // Overloaded operator for addition
inline Matrix3x3 operator+(const Matrix3x3& matrix1, const Matrix3x3& matrix2) { inline Matrix3x3 operator+(const Matrix3x3& matrix1, const Matrix3x3& matrix2) {
return Matrix3x3(matrix1.array[0][0] + matrix2.array[0][0], matrix1.array[0][1] + matrix2.array[0][1], matrix1.array[0][2] + matrix2.array[0][2], return Matrix3x3(matrix1.mArray[0][0] + matrix2.mArray[0][0], matrix1.mArray[0][1] +
matrix1.array[1][0] + matrix2.array[1][0], matrix1.array[1][1] + matrix2.array[1][1], matrix1.array[1][2] + matrix2.array[1][2], matrix2.mArray[0][1], matrix1.mArray[0][2] + matrix2.mArray[0][2],
matrix1.array[2][0] + matrix2.array[2][0], matrix1.array[2][1] + matrix2.array[2][1], matrix1.array[2][2] + matrix2.array[2][2]); matrix1.mArray[1][0] + matrix2.mArray[1][0], matrix1.mArray[1][1] +
matrix2.mArray[1][1], matrix1.mArray[1][2] + matrix2.mArray[1][2],
matrix1.mArray[2][0] + matrix2.mArray[2][0], matrix1.mArray[2][1] +
matrix2.mArray[2][1], matrix1.mArray[2][2] + matrix2.mArray[2][2]);
} }
// Overloaded operator for substraction // Overloaded operator for substraction
inline Matrix3x3 operator-(const Matrix3x3& matrix1, const Matrix3x3& matrix2) { inline Matrix3x3 operator-(const Matrix3x3& matrix1, const Matrix3x3& matrix2) {
return Matrix3x3(matrix1.array[0][0] - matrix2.array[0][0], matrix1.array[0][1] - matrix2.array[0][1], matrix1.array[0][2] - matrix2.array[0][2], return Matrix3x3(matrix1.mArray[0][0] - matrix2.mArray[0][0], matrix1.mArray[0][1] -
matrix1.array[1][0] - matrix2.array[1][0], matrix1.array[1][1] - matrix2.array[1][1], matrix1.array[1][2] - matrix2.array[1][2], matrix2.mArray[0][1], matrix1.mArray[0][2] - matrix2.mArray[0][2],
matrix1.array[2][0] - matrix2.array[2][0], matrix1.array[2][1] - matrix2.array[2][1], matrix1.array[2][2] - matrix2.array[2][2]); matrix1.mArray[1][0] - matrix2.mArray[1][0], matrix1.mArray[1][1] -
matrix2.mArray[1][1], matrix1.mArray[1][2] - matrix2.mArray[1][2],
matrix1.mArray[2][0] - matrix2.mArray[2][0], matrix1.mArray[2][1] -
matrix2.mArray[2][1], matrix1.mArray[2][2] - matrix2.mArray[2][2]);
} }
// Overloaded operator for the negative of the matrix // Overloaded operator for the negative of the matrix
inline Matrix3x3 operator-(const Matrix3x3& matrix) { inline Matrix3x3 operator-(const Matrix3x3& matrix) {
return Matrix3x3(-matrix.array[0][0], -matrix.array[0][1], -matrix.array[0][2], return Matrix3x3(-matrix.mArray[0][0], -matrix.mArray[0][1], -matrix.mArray[0][2],
-matrix.array[1][0], -matrix.array[1][1], -matrix.array[1][2], -matrix.mArray[1][0], -matrix.mArray[1][1], -matrix.mArray[1][2],
-matrix.array[2][0], -matrix.array[2][1], -matrix.array[2][2]); -matrix.mArray[2][0], -matrix.mArray[2][1], -matrix.mArray[2][2]);
} }
// Overloaded operator for multiplication with a number // Overloaded operator for multiplication with a number
inline Matrix3x3 operator*(decimal nb, const Matrix3x3& matrix) { inline Matrix3x3 operator*(decimal nb, const Matrix3x3& matrix) {
return Matrix3x3(matrix.array[0][0] * nb, matrix.array[0][1] * nb, matrix.array[0][2] * nb, return Matrix3x3(matrix.mArray[0][0] * nb, matrix.mArray[0][1] * nb, matrix.mArray[0][2] * nb,
matrix.array[1][0] * nb, matrix.array[1][1] * nb, matrix.array[1][2] * nb, matrix.mArray[1][0] * nb, matrix.mArray[1][1] * nb, matrix.mArray[1][2] * nb,
matrix.array[2][0] * nb, matrix.array[2][1] * nb, matrix.array[2][2] * nb); matrix.mArray[2][0] * nb, matrix.mArray[2][1] * nb, matrix.mArray[2][2] * nb);
} }
// Overloaded operator for multiplication with a matrix // Overloaded operator for multiplication with a matrix
@ -183,29 +254,44 @@ inline Matrix3x3 operator*(const Matrix3x3& matrix, decimal nb) {
// Overloaded operator for matrix multiplication // Overloaded operator for matrix multiplication
inline Matrix3x3 operator*(const Matrix3x3& matrix1, const Matrix3x3& matrix2) { inline Matrix3x3 operator*(const Matrix3x3& matrix1, const Matrix3x3& matrix2) {
return Matrix3x3(matrix1.array[0][0]*matrix2.array[0][0] + matrix1.array[0][1]*matrix2.array[1][0] + matrix1.array[0][2]*matrix2.array[2][0], return Matrix3x3(matrix1.mArray[0][0]*matrix2.mArray[0][0] + matrix1.mArray[0][1] *
matrix1.array[0][0]*matrix2.array[0][1] + matrix1.array[0][1]*matrix2.array[1][1] + matrix1.array[0][2]*matrix2.array[2][1], matrix2.mArray[1][0] + matrix1.mArray[0][2]*matrix2.mArray[2][0],
matrix1.array[0][0]*matrix2.array[0][2] + matrix1.array[0][1]*matrix2.array[1][2] + matrix1.array[0][2]*matrix2.array[2][2], matrix1.mArray[0][0]*matrix2.mArray[0][1] + matrix1.mArray[0][1] *
matrix1.array[1][0]*matrix2.array[0][0] + matrix1.array[1][1]*matrix2.array[1][0] + matrix1.array[1][2]*matrix2.array[2][0], matrix2.mArray[1][1] + matrix1.mArray[0][2]*matrix2.mArray[2][1],
matrix1.array[1][0]*matrix2.array[0][1] + matrix1.array[1][1]*matrix2.array[1][1] + matrix1.array[1][2]*matrix2.array[2][1], matrix1.mArray[0][0]*matrix2.mArray[0][2] + matrix1.mArray[0][1] *
matrix1.array[1][0]*matrix2.array[0][2] + matrix1.array[1][1]*matrix2.array[1][2] + matrix1.array[1][2]*matrix2.array[2][2], matrix2.mArray[1][2] + matrix1.mArray[0][2]*matrix2.mArray[2][2],
matrix1.array[2][0]*matrix2.array[0][0] + matrix1.array[2][1]*matrix2.array[1][0] + matrix1.array[2][2]*matrix2.array[2][0], matrix1.mArray[1][0]*matrix2.mArray[0][0] + matrix1.mArray[1][1] *
matrix1.array[2][0]*matrix2.array[0][1] + matrix1.array[2][1]*matrix2.array[1][1] + matrix1.array[2][2]*matrix2.array[2][1], matrix2.mArray[1][0] + matrix1.mArray[1][2]*matrix2.mArray[2][0],
matrix1.array[2][0]*matrix2.array[0][2] + matrix1.array[2][1]*matrix2.array[1][2] + matrix1.array[2][2]*matrix2.array[2][2]); matrix1.mArray[1][0]*matrix2.mArray[0][1] + matrix1.mArray[1][1] *
matrix2.mArray[1][1] + matrix1.mArray[1][2]*matrix2.mArray[2][1],
matrix1.mArray[1][0]*matrix2.mArray[0][2] + matrix1.mArray[1][1] *
matrix2.mArray[1][2] + matrix1.mArray[1][2]*matrix2.mArray[2][2],
matrix1.mArray[2][0]*matrix2.mArray[0][0] + matrix1.mArray[2][1] *
matrix2.mArray[1][0] + matrix1.mArray[2][2]*matrix2.mArray[2][0],
matrix1.mArray[2][0]*matrix2.mArray[0][1] + matrix1.mArray[2][1] *
matrix2.mArray[1][1] + matrix1.mArray[2][2]*matrix2.mArray[2][1],
matrix1.mArray[2][0]*matrix2.mArray[0][2] + matrix1.mArray[2][1] *
matrix2.mArray[1][2] + matrix1.mArray[2][2]*matrix2.mArray[2][2]);
} }
// Overloaded operator for multiplication with a vector // Overloaded operator for multiplication with a vector
inline Vector3 operator*(const Matrix3x3& matrix, const Vector3& vector) { inline Vector3 operator*(const Matrix3x3& matrix, const Vector3& vector) {
return Vector3(matrix.array[0][0]*vector.getX() + matrix.array[0][1]*vector.getY() + matrix.array[0][2]*vector.getZ(), return Vector3(matrix.mArray[0][0]*vector.getX() + matrix.mArray[0][1]*vector.getY() +
matrix.array[1][0]*vector.getX() + matrix.array[1][1]*vector.getY() + matrix.array[1][2]*vector.getZ(), matrix.mArray[0][2]*vector.getZ(),
matrix.array[2][0]*vector.getX() + matrix.array[2][1]*vector.getY() + matrix.array[2][2]*vector.getZ()); matrix.mArray[1][0]*vector.getX() + matrix.mArray[1][1]*vector.getY() +
matrix.mArray[1][2]*vector.getZ(),
matrix.mArray[2][0]*vector.getX() + matrix.mArray[2][1]*vector.getY() +
matrix.mArray[2][2]*vector.getZ());
} }
// Overloaded operator for equality condition // Overloaded operator for equality condition
inline bool Matrix3x3::operator==(const Matrix3x3& matrix) const { inline bool Matrix3x3::operator==(const Matrix3x3& matrix) const {
return (array[0][0] == matrix.array[0][0] && array[0][1] == matrix.array[0][1] && array[0][2] == matrix.array[0][2] && return (mArray[0][0] == matrix.mArray[0][0] && mArray[0][1] == matrix.mArray[0][1] &&
array[1][0] == matrix.array[1][0] && array[1][1] == matrix.array[1][1] && array[1][2] == matrix.array[1][2] && mArray[0][2] == matrix.mArray[0][2] &&
array[2][0] == matrix.array[2][0] && array[2][1] == matrix.array[2][1] && array[2][2] == matrix.array[2][2]); mArray[1][0] == matrix.mArray[1][0] && mArray[1][1] == matrix.mArray[1][1] &&
mArray[1][2] == matrix.mArray[1][2] &&
mArray[2][0] == matrix.mArray[2][0] && mArray[2][1] == matrix.mArray[2][1] &&
mArray[2][2] == matrix.mArray[2][2]);
} }
// Overloaded operator for the is different condition // Overloaded operator for the is different condition
@ -215,25 +301,29 @@ inline bool Matrix3x3::operator!= (const Matrix3x3& matrix) const {
// Overloaded operator for addition with assignment // Overloaded operator for addition with assignment
inline Matrix3x3& Matrix3x3::operator+=(const Matrix3x3& matrix) { inline Matrix3x3& Matrix3x3::operator+=(const Matrix3x3& matrix) {
array[0][0] += matrix.array[0][0]; array[0][1] += matrix.array[0][1]; array[0][2] += matrix.array[0][2]; mArray[0][0] += matrix.mArray[0][0]; mArray[0][1] += matrix.mArray[0][1];
array[1][0] += matrix.array[1][0]; array[1][1] += matrix.array[1][1]; array[1][2] += matrix.array[1][2]; mArray[0][2] += matrix.mArray[0][2]; mArray[1][0] += matrix.mArray[1][0];
array[2][0] += matrix.array[2][0]; array[2][1] += matrix.array[2][1]; array[2][2] += matrix.array[2][2]; mArray[1][1] += matrix.mArray[1][1]; mArray[1][2] += matrix.mArray[1][2];
mArray[2][0] += matrix.mArray[2][0]; mArray[2][1] += matrix.mArray[2][1];
mArray[2][2] += matrix.mArray[2][2];
return *this; return *this;
} }
// Overloaded operator for substraction with assignment // Overloaded operator for substraction with assignment
inline Matrix3x3& Matrix3x3::operator-=(const Matrix3x3& matrix) { inline Matrix3x3& Matrix3x3::operator-=(const Matrix3x3& matrix) {
array[0][0] -= matrix.array[0][0]; array[0][1] -= matrix.array[0][1]; array[0][2] -= matrix.array[0][2]; mArray[0][0] -= matrix.mArray[0][0]; mArray[0][1] -= matrix.mArray[0][1];
array[1][0] -= matrix.array[1][0]; array[1][1] -= matrix.array[1][1]; array[1][2] -= matrix.array[1][2]; mArray[0][2] -= matrix.mArray[0][2]; mArray[1][0] -= matrix.mArray[1][0];
array[2][0] -= matrix.array[2][0]; array[2][1] -= matrix.array[2][1]; array[2][2] -= matrix.array[2][2]; mArray[1][1] -= matrix.mArray[1][1]; mArray[1][2] -= matrix.mArray[1][2];
mArray[2][0] -= matrix.mArray[2][0]; mArray[2][1] -= matrix.mArray[2][1];
mArray[2][2] -= matrix.mArray[2][2];
return *this; return *this;
} }
// Overloaded operator for multiplication with a number with assignment // Overloaded operator for multiplication with a number with assignment
inline Matrix3x3& Matrix3x3::operator*=(decimal nb) { inline Matrix3x3& Matrix3x3::operator*=(decimal nb) {
array[0][0] *= nb; array[0][1] *= nb; array[0][2] *= nb; mArray[0][0] *= nb; mArray[0][1] *= nb; mArray[0][2] *= nb;
array[1][0] *= nb; array[1][1] *= nb; array[1][2] *= nb; mArray[1][0] *= nb; mArray[1][1] *= nb; mArray[1][2] *= nb;
array[2][0] *= nb; array[2][1] *= nb; array[2][2] *= nb; mArray[2][0] *= nb; mArray[2][1] *= nb; mArray[2][2] *= nb;
return *this; return *this;
} }

View File

@ -33,25 +33,25 @@ using namespace reactphysics3d;
// Constructor of the class // Constructor of the class
Quaternion::Quaternion() Quaternion::Quaternion()
:x(0.0), y(0.0), z(0.0), w(0.0) { :mX(0.0), mY(0.0), mZ(0.0), mW(0.0) {
} }
// Constructor with arguments // Constructor with arguments
Quaternion::Quaternion(decimal x, decimal y, decimal z, decimal w) Quaternion::Quaternion(decimal x, decimal y, decimal z, decimal w)
:x(x), y(y), z(z), w(w) { :mX(x), mY(y), mZ(z), mW(w) {
} }
// Constructor with the component w and the vector v=(x y z) // Constructor with the component w and the vector v=(x y z)
Quaternion::Quaternion(decimal w, const Vector3& v) Quaternion::Quaternion(decimal w, const Vector3& v)
:x(v.getX()), y(v.getY()), z(v.getZ()), w(w) { :mX(v.getX()), mY(v.getY()), mZ(v.getZ()), mW(w) {
} }
// Copy-constructor // Copy-constructor
Quaternion::Quaternion(const Quaternion& quaternion) Quaternion::Quaternion(const Quaternion& quaternion)
:x(quaternion.x), y(quaternion.y), z(quaternion.z), w(quaternion.w) { :mX(quaternion.mX), mY(quaternion.mY), mZ(quaternion.mZ), mW(quaternion.mW) {
} }
@ -78,20 +78,20 @@ Quaternion::Quaternion(const Matrix3x3& matrix) {
s = 0.5 / r; s = 0.5 / r;
// Compute the quaternion // Compute the quaternion
x = (array[2][0] + array[0][2])*s; mX = (array[2][0] + array[0][2])*s;
y = (array[1][2] + array[2][1])*s; mY = (array[1][2] + array[2][1])*s;
z = 0.5*r; mZ = 0.5*r;
w = (array[1][0] - array[0][1])*s; mW = (array[1][0] - array[0][1])*s;
} }
else { else {
r = sqrt(array[1][1] - array[2][2] - array[0][0] + 1.0); r = sqrt(array[1][1] - array[2][2] - array[0][0] + 1.0);
s = 0.5 / r; s = 0.5 / r;
// Compute the quaternion // Compute the quaternion
x = (array[0][1] + array[1][0])*s; mX = (array[0][1] + array[1][0])*s;
y = 0.5 * r; mY = 0.5 * r;
z = (array[1][2] + array[2][1])*s; mZ = (array[1][2] + array[2][1])*s;
w = (array[0][2] - array[2][0])*s; mW = (array[0][2] - array[2][0])*s;
} }
} }
else if (array[2][2] > array[0][0]) { else if (array[2][2] > array[0][0]) {
@ -99,20 +99,20 @@ Quaternion::Quaternion(const Matrix3x3& matrix) {
s = 0.5 / r; s = 0.5 / r;
// Compute the quaternion // Compute the quaternion
x = (array[2][0] + array[0][2])*s; mX = (array[2][0] + array[0][2])*s;
y = (array[1][2] + array[2][1])*s; mY = (array[1][2] + array[2][1])*s;
z = 0.5 * r; mZ = 0.5 * r;
w = (array[1][0] - array[0][1])*s; mW = (array[1][0] - array[0][1])*s;
} }
else { else {
r = sqrt(array[0][0] - array[1][1] - array[2][2] + 1.0); r = sqrt(array[0][0] - array[1][1] - array[2][2] + 1.0);
s = 0.5 / r; s = 0.5 / r;
// Compute the quaternion // Compute the quaternion
x = 0.5 * r; mX = 0.5 * r;
y = (array[0][1] + array[1][0])*s; mY = (array[0][1] + array[1][0])*s;
z = (array[2][0] - array[0][2])*s; mZ = (array[2][0] - array[0][2])*s;
w = (array[2][1] - array[1][2])*s; mW = (array[2][1] - array[1][2])*s;
} }
} }
else { else {
@ -120,10 +120,10 @@ Quaternion::Quaternion(const Matrix3x3& matrix) {
s = 0.5/r; s = 0.5/r;
// Compute the quaternion // Compute the quaternion
x = (array[2][1]-array[1][2])*s; mX = (array[2][1]-array[1][2])*s;
y = (array[0][2]-array[2][0])*s; mY = (array[0][2]-array[2][0])*s;
z = (array[1][0]-array[0][1])*s; mZ = (array[1][0]-array[0][1])*s;
w = 0.5 * r; mW = 0.5 * r;
} }
} }
@ -148,10 +148,10 @@ void Quaternion::getRotationAngleAxis(decimal& angle, Vector3& axis) const {
} }
// Compute the roation angle // Compute the roation angle
angle = acos(quaternion.w) * 2.0; angle = acos(quaternion.mW) * 2.0;
// Compute the 3D rotation axis // Compute the 3D rotation axis
Vector3 rotationAxis(quaternion.x, quaternion.y, quaternion.z); Vector3 rotationAxis(quaternion.mX, quaternion.mY, quaternion.mZ);
// Normalize the rotation axis // Normalize the rotation axis
rotationAxis = rotationAxis.getUnit(); rotationAxis = rotationAxis.getUnit();
@ -163,7 +163,7 @@ void Quaternion::getRotationAngleAxis(decimal& angle, Vector3& axis) const {
// Return the orientation matrix corresponding to this quaternion // Return the orientation matrix corresponding to this quaternion
Matrix3x3 Quaternion::getMatrix() const { Matrix3x3 Quaternion::getMatrix() const {
decimal nQ = x*x + y*y + z*z + w*w; decimal nQ = mX*mX + mY*mY + mZ*mZ + mW*mW;
decimal s = 0.0; decimal s = 0.0;
if (nQ > 0.0) { if (nQ > 0.0) {
@ -171,18 +171,18 @@ Matrix3x3 Quaternion::getMatrix() const {
} }
// Computations used for optimization (less multiplications) // Computations used for optimization (less multiplications)
decimal xs = x*s; decimal xs = mX*s;
decimal ys = y*s; decimal ys = mY*s;
decimal zs = z*s; decimal zs = mZ*s;
decimal wxs = w*xs; decimal wxs = mW*xs;
decimal wys = w*ys; decimal wys = mW*ys;
decimal wzs = w*zs; decimal wzs = mW*zs;
decimal xxs = x*xs; decimal xxs = mX*xs;
decimal xys = x*ys; decimal xys = mX*ys;
decimal xzs = x*zs; decimal xzs = mX*zs;
decimal yys = y*ys; decimal yys = mY*ys;
decimal yzs = y*zs; decimal yzs = mY*zs;
decimal zzs = z*zs; decimal zzs = mZ*zs;
// Create the matrix corresponding to the quaternion // Create the matrix corresponding to the quaternion
return Matrix3x3(1.0-yys-zzs, xys-wzs, xzs + wys, return Matrix3x3(1.0-yys-zzs, xys-wzs, xzs + wys,
@ -192,7 +192,8 @@ Matrix3x3 Quaternion::getMatrix() const {
// Compute the spherical linear interpolation between two quaternions. // Compute the spherical linear interpolation between two quaternions.
// The t argument has to be such that 0 <= t <= 1. This method is static. // The t argument has to be such that 0 <= t <= 1. This method is static.
Quaternion Quaternion::slerp(const Quaternion& quaternion1, const Quaternion& quaternion2, decimal t) { Quaternion Quaternion::slerp(const Quaternion& quaternion1,
const Quaternion& quaternion2, decimal t) {
assert(t >= 0.0 && t <= 1.0); assert(t >= 0.0 && t <= 1.0);
decimal invert = 1.0; decimal invert = 1.0;
@ -206,7 +207,8 @@ Quaternion Quaternion::slerp(const Quaternion& quaternion1, const Quaternion& qu
invert = -1.0; invert = -1.0;
} }
// Because of precision, if cos(theta) is nearly 1, therefore theta is nearly 0 and we can write // Because of precision, if cos(theta) is nearly 1,
// therefore theta is nearly 0 and we can write
// sin((1-t)*theta) as (1-t) and sin(t*theta) as t // sin((1-t)*theta) as (1-t) and sin(t*theta) as t
const decimal epsilon = 0.00001; const decimal epsilon = 0.00001;
if(1-cosineTheta < epsilon) { if(1-cosineTheta < epsilon) {

View File

@ -42,99 +42,159 @@ namespace reactphysics3d {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class Quaternion { class Quaternion {
private : private :
decimal x; // Component x of the quaternion
decimal y; // Component y of the quaternion // -------------------- Attributes -------------------- //
decimal z; // Component z of the quaternion
decimal w; // Component w of the quaternion // Components of the quaternion
decimal mX, mY, mZ, mW;
public : public :
Quaternion(); // Constructor
Quaternion(decimal x, decimal y, decimal z, decimal w); // Constructor with arguments
Quaternion(decimal w, const Vector3& v); // Constructor with the component w and the vector v=(x y z)
Quaternion(const Quaternion& quaternion); // Copy-constructor
Quaternion(const Matrix3x3& matrix); // Create a unit quaternion from a rotation matrix
~Quaternion(); // Destructor
decimal getX() const; // Return the component x of the quaternion
decimal getY() const; // Return the component y of the quaternion
decimal getZ() const; // Return the component z of the quaternion
decimal getW() const; // Return the component w of the quaternion
void setX(decimal x); // Set the value x
void setY(decimal y); // Set the value y
void setZ(decimal z); // Set the value z
void setW(decimal w); // Set the value w
Vector3 vectorV() const; // Return the vector v=(x y z) of the quaternion
decimal length() const; // Return the length of the quaternion
Quaternion getUnit() const; // Return the unit quaternion
Quaternion getConjugate() const; // Return the conjugate quaternion
Quaternion getInverse() const; // Return the inverse of the quaternion
Matrix3x3 getMatrix() const; // Return the orientation matrix corresponding to this quaternion
static Quaternion identity(); // Return the identity quaternion
decimal dot(const Quaternion& quaternion) const; // Dot product between two quaternions
void getRotationAngleAxis(decimal& angle, Vector3& axis) const; // Compute the rotation angle (in radians) and the axis
static Quaternion slerp(const Quaternion& quaternion1,
const Quaternion& quaternion2, decimal t); // Compute the spherical linear interpolation between two quaternions
// --- Overloaded operators --- // // -------------------- Methods -------------------- //
Quaternion operator+(const Quaternion& quaternion) const; // Overloaded operator for the addition
Quaternion operator-(const Quaternion& quaternion) const; // Overloaded operator for the substraction // Constructor
Quaternion operator*(decimal nb) const; // Overloaded operator for the multiplication with a constant Quaternion();
Quaternion operator*(const Quaternion& quaternion) const; // Overloaded operator for the multiplication
Quaternion& operator=(const Quaternion& quaternion); // Overloaded operator for assignment // Constructor with arguments
bool operator==(const Quaternion& quaternion) const; // Overloaded operator for equality condition Quaternion(decimal x, decimal y, decimal z, decimal w);
// Constructor with the component w and the vector v=(x y z)
Quaternion(decimal w, const Vector3& v);
// Copy-constructor
Quaternion(const Quaternion& quaternion);
// Create a unit quaternion from a rotation matrix
Quaternion(const Matrix3x3& matrix);
// Destructor
~Quaternion();
// Return the component x of the quaternion
decimal getX() const;
// Return the component y of the quaternion
decimal getY() const;
// Return the component z of the quaternion
decimal getZ() const;
// Return the component w of the quaternion
decimal getW() const;
// Set the value x
void setX(decimal x);
// Set the value y
void setY(decimal y);
// Set the value z
void setZ(decimal z);
// Set the value w
void setW(decimal w);
// Return the vector v=(x y z) of the quaternion
Vector3 vectorV() const;
// Return the length of the quaternion
decimal length() const;
// Return the unit quaternion
Quaternion getUnit() const;
// Return the conjugate quaternion
Quaternion getConjugate() const;
// Return the inverse of the quaternion
Quaternion getInverse() const;
// Return the orientation matrix corresponding to this quaternion
Matrix3x3 getMatrix() const;
// Return the identity quaternion
static Quaternion identity();
// Dot product between two quaternions
decimal dot(const Quaternion& quaternion) const;
// Compute the rotation angle (in radians) and the axis
void getRotationAngleAxis(decimal& angle, Vector3& axis) const;
// Compute the spherical linear interpolation between two quaternions
static Quaternion slerp(const Quaternion& quaternion1, const Quaternion& quaternion2,
decimal t);
// Overloaded operator for the addition
Quaternion operator+(const Quaternion& quaternion) const;
// Overloaded operator for the substraction
Quaternion operator-(const Quaternion& quaternion) const;
// Overloaded operator for the multiplication with a constant
Quaternion operator*(decimal nb) const;
// Overloaded operator for the multiplication
Quaternion operator*(const Quaternion& quaternion) const;
// Overloaded operator for assignment
Quaternion& operator=(const Quaternion& quaternion);
// Overloaded operator for equality condition
bool operator==(const Quaternion& quaternion) const;
}; };
// --- Inline functions --- //
// Get the value x (inline) // Get the value x (inline)
inline decimal Quaternion::getX() const { inline decimal Quaternion::getX() const {
return x; return mX;
} }
// Get the value y (inline) // Get the value y (inline)
inline decimal Quaternion::getY() const { inline decimal Quaternion::getY() const {
return y; return mY;
} }
// Get the value z (inline) // Get the value z (inline)
inline decimal Quaternion::getZ() const { inline decimal Quaternion::getZ() const {
return z; return mZ;
} }
// Get the value w (inline) // Get the value w (inline)
inline decimal Quaternion::getW() const { inline decimal Quaternion::getW() const {
return w; return mW;
} }
// Set the value x (inline) // Set the value x (inline)
inline void Quaternion::setX(decimal x) { inline void Quaternion::setX(decimal x) {
this->x = x; mX = x;
} }
// Set the value y (inline) // Set the value y (inline)
inline void Quaternion::setY(decimal y) { inline void Quaternion::setY(decimal y) {
this->y = y; mY = y;
} }
// Set the value z (inline) // Set the value z (inline)
inline void Quaternion::setZ(decimal z) { inline void Quaternion::setZ(decimal z) {
this->z = z; mZ = z;
} }
// Set the value w (inline) // Set the value w (inline)
inline void Quaternion::setW(decimal w) { inline void Quaternion::setW(decimal w) {
this->w = w; mW = w;
} }
// Return the vector v=(x y z) of the quaternion // Return the vector v=(x y z) of the quaternion
inline Vector3 Quaternion::vectorV() const { inline Vector3 Quaternion::vectorV() const {
// Return the vector v // Return the vector v
return Vector3(x, y, z); return Vector3(mX, mY, mZ);
} }
// Return the length of the quaternion (inline) // Return the length of the quaternion (inline)
inline decimal Quaternion::length() const { inline decimal Quaternion::length() const {
return sqrt(x*x + y*y + z*z + w*w); return sqrt(mX*mX + mY*mY + mZ*mZ + mW*mW);
} }
// Return the unit quaternion // Return the unit quaternion
@ -145,7 +205,8 @@ inline Quaternion Quaternion::getUnit() const {
assert (lengthQuaternion != 0.0); assert (lengthQuaternion != 0.0);
// Compute and return the unit quaternion // Compute and return the unit quaternion
return Quaternion(x/lengthQuaternion, y/lengthQuaternion, z/lengthQuaternion, w/lengthQuaternion); return Quaternion(mX/lengthQuaternion, mY/lengthQuaternion,
mZ/lengthQuaternion, mW/lengthQuaternion);
} }
// Return the identity quaternion // Return the identity quaternion
@ -155,7 +216,7 @@ inline Quaternion Quaternion::identity() {
// Return the conjugate of the quaternion (inline) // Return the conjugate of the quaternion (inline)
inline Quaternion Quaternion::getConjugate() const { inline Quaternion Quaternion::getConjugate() const {
return Quaternion(-x, -y, -z, w); return Quaternion(-mX, -mY, -mZ, mW);
} }
// Return the inverse of the quaternion (inline) // Return the inverse of the quaternion (inline)
@ -166,46 +227,51 @@ inline Quaternion Quaternion::getInverse() const {
assert (lengthQuaternion != 0.0); assert (lengthQuaternion != 0.0);
// Compute and return the inverse quaternion // Compute and return the inverse quaternion
return Quaternion(-x/lengthQuaternion, -y/lengthQuaternion, -z/lengthQuaternion, w/lengthQuaternion); return Quaternion(-mX/lengthQuaternion, -mY/lengthQuaternion,
-mZ/lengthQuaternion, mW/lengthQuaternion);
} }
// Scalar product between two quaternions // Scalar product between two quaternions
inline decimal Quaternion::dot(const Quaternion& quaternion) const { inline decimal Quaternion::dot(const Quaternion& quaternion) const {
return (x*quaternion.x + y*quaternion.y + z*quaternion.z + w*quaternion.w); return (mX*quaternion.mX + mY*quaternion.mY + mZ*quaternion.mZ + mW*quaternion.mW);
} }
// Overloaded operator for the addition of two quaternions // Overloaded operator for the addition of two quaternions
inline Quaternion Quaternion::operator+(const Quaternion& quaternion) const { inline Quaternion Quaternion::operator+(const Quaternion& quaternion) const {
// Return the result quaternion // Return the result quaternion
return Quaternion(x + quaternion.x, y + quaternion.y, z + quaternion.z, w + quaternion.w); return Quaternion(mX + quaternion.mX, mY + quaternion.mY,
mZ + quaternion.mZ, mW + quaternion.mW);
} }
// Overloaded operator for the substraction of two quaternions // Overloaded operator for the substraction of two quaternions
inline Quaternion Quaternion::operator-(const Quaternion& quaternion) const { inline Quaternion Quaternion::operator-(const Quaternion& quaternion) const {
// Return the result of the substraction // Return the result of the substraction
return Quaternion(x-quaternion.x, y - quaternion.y, z - quaternion.z, w - quaternion.w); return Quaternion(mX-quaternion.mX, mY - quaternion.mY,
mZ - quaternion.mZ, mW - quaternion.mW);
} }
// Overloaded operator for the multiplication with a constant // Overloaded operator for the multiplication with a constant
inline Quaternion Quaternion::operator*(decimal nb) const { inline Quaternion Quaternion::operator*(decimal nb) const {
// Return the result // Return the result
return Quaternion(nb*x, nb*y, nb*z, nb*w); return Quaternion(nb*mX, nb*mY, nb*mZ, nb*mW);
} }
// Overloaded operator for the multiplication of two quaternions // Overloaded operator for the multiplication of two quaternions
inline Quaternion Quaternion::operator*(const Quaternion& quaternion) const { inline Quaternion Quaternion::operator*(const Quaternion& quaternion) const {
// Return the result of the multiplication // Return the result of the multiplication
return Quaternion(w*quaternion.w - vectorV().dot(quaternion.vectorV()), w*quaternion.vectorV()+quaternion.w*vectorV() + vectorV().cross(quaternion.vectorV())); return Quaternion(mW*quaternion.mW - vectorV().dot(quaternion.vectorV()),
mW*quaternion.vectorV()+quaternion.mW*vectorV() +
vectorV().cross(quaternion.vectorV()));
} }
// Overloaded operator for the assignment // Overloaded operator for the assignment
inline Quaternion& Quaternion::operator=(const Quaternion& quaternion) { inline Quaternion& Quaternion::operator=(const Quaternion& quaternion) {
// Check for self-assignment // Check for self-assignment
if (this != &quaternion) { if (this != &quaternion) {
x = quaternion.x; mX = quaternion.mX;
y = quaternion.y; mY = quaternion.mY;
z = quaternion.z; mZ = quaternion.mZ;
w = quaternion.w; mW = quaternion.mW;
} }
// Return this quaternion // Return this quaternion
@ -214,7 +280,8 @@ inline Quaternion& Quaternion::operator=(const Quaternion& quaternion) {
// Overloaded operator for equality condition // Overloaded operator for equality condition
inline bool Quaternion::operator==(const Quaternion& quaternion) const { inline bool Quaternion::operator==(const Quaternion& quaternion) const {
return (x == quaternion.x && y == quaternion.y && z == quaternion.z && w == quaternion.w); return (mX == quaternion.mX && mY == quaternion.mY &&
mZ == quaternion.mZ && mW == quaternion.mW);
} }
} // End of the ReactPhysics3D namespace } // End of the ReactPhysics3D namespace

View File

@ -31,23 +31,29 @@ using namespace reactphysics3d;
// Constructor // Constructor
Transform::Transform() { Transform::Transform() {
position = Vector3(0.0, 0.0, 0.0); mPosition = Vector3(0.0, 0.0, 0.0);
orientation = Quaternion::identity(); mOrientation = Quaternion::identity();
} }
// Constructor // Constructor
Transform::Transform(const Vector3& position, const Matrix3x3& orientation) { Transform::Transform(const Vector3& position, const Matrix3x3& orientation) {
this->position = position; mPosition = position;
this->orientation = Quaternion(orientation); mOrientation = Quaternion(orientation);
} }
// Constructor // Constructor
Transform::Transform(const Vector3& position, const Quaternion& orientation) { Transform::Transform(const Vector3& position, const Quaternion& orientation) {
this->position = position; mPosition = position;
this->orientation = orientation; mOrientation = orientation;
}
// Copy-constructor
Transform::Transform(const Transform& transform) {
mPosition = transform.mPosition;
mOrientation = transform.mOrientation;
} }
// Destructor // Destructor
Transform::~Transform() { Transform::~Transform() {
} }

View File

@ -41,58 +41,105 @@ namespace reactphysics3d {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class Transform { class Transform {
private : private :
Vector3 position; // Position
Quaternion orientation; // Orientation // -------------------- Attributes -------------------- //
// Position
Vector3 mPosition;
// Orientation
Quaternion mOrientation;
public : public :
Transform(); // Constructor
Transform(const Vector3& position, const Matrix3x3& orientation); // Constructor
Transform(const Vector3& position, const Quaternion& orientation); // Constructor
~Transform(); // Destructor
const Vector3& getPosition() const; // Return the origin of the transform // -------------------- Methods -------------------- //
void setPosition(const Vector3& position); // Set the origin of the transform
const Quaternion& getOrientation() const; // Return the orientation quaternion // Constructor
void setOrientation(const Quaternion& orientation); // Set the rotation quaternion Transform();
void setToIdentity(); // Set the transform to the identity transform
void setFromOpenGL(decimal* openglMatrix); // Set the transform from an OpenGL transform matrix // Constructor
void getOpenGLMatrix(decimal* openglMatrix) const; // Get the OpenGL matrix of the transform Transform(const Vector3& position, const Matrix3x3& orientation);
Transform inverse() const; // Return the inverse of the transform
// Constructor
Transform(const Vector3& position, const Quaternion& orientation);
// Destructor
~Transform();
// Copy-constructor
Transform(const Transform& transform);
// Return the origin of the transform
const Vector3& getPosition() const;
// Set the origin of the transform
void setPosition(const Vector3& position);
// Return the orientation quaternion
const Quaternion& getOrientation() const;
// Set the rotation quaternion
void setOrientation(const Quaternion& orientation);
// Set the transform to the identity transform
void setToIdentity();
// Set the transform from an OpenGL transform matrix
void setFromOpenGL(decimal* openglMatrix);
// Get the OpenGL matrix of the transform
void getOpenGLMatrix(decimal* openglMatrix) const;
// Return the inverse of the transform
Transform inverse() const;
// Return an interpolated transform
static Transform interpolateTransforms(const Transform& oldTransform, static Transform interpolateTransforms(const Transform& oldTransform,
const Transform& newTransform, const Transform& newTransform,
decimal interpolationFactor); // Return an interpolated transform decimal interpolationFactor);
Vector3 operator*(const Vector3& vector) const; // Return the transformed vector // Return the transformed vector
Transform operator*(const Transform& transform2) const; // Operator of multiplication of a transform with another one Vector3 operator*(const Vector3& vector) const;
bool operator==(const Transform& transform2) const; // Return true if the two transforms are equal
bool operator!=(const Transform& transform2) const; // Return true if the two transforms are different // Operator of multiplication of a transform with another one
Transform operator*(const Transform& transform2) const;
// Return true if the two transforms are equal
bool operator==(const Transform& transform2) const;
// Return true if the two transforms are different
bool operator!=(const Transform& transform2) const;
// Assignment operator
Transform& operator=(const Transform& transform);
}; };
// Return the position of the transform // Return the position of the transform
inline const Vector3& Transform::getPosition() const { inline const Vector3& Transform::getPosition() const {
return position; return mPosition;
} }
// Set the origin of the transform // Set the origin of the transform
inline void Transform::setPosition(const Vector3& position) { inline void Transform::setPosition(const Vector3& position) {
this->position = position; mPosition = position;
} }
// Return the rotation matrix // Return the rotation matrix
inline const Quaternion& Transform::getOrientation() const { inline const Quaternion& Transform::getOrientation() const {
return orientation; return mOrientation;
} }
// Set the rotation matrix of the transform // Set the rotation matrix of the transform
inline void Transform::setOrientation(const Quaternion& orientation) { inline void Transform::setOrientation(const Quaternion& orientation) {
this->orientation = orientation; mOrientation = orientation;
} }
// Set the transform to the identity transform // Set the transform to the identity transform
inline void Transform::setToIdentity() { inline void Transform::setToIdentity() {
position = Vector3(0.0, 0.0, 0.0); mPosition = Vector3(0.0, 0.0, 0.0);
orientation = Quaternion::identity(); mOrientation = Quaternion::identity();
} }
// Set the transform from an OpenGL transform matrix // Set the transform from an OpenGL transform matrix
@ -100,52 +147,74 @@ inline void Transform::setFromOpenGL(decimal* openglMatrix) {
Matrix3x3 matrix(openglMatrix[0], openglMatrix[4], openglMatrix[8], Matrix3x3 matrix(openglMatrix[0], openglMatrix[4], openglMatrix[8],
openglMatrix[1], openglMatrix[5], openglMatrix[9], openglMatrix[1], openglMatrix[5], openglMatrix[9],
openglMatrix[2], openglMatrix[6], openglMatrix[10]); openglMatrix[2], openglMatrix[6], openglMatrix[10]);
orientation = Quaternion(matrix); mOrientation = Quaternion(matrix);
position.setAllValues(openglMatrix[12], openglMatrix[13], openglMatrix[14]); mPosition.setAllValues(openglMatrix[12], openglMatrix[13], openglMatrix[14]);
} }
// Get the OpenGL matrix of the transform // Get the OpenGL matrix of the transform
inline void Transform::getOpenGLMatrix(decimal* openglMatrix) const { inline void Transform::getOpenGLMatrix(decimal* openglMatrix) const {
const Matrix3x3& matrix = orientation.getMatrix(); const Matrix3x3& matrix = mOrientation.getMatrix();
openglMatrix[0] = matrix.getValue(0, 0); openglMatrix[1] = matrix.getValue(1, 0); openglMatrix[2] = matrix.getValue(2, 0); openglMatrix[3] = 0.0; openglMatrix[0] = matrix.getValue(0, 0); openglMatrix[1] = matrix.getValue(1, 0);
openglMatrix[4] = matrix.getValue(0, 1); openglMatrix[5] = matrix.getValue(1, 1); openglMatrix[6] = matrix.getValue(2, 1); openglMatrix[7] = 0.0; openglMatrix[2] = matrix.getValue(2, 0); openglMatrix[3] = 0.0;
openglMatrix[8] = matrix.getValue(0, 2); openglMatrix[9] = matrix.getValue(1, 2); openglMatrix[10] = matrix.getValue(2, 2); openglMatrix[11] = 0.0; openglMatrix[4] = matrix.getValue(0, 1); openglMatrix[5] = matrix.getValue(1, 1);
openglMatrix[12] = position.getX(); openglMatrix[13] = position.getY(); openglMatrix[14] = position.getZ(); openglMatrix[15] = 1.0; openglMatrix[6] = matrix.getValue(2, 1); openglMatrix[7] = 0.0;
openglMatrix[8] = matrix.getValue(0, 2); openglMatrix[9] = matrix.getValue(1, 2);
openglMatrix[10] = matrix.getValue(2, 2); openglMatrix[11] = 0.0;
openglMatrix[12] = mPosition.getX(); openglMatrix[13] = mPosition.getY();
openglMatrix[14] = mPosition.getZ(); openglMatrix[15] = 1.0;
} }
// Return the inverse of the transform // Return the inverse of the transform
inline Transform Transform::inverse() const { inline Transform Transform::inverse() const {
const Quaternion& invQuaternion = orientation.getInverse(); const Quaternion& invQuaternion = mOrientation.getInverse();
Matrix3x3 invMatrix = invQuaternion.getMatrix(); Matrix3x3 invMatrix = invQuaternion.getMatrix();
return Transform(invMatrix * (-position), invQuaternion); return Transform(invMatrix * (-mPosition), invQuaternion);
} }
// Return an interpolated transform // Return an interpolated transform
inline Transform Transform::interpolateTransforms(const Transform& oldTransform, const Transform& newTransform, decimal interpolationFactor) { inline Transform Transform::interpolateTransforms(const Transform& oldTransform,
Vector3 interPosition = oldTransform.position * (1.0 - interpolationFactor) + newTransform.position * interpolationFactor; const Transform& newTransform,
Quaternion interOrientation = Quaternion::slerp(oldTransform.orientation, newTransform.orientation, interpolationFactor); decimal interpolationFactor) {
Vector3 interPosition = oldTransform.mPosition * (1.0 - interpolationFactor) +
newTransform.mPosition * interpolationFactor;
Quaternion interOrientation = Quaternion::slerp(oldTransform.mOrientation,
newTransform.mOrientation,
interpolationFactor);
return Transform(interPosition, interOrientation); return Transform(interPosition, interOrientation);
} }
// Return the transformed vector // Return the transformed vector
inline Vector3 Transform::operator*(const Vector3& vector) const { inline Vector3 Transform::operator*(const Vector3& vector) const {
return (orientation.getMatrix() * vector) + position; return (mOrientation.getMatrix() * vector) + mPosition;
} }
// Operator of multiplication of a transform with another one // Operator of multiplication of a transform with another one
inline Transform Transform::operator*(const Transform& transform2) const { inline Transform Transform::operator*(const Transform& transform2) const {
return Transform(position + orientation.getMatrix() * transform2.position, orientation * transform2.orientation); return Transform(mPosition + mOrientation.getMatrix() * transform2.mPosition,
mOrientation * transform2.mOrientation);
} }
// Return true if the two transforms are equal // Return true if the two transforms are equal
inline bool Transform::operator==(const Transform& transform2) const { inline bool Transform::operator==(const Transform& transform2) const {
return (position == transform2.position) && (orientation == transform2.orientation); return (mPosition == transform2.mPosition) && (mOrientation == transform2.mOrientation);
} }
// Return true if the two transforms are different // Return true if the two transforms are different
inline bool Transform::operator!=(const Transform& transform2) const { inline bool Transform::operator!=(const Transform& transform2) const {
return !(*this == transform2); return !(*this == transform2);
} }
// Assignment operator
inline Transform& Transform::operator=(const Transform& transform) {
if (&transform != this) {
mPosition = transform.mPosition;
mOrientation = transform.mOrientation;
}
return *this;
}
} // End of the ReactPhysics3D namespace } // End of the ReactPhysics3D namespace

View File

@ -34,23 +34,23 @@ using namespace reactphysics3d;
// Constructor of the class Vector3D // Constructor of the class Vector3D
Vector3::Vector3() { Vector3::Vector3() {
values[0] = 0.0; mValues[0] = 0.0;
values[1] = 0.0; mValues[1] = 0.0;
values[2] = 0.0; mValues[2] = 0.0;
} }
// Constructor with arguments // Constructor with arguments
Vector3::Vector3(decimal x, decimal y, decimal z) { Vector3::Vector3(decimal x, decimal y, decimal z) {
values[0] = x; mValues[0] = x;
values[1] = y; mValues[1] = y;
values[2] = z; mValues[2] = z;
} }
// Copy-constructor // Copy-constructor
Vector3::Vector3(const Vector3& vector) { Vector3::Vector3(const Vector3& vector) {
values[0] = vector.values[0]; mValues[0] = vector.mValues[0];
values[1] = vector.values[1]; mValues[1] = vector.mValues[1];
values[2] = vector.values[2]; mValues[2] = vector.mValues[2];
} }
// Destructor // Destructor
@ -66,7 +66,7 @@ Vector3 Vector3::getUnit() const {
// Compute and return the unit vector // Compute and return the unit vector
decimal lengthInv = 1.0 / lengthVector; decimal lengthInv = 1.0 / lengthVector;
return Vector3(values[0] * lengthInv, values[1] * lengthInv, values[2] * lengthInv); return Vector3(mValues[0] * lengthInv, mValues[1] * lengthInv, mValues[2] * lengthInv);
} }
// Return two unit orthogonal vectors of the current vector // Return two unit orthogonal vectors of the current vector
@ -75,20 +75,23 @@ Vector3 Vector3::getOneOrthogonalVector() const {
// Compute a first orthogonal vector // Compute a first orthogonal vector
Vector3 vector1; Vector3 vector1;
if (!approxEqual(values[0], 0.0)) { // If x != 0 if (!approxEqual(mValues[0], 0.0)) { // If x != 0
vector1.setY(values[0]); vector1.setY(mValues[0]);
vector1.setZ((-2*values[0]*values[1]*values[2] + 2*values[0]*values[2])/(2*(values[2]*values[2] + values[0]*values[0]))); vector1.setZ((-2*mValues[0]*mValues[1]*mValues[2] +
vector1.setX((-values[0]*values[1]-values[2]*vector1.getZ())/values[0]); 2*mValues[0]*mValues[2])/(2*(mValues[2]*mValues[2] + mValues[0]*mValues[0])));
vector1.setX((-mValues[0]*mValues[1]-mValues[2]*vector1.getZ())/mValues[0]);
} }
else if (!approxEqual(values[1], 0.0)) { // If y != 0 else if (!approxEqual(mValues[1], 0.0)) { // If y != 0
vector1.setZ(values[1]); vector1.setZ(mValues[1]);
vector1.setX((-2*values[0]*values[1]*values[2] + 2*values[0]*values[1])/(2*(values[1]*values[1] + values[0]*values[0]))); vector1.setX((-2*mValues[0]*mValues[1]*mValues[2] +
vector1.setY((-values[2]*values[1]-values[0]*vector1.getX())/values[1]); 2*mValues[0]*mValues[1])/(2*(mValues[1]*mValues[1] + mValues[0]*mValues[0])));
vector1.setY((-mValues[2]*mValues[1]-mValues[0]*vector1.getX())/mValues[1]);
} }
else if (!approxEqual(values[2], 0.0)) { // If z != 0 else if (!approxEqual(mValues[2], 0.0)) { // If z != 0
vector1.setX(values[2]); vector1.setX(mValues[2]);
vector1.setY((-2*values[0]*values[1]*values[2] + 2*values[1]*values[2])/(2*(values[2]*values[2] + values[1]*values[1]))); vector1.setY((-2*mValues[0]*mValues[1]*mValues[2] +
vector1.setZ((-values[0]*values[2]-values[1]*vector1.getY())/values[2]); 2*mValues[1]*mValues[2])/(2*(mValues[2]*mValues[2] + mValues[1]*mValues[1])));
vector1.setZ((-mValues[0]*mValues[2]-mValues[1]*vector1.getY())/mValues[2]);
} }
//assert(vector1.isUnit()); //assert(vector1.isUnit());

View File

@ -41,44 +41,113 @@ namespace reactphysics3d {
------------------------------------------------------------------- -------------------------------------------------------------------
*/ */
class Vector3 { class Vector3 {
private : private :
decimal values[3]; // Values of the 3D vector
// -------------------- Attributes -------------------- //
// Values of the 3D vector
decimal mValues[3];
public : public :
Vector3(); // Constructor of the class Vector3D
Vector3(decimal x, decimal y, decimal z); // Constructor with arguments // -------------------- Methods -------------------- //
Vector3(const Vector3& vector); // Copy-constructor
virtual ~Vector3(); // Destructor // Constructor of the class Vector3D
decimal getX() const; // Get the x component of the vector Vector3();
decimal getY() const; // Get the y component of the vector
decimal getZ() const; // Get the z component of the vector // Constructor with arguments
void setX(decimal x); // Set the x component of the vector Vector3(decimal x, decimal y, decimal z);
void setY(decimal y); // Set the y component of the vector
void setZ(decimal z); // Set the z component of the vector // Copy-constructor
void setAllValues(decimal x, decimal y, decimal z); // Set all the values of the vector Vector3(const Vector3& vector);
decimal length() const; // Return the lenght of the vector
decimal lengthSquare() const; // Return the square of the length of the vector // Destructor
Vector3 getUnit() const; // Return the corresponding unit vector ~Vector3();
bool isUnit() const; // Return true if the vector is unit and false otherwise
bool isZero() const; // Return true if the current vector is the zero vector // Get the x component of the vector
Vector3 getOneOrthogonalVector() const; // Return one unit orthogonal vectors of the current vector decimal getX() const;
decimal dot(const Vector3& vector) const; // Dot product of two vectors
Vector3 cross(const Vector3& vector) const; // Cross product of two vectors // Get the y component of the vector
Vector3 getAbsoluteVector() const; // Return the corresponding absolute value vector decimal getY() const;
int getMinAxis() const; // Return the axis with the minimal value
int getMaxAxis() const; // Return the axis with the maximal value // Get the z component of the vector
bool isParallelWith(const Vector3& vector) const; // Return true if two vectors are parallel decimal getZ() const;
// --- Overloaded operators --- // // Set the x component of the vector
bool operator== (const Vector3& vector) const; // Overloaded operator for the equality condition void setX(decimal x);
bool operator!= (const Vector3& vector) const; // Overloaded operator for the is different condition
Vector3& operator+=(const Vector3& vector); // Overloaded operator for addition with assignment // Set the y component of the vector
Vector3& operator-=(const Vector3& vector); // Overloaded operator for substraction with assignment void setY(decimal y);
Vector3& operator*=(decimal number); // Overloaded operator for multiplication with a number with assignment
decimal& operator[] (int index); // Overloaded operator for value access // Set the z component of the vector
const decimal& operator[] (int index) const; // Overloaded operator for value access void setZ(decimal z);
// Friend functions // Set all the values of the vector
void setAllValues(decimal x, decimal y, decimal z);
// Return the lenght of the vector
decimal length() const;
// Return the square of the length of the vector
decimal lengthSquare() const;
// Return the corresponding unit vector
Vector3 getUnit() const;
// Return true if the vector is unit and false otherwise
bool isUnit() const;
// Return true if the current vector is the zero vector
bool isZero() const;
// Return one unit orthogonal vectors of the current vector
Vector3 getOneOrthogonalVector() const;
// Dot product of two vectors
decimal dot(const Vector3& vector) const;
// Cross product of two vectors
Vector3 cross(const Vector3& vector) const;
// Return the corresponding absolute value vector
Vector3 getAbsoluteVector() const;
// Return the axis with the minimal value
int getMinAxis() const;
// Return the axis with the maximal value
int getMaxAxis() const;
// Return true if two vectors are parallel
bool isParallelWith(const Vector3& vector) const;
// Overloaded operator for the equality condition
bool operator== (const Vector3& vector) const;
// Overloaded operator for the is different condition
bool operator!= (const Vector3& vector) const;
// Overloaded operator for addition with assignment
Vector3& operator+=(const Vector3& vector);
// Overloaded operator for substraction with assignment
Vector3& operator-=(const Vector3& vector);
// Overloaded operator for multiplication with a number with assignment
Vector3& operator*=(decimal number);
// Overloaded operator for value access
decimal& operator[] (int index);
// Overloaded operator for value access
const decimal& operator[] (int index) const;
// Overloaded operator
Vector3& operator=(const Vector3& vector);
// -------------------- Friends -------------------- //
friend Vector3 operator+(const Vector3& vector1, const Vector3& vector2); friend Vector3 operator+(const Vector3& vector1, const Vector3& vector2);
friend Vector3 operator-(const Vector3& vector1, const Vector3& vector2); friend Vector3 operator-(const Vector3& vector1, const Vector3& vector2);
friend Vector3 operator-(const Vector3& vector); friend Vector3 operator-(const Vector3& vector);
@ -88,69 +157,69 @@ class Vector3 {
// Get the x component of the vector // Get the x component of the vector
inline decimal Vector3::getX() const { inline decimal Vector3::getX() const {
return values[0]; return mValues[0];
} }
// Get the y component of the vector // Get the y component of the vector
inline decimal Vector3::getY() const { inline decimal Vector3::getY() const {
return values[1]; return mValues[1];
} }
// Get the z component of the vector // Get the z component of the vector
inline decimal Vector3::getZ() const { inline decimal Vector3::getZ() const {
return values[2]; return mValues[2];
} }
// Set the x component of the vector // Set the x component of the vector
inline void Vector3::setX(decimal x) { inline void Vector3::setX(decimal x) {
this->values[0] = x; this->mValues[0] = x;
} }
// Set the y component of the vector // Set the y component of the vector
inline void Vector3::setY(decimal y) { inline void Vector3::setY(decimal y) {
this->values[1] = y; this->mValues[1] = y;
} }
// Set the z component of the vector // Set the z component of the vector
inline void Vector3::setZ(decimal z) { inline void Vector3::setZ(decimal z) {
this->values[2] = z; this->mValues[2] = z;
} }
// Set all the values of the vector (inline) // Set all the values of the vector (inline)
inline void Vector3::setAllValues(decimal x, decimal y, decimal z) { inline void Vector3::setAllValues(decimal x, decimal y, decimal z) {
values[0]= x; mValues[0]= x;
values[1] = y; mValues[1] = y;
values[2] = z; mValues[2] = z;
} }
// Return the length of the vector (inline) // Return the length of the vector (inline)
inline decimal Vector3::length() const { inline decimal Vector3::length() const {
// Compute and return the length of the vector // Compute and return the length of the vector
return sqrt(values[0]*values[0] + values[1]*values[1] + values[2]*values[2]); return sqrt(mValues[0]*mValues[0] + mValues[1]*mValues[1] + mValues[2]*mValues[2]);
} }
// Return the square of the length of the vector // Return the square of the length of the vector
inline decimal Vector3::lengthSquare() const { inline decimal Vector3::lengthSquare() const {
return values[0]*values[0] + values[1]*values[1] + values[2]*values[2]; return mValues[0]*mValues[0] + mValues[1]*mValues[1] + mValues[2]*mValues[2];
} }
// Scalar product of two vectors (inline) // Scalar product of two vectors (inline)
inline decimal Vector3::dot(const Vector3& vector) const { inline decimal Vector3::dot(const Vector3& vector) const {
// Compute and return the result of the scalar product // Compute and return the result of the scalar product
return (values[0] * vector.values[0] + values[1] * vector.values[1] + values[2] * vector.values[2]); return (mValues[0] * vector.mValues[0] + mValues[1] * vector.mValues[1] + mValues[2] * vector.mValues[2]);
} }
// Cross product of two vectors (inline) // Cross product of two vectors (inline)
inline Vector3 Vector3::cross(const Vector3& vector) const { inline Vector3 Vector3::cross(const Vector3& vector) const {
// Compute and return the cross product // Compute and return the cross product
return Vector3(values[1] * vector.values[2] - values[2] * vector.values[1], return Vector3(mValues[1] * vector.mValues[2] - mValues[2] * vector.mValues[1],
values[2] * vector.values[0] - values[0] * vector.values[2], mValues[2] * vector.mValues[0] - mValues[0] * vector.mValues[2],
values[0] * vector.values[1] - values[1] * vector.values[0]); mValues[0] * vector.mValues[1] - mValues[1] * vector.mValues[0]);
} }
// Return the corresponding absolute value vector // Return the corresponding absolute value vector
inline Vector3 Vector3::getAbsoluteVector() const { inline Vector3 Vector3::getAbsoluteVector() const {
return Vector3(std::abs(values[0]), std::abs(values[1]), std::abs(values[2])); return Vector3(std::abs(mValues[0]), std::abs(mValues[1]), std::abs(mValues[2]));
} }
// Return true if two vectors are parallel // Return true if two vectors are parallel
@ -162,27 +231,27 @@ inline bool Vector3::isParallelWith(const Vector3& vector) const {
// Return the axis with the minimal value // Return the axis with the minimal value
inline int Vector3::getMinAxis() const { inline int Vector3::getMinAxis() const {
return (values[0] < values[1] ? (values[0] < values[2] ? 0 : 2) : (values[1] < values[2] ? 1 : 2)); return (mValues[0] < mValues[1] ? (mValues[0] < mValues[2] ? 0 : 2) : (mValues[1] < mValues[2] ? 1 : 2));
} }
// Return the axis with the maximal value // Return the axis with the maximal value
inline int Vector3::getMaxAxis() const { inline int Vector3::getMaxAxis() const {
return (values[0] < values[1] ? (values[1] < values[2] ? 2 : 1) : (values[0] < values[2] ? 2 : 0)); return (mValues[0] < mValues[1] ? (mValues[1] < mValues[2] ? 2 : 1) : (mValues[0] < mValues[2] ? 2 : 0));
} }
// Return true if the vector is unit and false otherwise // Return true if the vector is unit and false otherwise
inline bool Vector3::isUnit() const { inline bool Vector3::isUnit() const {
return approxEqual(values[0] * values[0] + values[1] * values[1] + values[2] * values[2], 1.0); return approxEqual(mValues[0] * mValues[0] + mValues[1] * mValues[1] + mValues[2] * mValues[2], 1.0);
} }
// Return true if the vector is the zero vector // Return true if the vector is the zero vector
inline bool Vector3::isZero() const { inline bool Vector3::isZero() const {
return approxEqual(values[0] * values[0] + values[1] * values[1] + values[2] * values[2], 0.0); return approxEqual(mValues[0] * mValues[0] + mValues[1] * mValues[1] + mValues[2] * mValues[2], 0.0);
} }
// Overloaded operator for the equality condition // Overloaded operator for the equality condition
inline bool Vector3::operator== (const Vector3& vector) const { inline bool Vector3::operator== (const Vector3& vector) const {
return (values[0] == vector.values[0] && values[1] == vector.values[1] && values[2] == vector.values[2]); return (mValues[0] == vector.mValues[0] && mValues[1] == vector.mValues[1] && mValues[2] == vector.mValues[2]);
} }
// Overloaded operator for the is different condition // Overloaded operator for the is different condition
@ -192,56 +261,56 @@ inline bool Vector3::operator!= (const Vector3& vector) const {
// Overloaded operator for addition with assignment // Overloaded operator for addition with assignment
inline Vector3& Vector3::operator+=(const Vector3& vector) { inline Vector3& Vector3::operator+=(const Vector3& vector) {
values[0] += vector.values[0]; mValues[0] += vector.mValues[0];
values[1] += vector.values[1]; mValues[1] += vector.mValues[1];
values[2] += vector.values[2]; mValues[2] += vector.mValues[2];
return *this; return *this;
} }
// Overloaded operator for substraction with assignment // Overloaded operator for substraction with assignment
inline Vector3& Vector3::operator-=(const Vector3& vector) { inline Vector3& Vector3::operator-=(const Vector3& vector) {
values[0] -= vector.values[0]; mValues[0] -= vector.mValues[0];
values[1] -= vector.values[1]; mValues[1] -= vector.mValues[1];
values[2] -= vector.values[2]; mValues[2] -= vector.mValues[2];
return *this; return *this;
} }
// Overloaded operator for multiplication with a number with assignment // Overloaded operator for multiplication with a number with assignment
inline Vector3& Vector3::operator*=(decimal number) { inline Vector3& Vector3::operator*=(decimal number) {
values[0] *= number; mValues[0] *= number;
values[1] *= number; mValues[1] *= number;
values[2] *= number; mValues[2] *= number;
return *this; return *this;
} }
// Overloaded operator for value access // Overloaded operator for value access
inline decimal& Vector3::operator[] (int index) { inline decimal& Vector3::operator[] (int index) {
return values[index]; return mValues[index];
} }
// Overloaded operator for value access // Overloaded operator for value access
inline const decimal& Vector3::operator[] (int index) const { inline const decimal& Vector3::operator[] (int index) const {
return values[index]; return mValues[index];
} }
// Overloaded operator for addition // Overloaded operator for addition
inline Vector3 operator+(const Vector3& vector1, const Vector3& vector2) { inline Vector3 operator+(const Vector3& vector1, const Vector3& vector2) {
return Vector3(vector1.values[0] + vector2.values[0], vector1.values[1] + vector2.values[1], vector1.values[2] + vector2.values[2]); return Vector3(vector1.mValues[0] + vector2.mValues[0], vector1.mValues[1] + vector2.mValues[1], vector1.mValues[2] + vector2.mValues[2]);
} }
// Overloaded operator for substraction // Overloaded operator for substraction
inline Vector3 operator-(const Vector3& vector1, const Vector3& vector2) { inline Vector3 operator-(const Vector3& vector1, const Vector3& vector2) {
return Vector3(vector1.values[0] - vector2.values[0], vector1.values[1] - vector2.values[1], vector1.values[2] - vector2.values[2]); return Vector3(vector1.mValues[0] - vector2.mValues[0], vector1.mValues[1] - vector2.mValues[1], vector1.mValues[2] - vector2.mValues[2]);
} }
// Overloaded operator for the negative of a vector // Overloaded operator for the negative of a vector
inline Vector3 operator-(const Vector3& vector) { inline Vector3 operator-(const Vector3& vector) {
return Vector3(-vector.values[0], -vector.values[1], -vector.values[2]); return Vector3(-vector.mValues[0], -vector.mValues[1], -vector.mValues[2]);
} }
// Overloaded operator for multiplication with a number // Overloaded operator for multiplication with a number
inline Vector3 operator*(const Vector3& vector, decimal number) { inline Vector3 operator*(const Vector3& vector, decimal number) {
return Vector3(number * vector.values[0], number * vector.values[1], number * vector.values[2]); return Vector3(number * vector.mValues[0], number * vector.mValues[1], number * vector.mValues[2]);
} }
// Overloaded operator for multiplication with a number // Overloaded operator for multiplication with a number
@ -249,6 +318,16 @@ inline Vector3 operator*(decimal number, const Vector3& vector) {
return vector * number; return vector * number;
} }
// Assignment operator
inline Vector3& Vector3::operator=(const Vector3& vector) {
if (&vector != this) {
mValues[0] = vector.mValues[0];
mValues[1] = vector.mValues[1];
mValues[2] = vector.mValues[2];
}
return *this;
}
} // End of the ReactPhysics3D namespace } // End of the ReactPhysics3D namespace
#endif #endif

View File

@ -38,412 +38,4 @@
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
// ReactPhysics3D namespace
namespace reactphysics3d {
// ---------- Mathematics functions ---------- //
// Rotate a vector according to a rotation quaternion.
// The function returns the vector rotated according to the quaternion in argument
inline reactphysics3d::Vector3 rotateVectorWithQuaternion(const reactphysics3d::Vector3& vector, const reactphysics3d::Quaternion& quaternion) {
// Convert the vector into a quaternion
reactphysics3d::Quaternion vectorQuaternion(0, vector);
// Compute the quaternion rotation result
reactphysics3d::Quaternion quaternionResult = (quaternion * vectorQuaternion) * quaternion.getInverse();
// Convert the result quaternion into a vector
return quaternionResult.vectorV();
}
// Given two lines (given by the points "point1", "point2" and the vectors "d1" and "d2" that are not parallel, this method returns the values
// "alpha" and "beta" such that the two points P1 and P2 are the two closest point between the two lines and such that
// P1 = point1 + alpha * d1
// P2 = point2 + beta * d2
inline void closestPointsBetweenTwoLines(const reactphysics3d::Vector3& point1, const reactphysics3d::Vector3& d1, const reactphysics3d::Vector3& point2,
const reactphysics3d::Vector3& d2, decimal* alpha, decimal* beta) {
reactphysics3d::Vector3 r = point1 - point2;
decimal a = d1.dot(d1);
decimal b = d1.dot(d2);
decimal c = d1.dot(r);
decimal e = d2.dot(d2);
decimal f = d2.dot(r);
decimal d = a*e-b*b;
// The two lines must not be parallel
assert(!reactphysics3d::approxEqual(d, 0.0));
// Compute the "alpha" and "beta" values
*alpha = (b*f -c*e)/d;
*beta = (a*f-b*c)/d;
}
// This method returns true if the point "P" is on the segment between "segPointA" and "segPointB" and return false otherwise
inline bool isPointOnSegment(const reactphysics3d::Vector3& segPointA, const reactphysics3d::Vector3& segPointB, const reactphysics3d::Vector3& P) {
// Check if the point P is on the line between "segPointA" and "segPointB"
reactphysics3d::Vector3 d = segPointB - segPointA;
reactphysics3d::Vector3 dP = P - segPointA;
if (!d.isParallelWith(dP)) {
return false;
}
// Compute the length of the segment
decimal segmentLength = d.length();
// Compute the distance from point "P" to points "segPointA" and "segPointB"
decimal distA = dP.length();
decimal distB = (P - segPointB).length();
// If one of the "distA" and "distB" is greather than the length of the segment, then P is not on the segment
if (distA > segmentLength || distB > segmentLength) {
return false;
}
// Otherwise, the point P is on the segment
return true;
}
// Given two lines in 3D that intersect, this method returns the intersection point between the two lines.
// The first line is given by the point "p1" and the vector "d1", the second line is given by the point "p2" and the vector "d2".
inline reactphysics3d::Vector3 computeLinesIntersection(const reactphysics3d::Vector3& p1, const reactphysics3d::Vector3& d1,
const reactphysics3d::Vector3& p2, const reactphysics3d::Vector3& d2) {
// Computes the two closest points on the lines
decimal alpha, beta;
closestPointsBetweenTwoLines(p1, d1, p2, d2, &alpha, &beta);
reactphysics3d::Vector3 point1 = p1 + alpha * d1;
reactphysics3d::Vector3 point2 = p2 + beta * d2;
// The two points must be very close
//assert((point1-point2).length() <= 0.1);
// Return the intersection point (halfway between "point1" and "point2")
return 0.5 * (point1 + point2);
}
// Given two segments in 3D that are not parallel and that intersect, this method computes the intersection point between the two segments.
// This method returns the intersection point.
inline reactphysics3d::Vector3 computeNonParallelSegmentsIntersection(const reactphysics3d::Vector3& seg1PointA, const reactphysics3d::Vector3& seg1PointB,
const reactphysics3d::Vector3& seg2PointA, const reactphysics3d::Vector3& seg2PointB) {
// Determine the lines of both segments
reactphysics3d::Vector3 d1 = seg1PointB - seg1PointA;
reactphysics3d::Vector3 d2 = seg2PointB - seg2PointA;
// The segments must not be parallel
assert(!d1.isParallelWith(d2));
// Compute the closet points between the two lines
decimal alpha, beta;
closestPointsBetweenTwoLines(seg1PointA, d1, seg2PointA, d2, &alpha, &beta);
reactphysics3d::Vector3 point1 = seg1PointA + alpha * d1;
reactphysics3d::Vector3 point2 = seg2PointA + beta * d2;
// The closest points have to be on the segments, otherwise there is no intersection between the segments
assert(isPointOnSegment(seg1PointA, seg1PointB, point1));
assert(isPointOnSegment(seg2PointA, seg2PointB, point2));
// If the two closest point aren't very close, there is no intersection between the segments
reactphysics3d::Vector3 d = point2 - point1;
const decimal epsilon = 0.00001;
assert(d.length() <= epsilon);
// They are very close so we return the intersection point (halfway between "point1" and "point2"
return 0.5 * (point1 + point2);
}
// Move a set of points by a given vector.
// The method returns a set of points moved by the given vector.
inline std::vector<reactphysics3d::Vector3> movePoints(const std::vector<reactphysics3d::Vector3>& points, const reactphysics3d::Vector3& vector) {
std::vector<reactphysics3d::Vector3> result;
// For each point of the set
for (unsigned int i=0; i<points.size(); ++i) {
// Move the point
result.push_back(points[i] + vector);
}
// Return the result set of points
return result;
}
// Compute the projection of a set of 3D points onto a 3D plane. The set of points is given by "points" and the plane is given by
// a point "A" and a normal vector "normal". This method returns the initial set of points projected onto the plane.
inline std::vector<reactphysics3d::Vector3> projectPointsOntoPlane(const std::vector<reactphysics3d::Vector3>& points, const reactphysics3d::Vector3& A,
const reactphysics3d::Vector3& normal) {
assert(normal.length() != 0.0);
std::vector<Vector3> projectedPoints;
reactphysics3d::Vector3 n = normal.getUnit();
// For each point of the set
for (unsigned int i=0; i<points.size(); ++i) {
// Compute the projection of the point onto the plane
projectedPoints.push_back(points[i] - (n * (points[i] - A).dot(n)));
}
// Return the projected set of points
return projectedPoints;
}
// Compute the distance between a point "P" and a line (given by a point "A" and a vector "v")
inline decimal computeDistanceBetweenPointAndLine(const reactphysics3d::Vector3& P, const reactphysics3d::Vector3& A, const reactphysics3d::Vector3& v) {
assert(v.length() != 0);
return ((P-A).cross(v).length() / (v.length()));
}
// Compute the orthogonal projection of a point "P" on a line (given by a point "A" and a vector "v")
inline reactphysics3d::Vector3 computeOrthogonalProjectionOfPointOntoALine(const reactphysics3d::Vector3& P, const reactphysics3d::Vector3& A, const reactphysics3d::Vector3& v) {
return (A + ((P-A).dot(v) / (v.dot(v))) * v);
}
// Given a point P and 4 points that form a rectangle (point P and the 4 points have to be on the same plane) this method computes
// the point Q that is the nearest point to P that is inside (on a border of) the rectangle. The point P should be outside the rectangle.
// The result point Q will be in a segment of the rectangle
inline reactphysics3d::Vector3 computeNearestPointOnRectangle(const reactphysics3d::Vector3& P, const std::vector<reactphysics3d::Vector3> rectangle) {
assert(rectangle.size() == 4);
decimal distPSegment1 = computeDistanceBetweenPointAndLine(P, rectangle[0], rectangle[1] - rectangle[0]);
decimal distPSegment2 = computeDistanceBetweenPointAndLine(P, rectangle[1], rectangle[2] - rectangle[1]);
decimal distPSegment3 = computeDistanceBetweenPointAndLine(P, rectangle[2], rectangle[3] - rectangle[2]);
decimal distPSegment4 = computeDistanceBetweenPointAndLine(P, rectangle[3], rectangle[0] - rectangle[3]);
decimal distSegment1Segment3 = computeDistanceBetweenPointAndLine(rectangle[0], rectangle[3], rectangle[3] - rectangle[2]);
decimal distSegment2Segment4 = computeDistanceBetweenPointAndLine(rectangle[1], rectangle[3], rectangle[0] - rectangle[3]);
Vector3 resultPoint;
// Check if P is between the lines of the first pair of parallel segments of the rectangle
if (distPSegment1 <= distSegment1Segment3 && distPSegment3 <= distSegment1Segment3) {
// Find among segments 2 and 4 which one is the nearest
if (distPSegment2 <= distPSegment4) { // Segment 2 is the nearest
// We compute the projection of the point P onto the segment 2
resultPoint = computeOrthogonalProjectionOfPointOntoALine(P, rectangle[1], rectangle[2] - rectangle[1]);
}
else { // Segment 4 is the nearest
// We compute the projection of the point P onto the segment 4
resultPoint = computeOrthogonalProjectionOfPointOntoALine(P, rectangle[3], rectangle[0] - rectangle[3]);
}
}
// Check if P is between the lines of the second pair of parallel segments of the rectangle
else if (distPSegment2 <= distSegment2Segment4 && distPSegment4 <= distSegment2Segment4) {
// Find among segments 1 and 3 which one is the nearest
if (distPSegment1 <= distPSegment3) { // Segment 1 is the nearest
// We compute the projection of the point P onto the segment 1
resultPoint = computeOrthogonalProjectionOfPointOntoALine(P, rectangle[0], rectangle[1] - rectangle[0]);
}
else { // Segment 3 is the nearest
// We compute the projection of the point P onto the segment 3
resultPoint = computeOrthogonalProjectionOfPointOntoALine(P, rectangle[2], rectangle[3] - rectangle[2]);
}
}
else if (distPSegment4 <= distPSegment2) {
if (distPSegment1 <= distPSegment3) { // The point P is in the corner of point rectangle[0]
// Return the corner of the rectangle
return rectangle[0];
}
else { // The point P is in the corner of point rectangle[3]
// Return the corner of the rectangle
return rectangle[3];
}
}
else {
if (distPSegment1 <= distPSegment3) { // The point P is in the corner of point rectangle[1]
// Return the corner of the rectangle
return rectangle[1];
}
else { // The point P is in the corner of point rectangle[2]
// Return the corner of the rectangle
return rectangle[2];
}
}
// Return the result point
return resultPoint;
}
// Compute the intersection between two parallel segments (the first segment is between the points "seg1PointA" and "seg1PointB" and the second
// segment is between the points "seg2PointA" and "seg2PointB"). The result is the segment intersection (represented by the points "resultPointA"
// and "resultPointB". Because the two given segments don't have to be on the same exact line, the result intersection segment will a segment
// halway between the first and the second given segments.
inline void computeParallelSegmentsIntersection(const reactphysics3d::Vector3& seg1PointA, const reactphysics3d::Vector3& seg1PointB,
const reactphysics3d::Vector3& seg2PointA, const reactphysics3d::Vector3& seg2PointB,
reactphysics3d::Vector3& resultPointA, reactphysics3d::Vector3& resultPointB) {
// Compute the segment vectors
reactphysics3d::Vector3 d1 = seg1PointB - seg1PointA;
reactphysics3d::Vector3 d2 = seg2PointB - seg2PointA;
// The two segments should be parallel
assert(d1.isParallelWith(d2));
// Compute the projection of the two points of the second segment onto the vector of segment 1
decimal projSeg2PointA = d1.getUnit().dot(seg2PointA - seg1PointA);
decimal projSeg2PointB = d1.getUnit().dot(seg2PointB - seg1PointA);
// The projections intervals should intersect
assert(!(projSeg2PointA < 0.0 && projSeg2PointB < 0.0));
assert(!(projSeg2PointA > d1.length() && projSeg2PointB > d1.length()));
// Compute the vector "v" from a point on the line 1 to the orthogonal point of the line 2
reactphysics3d::Vector3 point = computeOrthogonalProjectionOfPointOntoALine(seg2PointA, seg1PointA, d1);
reactphysics3d::Vector3 v = seg2PointA - point;
// Return the segment intersection according to the configuration of two projection intervals
if (projSeg2PointA >= 0 && projSeg2PointA <= d1.length() && projSeg2PointB >= d1.length()) {
// Move the contact points halfway between the two segments
resultPointA = seg2PointA - 0.5 * v;
resultPointB = seg1PointB + 0.5 * v;
}
else if (projSeg2PointA <= 0 && projSeg2PointB >= 0 && projSeg2PointB <= d1.length()) {
// Move the contact points halfway between the two segments
resultPointA = seg1PointA + 0.5 * v;
resultPointB = seg2PointB - 0.5 * v;
}
else if (projSeg2PointA <= 0 && projSeg2PointB >= d1.length()) {
// Move the contact points halfway between the two segments
resultPointA = seg1PointA + 0.5 * v;
resultPointB = seg1PointB + 0.5 * v;
}
else if (projSeg2PointA <= d1.length() && projSeg2PointB <= d1.length()) {
// Move the contact points halfway between the two segments
resultPointA = seg2PointA - 0.5 * v;
resultPointB = seg2PointB - 0.5 * v;
}
}
// This method clip a 3D segment with 3D rectangle polygon. The segment and the rectangle are asssumed to be on the same plane. We
// also assume that the segment is not completely outside the clipping rectangle.
// The segment is given by the two vertices in "segment" and the rectangle is given by the ordered vertices in "clipRectangle".
// This method returns the clipped segment.
inline std::vector<reactphysics3d::Vector3> clipSegmentWithRectangleInPlane(const std::vector<reactphysics3d::Vector3>& segment, const std::vector<reactphysics3d::Vector3> clipRectangle) {
decimal const epsilon = 0.01;
assert(segment.size() == 2);
assert(clipRectangle.size() == 4);
std::vector<reactphysics3d::Vector3> inputSegment = segment;
std::vector<reactphysics3d::Vector3> outputSegment;
// For each edge of the clip rectangle
for (unsigned int i=0; i<4; ++i) {
outputSegment.clear();
// Current clipped segment
//assert(inputSegment.size() == 2);
reactphysics3d::Vector3 S = inputSegment[0];
reactphysics3d::Vector3 P = inputSegment[1];
// Edge of the clip rectangle
reactphysics3d::Vector3 A = clipRectangle[i];
reactphysics3d::Vector3 B = clipRectangle[ (i+1) % 4];
reactphysics3d::Vector3 planeNormal = clipRectangle[(i+2) % 4] - clipRectangle[(i+1) % 4];
// If the point P is inside the clip plane
if (planeNormal.dot(P-A) >= 0.0 - epsilon) {
// If the point S is inside the clip plane
if (planeNormal.dot(S-A) >= 0.0 - epsilon) {
outputSegment.push_back(P);
outputSegment.push_back(S);
}
else { // P is inside and S is outside the clip plane
// Compute the intersection point between the segment SP and the clip plane
reactphysics3d::Vector3 intersectPoint = computeLinesIntersection(S, P-S, A, B-A);
outputSegment.push_back(P);
outputSegment.push_back(intersectPoint);
}
}
else if (planeNormal.dot(S-A) > 0.0 - epsilon) { // P is outside and S is inside the clip plane
// Compute the intersection point between the segment SP and the clip plane
reactphysics3d::Vector3 intersectPoint = computeLinesIntersection(S, P-S, A, B-A);
outputSegment.push_back(S);
outputSegment.push_back(intersectPoint);
}
inputSegment = outputSegment;
}
// Return the clipped segment
return outputSegment;
}
// This method uses the Sutherland-Hodgman clipping algorithm to clip a subject polygon (given by the ordered 3D vertices in "subjectPolygon") using
// a rectangle polygon (given by the ordered 3D vertices in "clipRectangle"). The subject polygon and the clip rectangle are in 3D but we assumed that
// they are on a same plane in 3D. The method returns the ordered 3D vertices of the subject polygon clipped using the rectangle polygon.
inline std::vector<reactphysics3d::Vector3> clipPolygonWithRectangleInPlane(const std::vector<reactphysics3d::Vector3>& subjectPolygon, const std::vector<reactphysics3d::Vector3>& clipRectangle) {
decimal const epsilon = 0.1;
assert(clipRectangle.size() == 4);
std::vector<reactphysics3d::Vector3> outputPolygon;
std::vector<reactphysics3d::Vector3> inputPolygon = subjectPolygon;
// For each edge of the clip rectangle
for (unsigned int i=0; i<4; ++i) {
outputPolygon.clear();
// Each edge defines a clip plane. The clip plane is define by a point on this plane (a vertice of the current edge) and
// a plane normal (because we are using a clip rectangle, the plane normal is the next edge of the clip rectangle).
reactphysics3d::Vector3 planeNormal = clipRectangle[(i+2) % 4] - clipRectangle[(i+1) % 4];
reactphysics3d::Vector3 A = clipRectangle[i]; // Segment AB is the current segment of the "clipRectangle"
reactphysics3d::Vector3 B = clipRectangle[(i+1) % 4];
reactphysics3d::Vector3 S = inputPolygon[0];
// For each vertex of the subject polygon
for (unsigned int j=0; j<inputPolygon.size(); ++j) {
reactphysics3d::Vector3 P = inputPolygon[(j+1) % inputPolygon.size()];
// If the point P is inside the clip plane
if (planeNormal.dot(P-A) >= 0.0 - epsilon) {
// If the point S is also inside the clip plane
if (planeNormal.dot(S-A) >= 0.0 - epsilon) {
outputPolygon.push_back(P);
}
else { // If the point S is outside the clip plane
// Compute the intersection point between the segment SP and the clip plane
reactphysics3d::Vector3 intersectPoint = computeLinesIntersection(S, P-S, A, B-A);
outputPolygon.push_back(intersectPoint);
outputPolygon.push_back(P);
}
}
else if (planeNormal.dot(S-A) > 0.0) {
// Compute the intersection point between the segment SP and the clip plane
reactphysics3d::Vector3 intersectPoint = computeLinesIntersection(S, P-S, A, B-A);
outputPolygon.push_back(intersectPoint);
}
S = P;
}
inputPolygon = outputPolygon;
}
// Return the clipped polygon
return outputPolygon;
}
// Compute the intersection point between a line and a plane in 3D space. There must be an intersection, therefore the
// the lineVector must not be orthogonal to the planeNormal.
inline reactphysics3d::Vector3 intersectLineWithPlane(const reactphysics3d::Vector3& linePoint, const reactphysics3d::Vector3& lineVector,
const reactphysics3d::Vector3& planePoint, const reactphysics3d::Vector3& planeNormal) {
assert(!approxEqual(lineVector.dot(planeNormal), 0.0));
// The plane is represented by the equation planeNormal dot X = d where X is a point of the plane
decimal d = planeNormal.dot(planePoint);
// Compute the parameter t
decimal t = (d - planeNormal.dot(linePoint)) / planeNormal.dot(lineVector);
// Compute the intersection point
return linePoint + lineVector * t;
}
} // End of the ReactPhysics3D namespace
#endif #endif

View File

@ -50,6 +50,7 @@ namespace reactphysics3d {
*/ */
template<class T> template<class T>
class MemoryPool { class MemoryPool {
private: private:
// MemoryUnit represents a unit of memory // MemoryUnit represents a unit of memory
@ -63,23 +64,62 @@ class MemoryPool {
struct MemoryBlock* pNext; // Pointer to the next memory block struct MemoryBlock* pNext; // Pointer to the next memory block
}; };
// -------------------- Constants -------------------- //
static const uint NB_OBJECTS_FIRST_BLOCK; // Number of objects allocated in the first block static const uint NB_OBJECTS_FIRST_BLOCK; // Number of objects allocated in the first block
void* pBlocks; // Pointer to the first allocated memory block
MemoryUnit* pAllocatedUnits; // Pointer to the first allocated memory unit // -------------------- Attributes -------------------- //
MemoryUnit* pFreeUnits; // Pointer to the first free memory unit
uint currentNbObjects; // Current number of objects in the pool // Pointer to the first allocated memory block
uint capacity; // Current maximum number of objects that can be allocated in the pool void* mPBlocks;
uint nbObjectsNextBlock; // Number of objects to allocate in the next block
void allocateMemory(); // Allocate more memory (more blocks) when needed // Pointer to the first allocated memory unit
MemoryUnit* mPAllocatedUnits;
// Pointer to the first free memory unit
MemoryUnit* mPFreeUnits;
// Current number of objects in the pool
uint mCurrentNbObjects;
// Current maximum number of objects that can be allocated in the pool
uint mCapacity;
// Number of objects to allocate in the next block
uint mNbObjectsNextBlock;
// -------------------- Methods -------------------- //
// Private copy-constructor
MemoryPool(const MemoryPool& body);
// Private assignment operator
MemoryPool& operator=(const MemoryPool& timer);
// Allocate more memory (more blocks) when needed
void allocateMemory();
public: public:
MemoryPool(uint capacity = 0) throw(std::bad_alloc); // Constructor
~MemoryPool(); // Destructor
uint getCapacity() const; // Return the current maximum number of objects allowed in the pool // -------------------- Methods -------------------- //
uint getCurrentNbObjects() const; // Return the current number of objects in the pool
void* allocateObject(); // Return a pointer to an memory allocated location to store a new object // Constructor
void freeObject(void* pObjectToFree); // Tell the pool that an object doesn't need to be store in the pool anymore MemoryPool(uint capacity = 0) throw(std::bad_alloc);
// Destructor
~MemoryPool();
// Return the current maximum number of objects allowed in the pool
uint getCapacity() const;
// Return the current number of objects in the pool
uint getCurrentNbObjects() const;
// Return a pointer to an memory allocated location to store a new object
void* allocateObject();
// Tell the pool that an object doesn't need to be store in the pool anymore
void freeObject(void* pObjectToFree);
}; };
// static member definition // static member definition
@ -90,11 +130,11 @@ template<class T> const uint MemoryPool<T>::NB_OBJECTS_FIRST_BLOCK = 100;
// a given number of object of the template type T // a given number of object of the template type T
template<class T> template<class T>
MemoryPool<T>::MemoryPool(uint capacity) throw(std::bad_alloc) MemoryPool<T>::MemoryPool(uint capacity) throw(std::bad_alloc)
: currentNbObjects(0), capacity(capacity) { : mCurrentNbObjects(0), mCapacity(capacity) {
pBlocks = 0; mPBlocks = 0;
pAllocatedUnits = 0; mPAllocatedUnits = 0;
pFreeUnits = 0; mPFreeUnits = 0;
nbObjectsNextBlock = (capacity == 0) ? NB_OBJECTS_FIRST_BLOCK : capacity; mNbObjectsNextBlock = (capacity == 0) ? NB_OBJECTS_FIRST_BLOCK : capacity;
// Allocate the first memory block if the capacity is // Allocate the first memory block if the capacity is
// different from zero // different from zero
@ -107,10 +147,10 @@ template<class T>
MemoryPool<T>::~MemoryPool() { MemoryPool<T>::~MemoryPool() {
// Check if we have a memory leak // Check if we have a memory leak
assert(currentNbObjects == 0); assert(mCurrentNbObjects == 0);
// Release all the allocated memory blocks // Release all the allocated memory blocks
MemoryBlock* currentBlock = (MemoryBlock*) pBlocks; MemoryBlock* currentBlock = (MemoryBlock*) mPBlocks;
while(currentBlock) { while(currentBlock) {
MemoryBlock* tempBlock = currentBlock->pNext; MemoryBlock* tempBlock = currentBlock->pNext;
free(currentBlock); free(currentBlock);
@ -125,28 +165,28 @@ template<class T>
void* MemoryPool<T>::allocateObject() { void* MemoryPool<T>::allocateObject() {
// If there is not enough allocated memory in the pool // If there is not enough allocated memory in the pool
if (currentNbObjects == capacity) { if (mCurrentNbObjects == mCapacity) {
// Allocate a new memory block // Allocate a new memory block
allocateMemory(); allocateMemory();
} }
assert(currentNbObjects < capacity); assert(mCurrentNbObjects < mCapacity);
assert(pFreeUnits); assert(mPFreeUnits);
MemoryUnit* currentUnit = pFreeUnits; MemoryUnit* currentUnit = mPFreeUnits;
pFreeUnits = currentUnit->pNext; mPFreeUnits = currentUnit->pNext;
if (pFreeUnits) { if (mPFreeUnits) {
pFreeUnits->pPrevious = 0; mPFreeUnits->pPrevious = 0;
} }
currentUnit->pNext = pAllocatedUnits; currentUnit->pNext = mPAllocatedUnits;
if (pAllocatedUnits) { if (mPAllocatedUnits) {
pAllocatedUnits->pPrevious = currentUnit; mPAllocatedUnits->pPrevious = currentUnit;
} }
pAllocatedUnits = currentUnit; mPAllocatedUnits = currentUnit;
currentNbObjects++; mCurrentNbObjects++;
// Return a pointer to the allocated memory unit // Return a pointer to the allocated memory unit
return (void*)((char*)currentUnit + sizeof(MemoryUnit)); return (void*)((char*)currentUnit + sizeof(MemoryUnit));
@ -164,18 +204,18 @@ void MemoryPool<T>::freeObject(void* pObjectToFree) {
//assert(pBlocks<pObjectToFree && pObjectToFree<(void*)((char*)pBlocks + memorySize)); //assert(pBlocks<pObjectToFree && pObjectToFree<(void*)((char*)pBlocks + memorySize));
MemoryUnit* currentUnit = (MemoryUnit*)((char*)pObjectToFree - sizeof(MemoryUnit)); MemoryUnit* currentUnit = (MemoryUnit*)((char*)pObjectToFree - sizeof(MemoryUnit));
pAllocatedUnits = currentUnit->pNext; mPAllocatedUnits = currentUnit->pNext;
if (pAllocatedUnits) { if (mPAllocatedUnits) {
pAllocatedUnits->pPrevious = 0; mPAllocatedUnits->pPrevious = 0;
} }
currentUnit->pNext = pFreeUnits; currentUnit->pNext = mPFreeUnits;
if (pFreeUnits) { if (mPFreeUnits) {
pFreeUnits->pPrevious = currentUnit; mPFreeUnits->pPrevious = currentUnit;
} }
pFreeUnits = currentUnit; mPFreeUnits = currentUnit;
currentNbObjects--; mCurrentNbObjects--;
} }
// Allocate more memory. This method is called when there are no // Allocate more memory. This method is called when there are no
@ -185,54 +225,55 @@ template<class T>
void MemoryPool<T>::allocateMemory() { void MemoryPool<T>::allocateMemory() {
// Compute the size of the new // Compute the size of the new
size_t sizeBlock = nbObjectsNextBlock * (sizeof(MemoryUnit) + sizeof(T)); size_t sizeBlock = mNbObjectsNextBlock * (sizeof(MemoryUnit) + sizeof(T));
MemoryBlock* tempBlocks = (MemoryBlock*) pBlocks; MemoryBlock* tempBlocks = (MemoryBlock*) mPBlocks;
// Allocate a new memory block // Allocate a new memory block
pBlocks = malloc(sizeBlock); mPBlocks = malloc(sizeBlock);
// Check that the allocation didn't fail // Check that the allocation didn't fail
if (!pBlocks) throw std::bad_alloc(); if (!mPBlocks) throw std::bad_alloc();
MemoryBlock* block = (MemoryBlock*) pBlocks; MemoryBlock* block = (MemoryBlock*) mPBlocks;
block->pNext = tempBlocks; block->pNext = tempBlocks;
// For each allocated memory unit in the new block // For each allocated memory unit in the new block
for (uint i=0; i<nbObjectsNextBlock; i++) { for (uint i=0; i<mNbObjectsNextBlock; i++) {
// Get the adress of a memory unit // Get the adress of a memory unit
MemoryUnit* currentUnit = (MemoryUnit*)( (char*)pBlocks + i * (sizeof(T) + sizeof(MemoryUnit)) ); MemoryUnit* currentUnit = (MemoryUnit*)( (char*)mPBlocks + i *
(sizeof(T) + sizeof(MemoryUnit)) );
currentUnit->pPrevious = 0; currentUnit->pPrevious = 0;
currentUnit->pNext = pFreeUnits; currentUnit->pNext = mPFreeUnits;
if (pFreeUnits) { if (mPFreeUnits) {
pFreeUnits->pPrevious = currentUnit; mPFreeUnits->pPrevious = currentUnit;
} }
pFreeUnits = currentUnit; mPFreeUnits = currentUnit;
} }
// Update the current capacity of the memory pool // Update the current capacity of the memory pool
capacity += nbObjectsNextBlock; mCapacity += mNbObjectsNextBlock;
// The next block will be two times the size of the last // The next block will be two times the size of the last
// allocated memory block // allocated memory block
nbObjectsNextBlock *= 2; mNbObjectsNextBlock *= 2;
} }
// Return the maximum number of objects allowed in the pool // Return the maximum number of objects allowed in the pool
template<class T> template<class T>
uint MemoryPool<T>::getCapacity() const { uint MemoryPool<T>::getCapacity() const {
return capacity; return mCapacity;
} }
// Return the current number of objects in the pool // Return the current number of objects in the pool
template<class T> template<class T>
uint MemoryPool<T>::getCurrentNbObjects() const { uint MemoryPool<T>::getCurrentNbObjects() const {
return currentNbObjects; return mCurrentNbObjects;
} }
} }

View File

@ -51,6 +51,4 @@
// Alias to the ReactPhysics3D namespace // Alias to the ReactPhysics3D namespace
namespace rp3d = reactphysics3d; namespace rp3d = reactphysics3d;
// TODO : Use using namespace std in every possible cpp files to increase readability
#endif #endif