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;
// Constructor
Body::Body(bodyindex id) : id(id) {
Body::Body(bodyindex id) : mID(id) {
}

View File

@ -44,44 +44,69 @@ namespace reactphysics3d {
class Body {
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 :
Body(bodyindex id); // Constructor
virtual ~Body(); // Destructor
bodyindex getID() const; // Return the id of the body
// -------------------- Methods -------------------- //
// Operators
bool operator<(const Body& body2) 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
// Constructor
Body(bodyindex id);
// Destructor
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
inline bodyindex Body::getID() const {
return id;
return mID;
}
// Smaller than operator
inline bool Body::operator<(const Body& body2) const {
return (id < body2.id);
return (mID < body2.mID);
}
// Larger than operator
inline bool Body::operator>(const Body& body2) const {
return (id > body2.id);
return (mID > body2.mID);
}
// Equal operator
inline bool Body::operator==(const Body& body2) const {
return (id == body2.id);
return (mID == body2.mID);
}
// Not equal operator
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;
// Constructor
CollisionBody::CollisionBody(const Transform& transform, CollisionShape *collisionShape, bodyindex id)
: Body(id), collisionShape(collisionShape), transform(transform), isActive(true), hasMoved(false) {
CollisionBody::CollisionBody(const Transform& transform, CollisionShape *collisionShape,
bodyindex id)
: Body(id), mCollisionShape(collisionShape), mTransform(transform),
mIsActive(true), mHasMoved(false) {
assert(collisionShape);
isMotionEnabled = true;
isCollisionEnabled = true;
interpolationFactor = 0.0;
mIsMotionEnabled = true;
mIsCollisionEnabled = true;
mInterpolationFactor = 0.0;
// Initialize the old transform
oldTransform = transform;
mOldTransform = transform;
// 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
CollisionBody::~CollisionBody() {
// Delete the AABB
delete aabb;
delete mAabb;
}

View File

@ -48,127 +48,194 @@ namespace reactphysics3d {
class CollisionBody : public Body {
protected :
CollisionShape* collisionShape; // Collision shape of the body
Transform transform; // Position and orientation of the body
Transform oldTransform; // Last position and orientation of the body
decimal interpolationFactor; // Interpolation factor used for the state interpolation
bool isActive; // True if the body is active (not sleeping because of deactivation)
bool isMotionEnabled; // True if the body is able to move
bool isCollisionEnabled; // True if the body can collide with others bodies
AABB* aabb; // Axis-Aligned Bounding Box for Broad-Phase collision detection
bool hasMoved; // True if the body has moved during the last frame
// -------------------- Attributes -------------------- //
// Collision shape of the body
CollisionShape* mCollisionShape;
// Position and orientation of the body
Transform mTransform;
// 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 :
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
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
void setCollisionShape(CollisionShape* collisionShape); // Set the collision shape
bool getIsActive() const; // Return true if the body is active
void setIsActive(bool isActive); // Set the isActive variable
const Transform& getTransform() const; // Return the current position and orientation
void setTransform(const Transform& transform); // Set the current position and orientation
const AABB* getAABB() const; // Return the AAABB of the body
Transform getInterpolatedTransform() const; // Return the interpolated transform for rendering
void setInterpolationFactor(decimal factor); // Set the interpolation factor of the body
bool getIsMotionEnabled() const; // Return if the rigid body can move
void setIsMotionEnabled(bool isMotionEnabled); // Set the value to true if the body can move
bool getIsCollisionEnabled() const; // Return true if the body can collide with others bodies
void setIsCollisionEnabled(bool isCollisionEnabled); // Set the isCollisionEnabled value
void updateOldTransform(); // Update the old transform with the current one
void updateAABB(); // Update the Axis-Aligned Bounding Box coordinates
// -------------------- Methods -------------------- //
// Constructor
CollisionBody(const Transform& transform, CollisionShape* collisionShape, bodyindex id);
// Destructor
virtual ~CollisionBody();
// Return true if the body has moved during the last frame
bool getHasMoved() const;
// Set the hasMoved variable (true if the body has moved during the last frame)
void setHasMoved(bool hasMoved);
// Return the collision shape
CollisionShape* getCollisionShape() const;
// 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
inline bool CollisionBody::getHasMoved() const {
return hasMoved;
return mHasMoved;
}
// Set the hasMoved variable (true if the body has moved during the last frame)
inline void CollisionBody::setHasMoved(bool hasMoved) {
this->hasMoved = hasMoved;
mHasMoved = hasMoved;
}
// Return the collision shape
inline CollisionShape* CollisionBody::getCollisionShape() const {
assert(collisionShape);
return collisionShape;
assert(mCollisionShape);
return mCollisionShape;
}
// Set the collision shape
inline void CollisionBody::setCollisionShape(CollisionShape* collisionShape) {
assert(collisionShape);
this->collisionShape = collisionShape;
mCollisionShape = collisionShape;
}
// Return true if the body is active
inline bool CollisionBody::getIsActive() const {
return isActive;
return mIsActive;
}
// Set the isActive variable
inline void CollisionBody::setIsActive(bool isActive) {
this->isActive = isActive;
mIsActive = isActive;
}
// Return the interpolated transform for rendering
inline Transform CollisionBody::getInterpolatedTransform() const {
return Transform::interpolateTransforms(oldTransform, transform, interpolationFactor);
return Transform::interpolateTransforms(mOldTransform, mTransform, mInterpolationFactor);
}
// Set the interpolation factor of the body
inline void CollisionBody::setInterpolationFactor(decimal factor) {
// Set the factor
interpolationFactor = factor;
mInterpolationFactor = factor;
}
// Return if the rigid body can move
inline bool CollisionBody::getIsMotionEnabled() const {
return isMotionEnabled;
return mIsMotionEnabled;
}
// Set the value to true if the body can move
inline void CollisionBody::setIsMotionEnabled(bool isMotionEnabled) {
this->isMotionEnabled = isMotionEnabled;
mIsMotionEnabled = isMotionEnabled;
}
// Return the current position and orientation
inline const Transform& CollisionBody::getTransform() const {
return transform;
return mTransform;
}
// Set the current position and orientation
inline void CollisionBody::setTransform(const Transform& transform) {
// Check if the body has moved
if (this->transform != transform) {
hasMoved = true;
if (this->mTransform != transform) {
mHasMoved = true;
}
this->transform = transform;
mTransform = transform;
}
// Return the AAABB of the body
inline const AABB* CollisionBody::getAABB() const {
return aabb;
return mAabb;
}
// Return true if the body can collide with others bodies
inline bool CollisionBody::getIsCollisionEnabled() const {
return isCollisionEnabled;
return mIsCollisionEnabled;
}
// Set the isCollisionEnabled value
inline void CollisionBody::setIsCollisionEnabled(bool isCollisionEnabled) {
this->isCollisionEnabled = isCollisionEnabled;
mIsCollisionEnabled = isCollisionEnabled;
}
// Update the old transform with the current one
// This is used to compute the interpolated position and orientation of the body
inline void CollisionBody::updateOldTransform() {
oldTransform = transform;
mOldTransform = mTransform;
}
// 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
// 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;
// Constructor
RigidBody::RigidBody(const Transform& transform, decimal mass, const Matrix3x3& inertiaTensorLocal, CollisionShape *collisionShape, bodyindex id)
: CollisionBody(transform, collisionShape, id), inertiaTensorLocal(inertiaTensorLocal),
mass(mass), inertiaTensorLocalInverse(inertiaTensorLocal.getInverse()), massInverse(1.0/mass) {
RigidBody::RigidBody(const Transform& transform, decimal mass, const Matrix3x3& inertiaTensorLocal,
CollisionShape *collisionShape, bodyindex id)
: 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
aabb->setBodyPointer(this);
mAabb->setBodyPointer(this);
assert(collisionShape);
assert(aabb);
assert(mAabb);
}
// Destructor

View File

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

View File

@ -38,28 +38,49 @@ namespace reactphysics3d {
struct BroadPhasePair {
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
~BroadPhasePair(); // Destructor
// -------------------- Attributes -------------------- //
bodyindexpair getBodiesIndexPair() const; // Return the pair of bodies index
// Pointer to the first body
CollisionBody* body1;
// Operators
bool operator<(const BroadPhasePair& broadPhasePair2) 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
// Pointer to the second body
CollisionBody* body2;
// Previous cached separating axis
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
inline bodyindexpair BroadPhasePair::getBodiesIndexPair() const {
// Construct the pair of body index
bodyindexpair indexPair = body1->getID() < body2->getID() ? std::make_pair(body1->getID(), body2->getID()) :
std::make_pair(body2->getID(), body1->getID());
bodyindexpair indexPair = body1->getID() < body2->getID() ?
std::make_pair(body1->getID(), body2->getID()) :
std::make_pair(body2->getID(), body1->getID());
assert(indexPair.first != indexPair.second);
return indexPair;
}

View File

@ -46,19 +46,19 @@ using namespace std;
// Constructor
CollisionDetection::CollisionDetection(CollisionWorld* world)
: world(world), narrowPhaseGJKAlgorithm(memoryPoolContactInfos),
narrowPhaseSphereVsSphereAlgorithm(memoryPoolContactInfos) {
: mWorld(world), mNarrowPhaseGJKAlgorithm(mMemoryPoolContactInfos),
mNarrowPhaseSphereVsSphereAlgorithm(mMemoryPoolContactInfos) {
// Create the broad-phase algorithm that will be used (Sweep and Prune with AABB)
broadPhaseAlgorithm = new SweepAndPruneAlgorithm(*this);
assert(broadPhaseAlgorithm);
mBroadPhaseAlgorithm = new SweepAndPruneAlgorithm(*this);
assert(mBroadPhaseAlgorithm);
}
// Destructor
CollisionDetection::~CollisionDetection() {
// Delete the broad-phase algorithm
delete broadPhaseAlgorithm;
delete mBroadPhaseAlgorithm;
}
// Compute the collision detection
@ -90,13 +90,13 @@ bool CollisionDetection::computeCollisionDetection() {
void CollisionDetection::computeBroadPhase() {
// 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 ((*it)->getHasMoved()) {
// 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;
// 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;
BroadPhasePair* pair = (*it).second;
@ -117,7 +117,7 @@ bool CollisionDetection::computeNarrowPhase() {
CollisionBody* const body2 = pair->body2;
// 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
NarrowPhaseAlgorithm& narrowPhaseAlgorithm = SelectNarrowPhaseAlgorithm(body1->getCollisionShape(), body2->getCollisionShape());
@ -132,11 +132,11 @@ bool CollisionDetection::computeNarrowPhase() {
collisionExists = true;
// 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
contactInfo->ContactInfo::~ContactInfo();
memoryPoolContactInfos.freeObject(contactInfo);
mMemoryPoolContactInfos.freeObject(contactInfo);
}
}
@ -151,14 +151,14 @@ void CollisionDetection::broadPhaseNotifyAddedOverlappingPair(BodyPair* addedPai
bodyindexpair indexPair = addedPair->getBodiesIndexPair();
// 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)
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);
// 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
@ -168,14 +168,14 @@ void CollisionDetection::broadPhaseNotifyRemovedOverlappingPair(BodyPair* remove
bodyindexpair indexPair = removedPair->getBodiesIndexPair();
// Get the broad-phase pair
BroadPhasePair* broadPhasePair = overlappingPairs[indexPair];
BroadPhasePair* broadPhasePair = mOverlappingPairs[indexPair];
assert(broadPhasePair);
// Notify the world about the removed broad-phase pair
world->notifyRemovedOverlappingPair(broadPhasePair);
mWorld->notifyRemovedOverlappingPair(broadPhasePair);
// Remove the overlapping pair from the memory pool
broadPhasePair->BroadPhasePair::~BroadPhasePair();
memoryPoolOverlappingPairs.freeObject(broadPhasePair);
overlappingPairs.erase(indexPair);
mMemoryPoolBroadPhasePairs.freeObject(broadPhasePair);
mOverlappingPairs.erase(indexPair);
}

View File

@ -59,39 +59,84 @@ class CollisionWorld;
class CollisionDetection {
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
bool computeNarrowPhase(); // Compute the narrow-phase collision detection
// -------------------- Attributes -------------------- //
// 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,
CollisionShape* collisionShape2); // Select the narrow phase algorithm to use given two collision shapes
CollisionShape* collisionShape2);
public :
CollisionDetection(CollisionWorld* world); // Constructor
~CollisionDetection(); // Destructor
void addBody(CollisionBody* body); // Add a body to the collision detection
void removeBody(CollisionBody* body); // Remove a body from the collision detection
bool computeCollisionDetection(); // Compute the collision detection
void broadPhaseNotifyAddedOverlappingPair(BodyPair* pair); // Allow the broadphase to notify the collision detection about a new overlapping pair
void broadPhaseNotifyRemovedOverlappingPair(BodyPair* pair); // Allow the broadphase to notify the collision detection about a removed overlapping pair
// -------------------- Methods -------------------- //
// Constructor
CollisionDetection(CollisionWorld* world);
// Destructor
~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
inline NarrowPhaseAlgorithm& CollisionDetection::SelectNarrowPhaseAlgorithm(CollisionShape* collisionShape1, CollisionShape* collisionShape2) {
inline NarrowPhaseAlgorithm& CollisionDetection::SelectNarrowPhaseAlgorithm(
CollisionShape* collisionShape1, CollisionShape* collisionShape2) {
// Sphere vs Sphere algorithm
if (collisionShape1->getType() == SPHERE && collisionShape2->getType() == SPHERE) {
return narrowPhaseSphereVsSphereAlgorithm;
return mNarrowPhaseSphereVsSphereAlgorithm;
}
else { // GJK algorithm
return narrowPhaseGJKAlgorithm;
return mNarrowPhaseGJKAlgorithm;
}
}
@ -99,14 +144,14 @@ inline NarrowPhaseAlgorithm& CollisionDetection::SelectNarrowPhaseAlgorithm(Coll
inline void CollisionDetection::addBody(CollisionBody* body) {
// Add the body to the broad-phase
broadPhaseAlgorithm->addObject(body, *(body->getAABB()));
mBroadPhaseAlgorithm->addObject(body, *(body->getAABB()));
}
// Remove a body from the collision detection
inline void CollisionDetection::removeBody(CollisionBody* body) {
// Remove the body from the broad-phase
broadPhaseAlgorithm->removeObject(body);
mBroadPhaseAlgorithm->removeObject(body);
}
} // End of the ReactPhysics3D namespace

View File

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

View File

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

View File

@ -51,39 +51,68 @@ class CollisionDetection;
--------------------------------------------------------------------
*/
class BroadPhaseAlgorithm {
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 :
BroadPhaseAlgorithm(CollisionDetection& collisionDetection); // Constructor
virtual ~BroadPhaseAlgorithm(); // Destructor
// -------------------- Methods -------------------- //
// Constructor
BroadPhaseAlgorithm(CollisionDetection& collisionDetection);
// Destructor
virtual ~BroadPhaseAlgorithm();
// TODO : DELETE THIS METHOD
uint getNbOverlappingPairs() const;
virtual void addObject(CollisionBody* body, const AABB& aabb)=0; // 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 updateObject(CollisionBody* body, const AABB& aabb)=0; // Notify the broad-phase that the AABB of an object has changed
// Notify the broad-phase about a new object in the world
virtual void addObject(CollisionBody* body, const AABB& aabb)=0;
BodyPair* beginOverlappingPairsPointer() const; // Return a pointer to the first active pair (used to iterate over the active pairs)
BodyPair* endOverlappingPairsPointer() const; // Return a pointer to the last active pair (used to iterate over the active pairs)
// Notify the broad-phase about an object that has been removed from the world
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
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)
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)
inline BodyPair* BroadPhaseAlgorithm::endOverlappingPairsPointer() const {
return pairManager.endOverlappingPairsPointer();
return mPairManager.endOverlappingPairsPointer();
}
} // End of reactphysics3d namespace

View File

@ -43,16 +43,40 @@ namespace reactphysics3d {
--------------------------------------------------------------------
*/
class NoBroadPhaseAlgorithm : public BroadPhaseAlgorithm {
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 :
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
virtual void removeObject(CollisionBody* body); // Notify the broad-phase about an 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
// Notify the broad-phase about a new object in the world
virtual void addObject(CollisionBody* body, const AABB& aabb);
// 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;
// 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
pairManager.addPair(*it, body);
mPairManager.addPair(*it, body);
}
// 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
inline void NoBroadPhaseAlgorithm::removeObject(CollisionBody* body) {
// 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()) {
// 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
bodies.erase(body);
mBodies.erase(body);
}
// 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();
// Constructor of PairManager
PairManager::PairManager(CollisionDetection& collisionDetection) : collisionDetection(collisionDetection) {
hashTable = 0;
overlappingPairs = 0;
offsetNextPair = 0;
nbOverlappingPairs = 0;
hashMask = 0;
nbElementsHashTable = 0;
PairManager::PairManager(CollisionDetection& collisionDetection)
: mCollisionDetection(collisionDetection) {
mHashTable = 0;
mOverlappingPairs = 0;
mOffsetNextPair = 0;
mNbOverlappingPairs = 0;
mHashMask = 0;
mNbElementsHashTable = 0;
}
// Destructor of PairManager
PairManager::~PairManager() {
// Release the allocated memory
free(offsetNextPair);
free(overlappingPairs);
free(hashTable);
free(mOffsetNextPair);
free(mOverlappingPairs);
free(mHashTable);
}
// 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();
// 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.
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 (nbOverlappingPairs >= nbElementsHashTable) {
if (mNbOverlappingPairs >= mNbElementsHashTable) {
// 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
hashMask = nbElementsHashTable - 1;
mHashMask = mNbElementsHashTable - 1;
// Reallocate more pairs
reallocatePairs();
// 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
BodyPair* newPair = &overlappingPairs[nbOverlappingPairs];
BodyPair* newPair = &mOverlappingPairs[mNbOverlappingPairs];
newPair->body1 = body1;
newPair->body2 = body2;
// Put the new pair as the initial pair with this hash value
offsetNextPair[nbOverlappingPairs] = hashTable[hashValue];
hashTable[hashValue] = nbOverlappingPairs++;
mOffsetNextPair[mNbOverlappingPairs] = mHashTable[hashValue];
mHashTable[hashValue] = mNbOverlappingPairs++;
// Notify the collision detection about this new overlapping pair
collisionDetection.broadPhaseNotifyAddedOverlappingPair(newPair);
mCollisionDetection.broadPhaseNotifyAddedOverlappingPair(newPair);
// Return a pointer to the new created pair
return newPair;
@ -116,7 +117,7 @@ bool PairManager::removePair(bodyindex id1, bodyindex id2) {
sortIDs(id1, id2);
// 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
BodyPair* pair = findPairWithHashValue(id1, id2, hashValue);
@ -130,7 +131,7 @@ bool PairManager::removePair(bodyindex id1, bodyindex id2) {
assert(pair->body2->getID() == id2);
// Notify the collision detection about this removed overlapping pair
collisionDetection.broadPhaseNotifyRemovedOverlappingPair(pair);
mCollisionDetection.broadPhaseNotifyRemovedOverlappingPair(pair);
// Remove the pair from the set of overlapping pairs
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
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
// the corresponding hash value
bodyindex offset = hashTable[hashValue];
bodyindex offset = mHashTable[hashValue];
assert(offset != INVALID_INDEX);
// Look for the pair in the set of overlapping pairs
bodyindex previousPair = INVALID_INDEX;
while(offset != indexPair) {
previousPair = offset;
offset = offsetNextPair[offset];
offset = mOffsetNextPair[offset];
}
// 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) {
// Replace the pair to remove in the
// hash table by the next one
hashTable[hashValue] = offsetNextPair[indexPair];
mHashTable[hashValue] = mOffsetNextPair[indexPair];
}
else { // If the pair was not the first one
// Replace the pair to remove in the
// hash table by the next one
assert(offsetNextPair[previousPair] == indexPair);
offsetNextPair[previousPair] = offsetNextPair[indexPair];
assert(mOffsetNextPair[previousPair] == 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 (indexPair == indexLastPair) {
// We simply decrease the number of overlapping pairs
nbOverlappingPairs--;
mNbOverlappingPairs--;
}
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
// Get the last pair
const BodyPair* lastPair = &overlappingPairs[indexLastPair];
const uint lastPairHashValue = computeHashBodies(lastPair->body1->getID(), lastPair->body2->getID()) & hashMask;
const BodyPair* lastPair = &mOverlappingPairs[indexLastPair];
const uint lastPairHashValue = computeHashBodies(lastPair->body1->getID(),
lastPair->body2->getID()) & mHashMask;
// Compute the initial offset of the last pair
bodyindex offset = hashTable[lastPairHashValue];
bodyindex offset = mHashTable[lastPairHashValue];
assert(offset != INVALID_INDEX);
// 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;
while(offset != indexLastPair) {
previous = offset;
offset = offsetNextPair[offset];
offset = mOffsetNextPair[offset];
}
// If the last pair is not the first one with this hash value
if (previous != INVALID_INDEX) {
// Remove the offset of the last pair in the "nextOffset" array
assert(offsetNextPair[previous] == indexLastPair);
offsetNextPair[previous] = offsetNextPair[indexLastPair];
assert(mOffsetNextPair[previous] == indexLastPair);
mOffsetNextPair[previous] = mOffsetNextPair[indexLastPair];
}
else { // If the last pair is the first offset with this hash value
// 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
// the overlapping pairs array
overlappingPairs[indexPair] = overlappingPairs[indexLastPair];
offsetNextPair[indexPair] = hashTable[lastPairHashValue];
hashTable[lastPairHashValue] = indexPair;
mOverlappingPairs[indexPair] = mOverlappingPairs[indexLastPair];
mOffsetNextPair[indexPair] = mHashTable[lastPairHashValue];
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 {
// Look for the pair in the set of overlapping pairs
bodyindex offset = hashTable[hashValue];
while (offset != INVALID_INDEX && isDifferentPair(overlappingPairs[offset], id1, id2)) {
offset = offsetNextPair[offset];
bodyindex offset = mHashTable[hashValue];
while (offset != INVALID_INDEX && isDifferentPair(mOverlappingPairs[offset], id1, id2)) {
offset = mOffsetNextPair[offset];
}
// 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;
}
assert(offset < nbOverlappingPairs);
assert(offset < mNbOverlappingPairs);
// The pair has been found in the set of overlapping pairs, then
// we return a pointer to it
return &overlappingPairs[offset];
return &mOverlappingPairs[offset];
}
// Reallocate more pairs
void PairManager::reallocatePairs() {
// Reallocate the hash table and initialize it
free(hashTable);
hashTable = (bodyindex*) malloc(nbElementsHashTable * sizeof(bodyindex));
assert(hashTable);
for (bodyindex i=0; i<nbElementsHashTable; i++) {
hashTable[i] = INVALID_INDEX;
free(mHashTable);
mHashTable = (bodyindex*) malloc(mNbElementsHashTable * sizeof(bodyindex));
assert(mHashTable);
for (bodyindex i=0; i<mNbElementsHashTable; i++) {
mHashTable[i] = INVALID_INDEX;
}
// Reallocate the overlapping pairs
BodyPair* newOverlappingPairs = (BodyPair*) malloc(nbElementsHashTable * sizeof(BodyPair));
bodyindex* newOffsetNextPair = (bodyindex*) malloc(nbElementsHashTable * sizeof(bodyindex));
BodyPair* newOverlappingPairs = (BodyPair*) malloc(mNbElementsHashTable * sizeof(BodyPair));
bodyindex* newOffsetNextPair = (bodyindex*) malloc(mNbElementsHashTable * sizeof(bodyindex));
assert(newOverlappingPairs);
assert(newOffsetNextPair);
// If there is already some overlapping pairs
if (nbOverlappingPairs) {
if (mNbOverlappingPairs) {
// 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
for (bodyindex i=0; i<nbOverlappingPairs; i++) {
const uint newHashValue = computeHashBodies(overlappingPairs[i].body1->getID(), overlappingPairs[i].body2->getID()) & hashMask;
newOffsetNextPair[i] = hashTable[newHashValue];
hashTable[newHashValue] = i;
for (bodyindex i=0; i<mNbOverlappingPairs; i++) {
const uint newHashValue = computeHashBodies(mOverlappingPairs[i].body1->getID(),
mOverlappingPairs[i].body2->getID()) & mHashMask;
newOffsetNextPair[i] = mHashTable[newHashValue];
mHashTable[newHashValue] = i;
}
// Delete the old pairs
free(offsetNextPair);
free(overlappingPairs);
free(mOffsetNextPair);
free(mOverlappingPairs);
// Replace by the new data
overlappingPairs = newOverlappingPairs;
offsetNextPair = newOffsetNextPair;
mOverlappingPairs = newOverlappingPairs;
mOffsetNextPair = newOffsetNextPair;
}

View File

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

View File

@ -47,20 +47,20 @@ AABBInt::AABBInt(const AABB& aabb) {
// Constructor
SweepAndPruneAlgorithm::SweepAndPruneAlgorithm(CollisionDetection& collisionDetection)
:BroadPhaseAlgorithm(collisionDetection) {
boxes = 0;
endPoints[0] = 0;
endPoints[1] = 0;
endPoints[2] = 0;
nbBoxes = 0;
nbMaxBoxes = 0;
mBoxes = 0;
mEndPoints[0] = 0;
mEndPoints[1] = 0;
mEndPoints[2] = 0;
mNbBoxes = 0;
mNbMaxBoxes = 0;
}
// Destructor
SweepAndPruneAlgorithm::~SweepAndPruneAlgorithm() {
delete[] boxes;
delete[] endPoints[0];
delete[] endPoints[1];
delete[] endPoints[2];
delete[] mBoxes;
delete[] mEndPoints[0];
delete[] mEndPoints[1];
delete[] mEndPoints[2];
}
// 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
// there is a bucket in the middle of the array that doesn't
// contain a box anymore because it has been removed)
if (!freeBoxIndices.empty()) {
boxIndex = freeBoxIndices.back();
freeBoxIndices.pop_back();
if (!mFreeBoxIndices.empty()) {
boxIndex = mFreeBoxIndices.back();
mFreeBoxIndices.pop_back();
}
else {
// If the array boxes and end-points arrays are full
if (nbBoxes == nbMaxBoxes) {
if (mNbBoxes == mNbMaxBoxes) {
// Resize the arrays to make them larger
resizeArrays();
}
boxIndex = nbBoxes;
boxIndex = mNbBoxes;
}
// Move the maximum limit end-point two elements further
// at the end-points array in all three axis
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++) {
EndPoint* maxLimitEndPoint = &endPoints[axis][indexLimitEndPoint];
assert(endPoints[axis][0].boxID == INVALID_INDEX && endPoints[axis][0].isMin == true);
EndPoint* maxLimitEndPoint = &mEndPoints[axis][indexLimitEndPoint];
assert(mEndPoints[axis][0].boxID == INVALID_INDEX && mEndPoints[axis][0].isMin == true);
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);
}
// Create a new box
BoxAABB* box = &boxes[boxIndex];
BoxAABB* box = &mBoxes[boxIndex];
box->body = body;
const uint minEndPointValue = encodeFloatIntoInteger(DECIMAL_LARGEST - 2.0);
const uint maxEndPointValue = encodeFloatIntoInteger(DECIMAL_LARGEST - 1.0);
for (uint axis=0; axis<3; axis++) {
box->min[axis] = indexLimitEndPoint;
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);
EndPoint* maximumEndPoint = &endPoints[axis][box->max[axis]];
EndPoint* maximumEndPoint = &mEndPoints[axis][box->max[axis]];
maximumEndPoint->setValues(body->getID(), false, maxEndPointValue);
}
// 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
// correct position in the array. This will also create the overlapping
@ -134,14 +134,14 @@ void SweepAndPruneAlgorithm::removeObject(CollisionBody* body) {
updateObject(body, aabb);
// Get the corresponding box
bodyindex boxIndex = mapBodyToBoxIndex[body];
BoxAABB* box = &boxes[boxIndex];
bodyindex boxIndex = mMapBodyToBoxIndex[body];
BoxAABB* box = &mBoxes[boxIndex];
// Add the box index into the list of free indices
freeBoxIndices.push_back(boxIndex);
mFreeBoxIndices.push_back(boxIndex);
mapBodyToBoxIndex.erase(body);
nbBoxes--;
mMapBodyToBoxIndex.erase(body);
mNbBoxes--;
}
// 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);
// Get the corresponding box
bodyindex boxIndex = mapBodyToBoxIndex[body];
BoxAABB* box = &boxes[boxIndex];
bodyindex boxIndex = mMapBodyToBoxIndex[body];
BoxAABB* box = &mBoxes[boxIndex];
// Current 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;
// Get the starting end-point of the current axis
EndPoint* startEndPointsCurrentAxis = endPoints[axis];
EndPoint* startEndPointsCurrentAxis = mEndPoints[axis];
// -------- Update the minimum end-point ------------//
@ -184,7 +184,7 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
const luint savedEndPointIndex = indexEndPoint;
while ((--currentMinEndPoint)->value > limit) {
BoxAABB* id1 = &boxes[currentMinEndPoint->boxID];
BoxAABB* id1 = &mBoxes[currentMinEndPoint->boxID];
const bool isMin = currentMinEndPoint->isMin;
// If it's a maximum end-point
@ -198,7 +198,7 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
testIntersect1DSortedAABBs(*id1, aabbInt, startEndPointsCurrentAxis, axis)) {
// 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
if (savedEndPointIndex != indexEndPoint) {
if (savedEndPoint.isMin) {
boxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
mBoxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
}
else {
boxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
mBoxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
}
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
// end-point and the new position of the minimum end-point
while ((++currentMinEndPoint)->value < limit) {
BoxAABB* id1 = &boxes[currentMinEndPoint->boxID];
BoxAABB* id1 = &mBoxes[currentMinEndPoint->boxID];
const bool isMin = currentMinEndPoint->isMin;
// 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)) {
// 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
if (savedEndPointIndex != indexEndPoint) {
if (savedEndPoint.isMin) {
boxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
mBoxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
}
else {
boxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
mBoxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
}
startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint;
@ -295,7 +295,7 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
while ((++currentMaxEndPoint)->value < limit) {
// Get the next end-point
BoxAABB* id1 = &boxes[currentMaxEndPoint->boxID];
BoxAABB* id1 = &mBoxes[currentMaxEndPoint->boxID];
const bool isMin = currentMaxEndPoint->isMin;
// If it's a maximum end-point
@ -309,7 +309,7 @@ void SweepAndPruneAlgorithm::updateObject(CollisionBody* body, const AABB& aabb)
testIntersect1DSortedAABBs(*id1, aabbInt, startEndPointsCurrentAxis,axis)) {
// 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
if (savedEndPointIndex != indexEndPoint) {
if (savedEndPoint.isMin) {
boxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
mBoxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
}
else {
boxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
mBoxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
}
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
// end-point and the new position of the maximum end-point
while ((--currentMaxEndPoint)->value > limit) {
BoxAABB* id1 = &boxes[currentMaxEndPoint->boxID];
BoxAABB* id1 = &mBoxes[currentMaxEndPoint->boxID];
const bool isMin = currentMaxEndPoint->isMin;
// 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)) {
// 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
if (savedEndPointIndex != indexEndPoint) {
if (savedEndPoint.isMin) {
boxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
mBoxes[savedEndPoint.boxID].min[axis] = indexEndPoint;
}
else {
boxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
mBoxes[savedEndPoint.boxID].max[axis] = indexEndPoint;
}
startEndPointsCurrentAxis[indexEndPoint] = savedEndPoint;
@ -389,8 +389,8 @@ void SweepAndPruneAlgorithm::resizeArrays() {
// New number of boxes in the array
const luint nbSentinels = 2;
const luint newNbMaxBoxes = nbMaxBoxes ? 2 * nbMaxBoxes : 100;
const luint nbEndPoints = nbBoxes * 2 + nbSentinels;
const luint newNbMaxBoxes = mNbMaxBoxes ? 2 * mNbMaxBoxes : 100;
const luint nbEndPoints = mNbBoxes * 2 + nbSentinels;
const luint newNbEndPoints = newNbMaxBoxes * 2 + nbSentinels;
// Allocate memory for the new boxes and end-points arrays
@ -405,14 +405,14 @@ void SweepAndPruneAlgorithm::resizeArrays() {
assert(newEndPointsZArray);
// If the arrays were not empty before
if (nbBoxes > 0) {
if (mNbBoxes > 0) {
// 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;
memcpy(newEndPointsXArray, endPoints[0], nbBytesNewEndPoints);
memcpy(newEndPointsYArray, endPoints[1], nbBytesNewEndPoints);
memcpy(newEndPointsZArray, endPoints[2], nbBytesNewEndPoints);
memcpy(newEndPointsXArray, mEndPoints[0], nbBytesNewEndPoints);
memcpy(newEndPointsYArray, mEndPoints[1], nbBytesNewEndPoints);
memcpy(newEndPointsZArray, mEndPoints[2], nbBytesNewEndPoints);
}
else { // If the arrays were empty
@ -428,16 +428,16 @@ void SweepAndPruneAlgorithm::resizeArrays() {
}
// Delete the old arrays
delete[] boxes;
delete[] endPoints[0];
delete[] endPoints[1];
delete[] endPoints[2];
delete[] mBoxes;
delete[] mEndPoints[0];
delete[] mEndPoints[1];
delete[] mEndPoints[2];
// Assign the pointer to the new arrays
boxes = newBoxesArray;
endPoints[0] = newEndPointsXArray;
endPoints[1] = newEndPointsYArray;
endPoints[2] = newEndPointsZArray;
mBoxes = newBoxesArray;
mEndPoints[0] = newEndPointsXArray;
mEndPoints[1] = newEndPointsYArray;
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
// on one of the three x,y or z axis
struct EndPoint {
public:
// TODO : Use uint here
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
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
inline void EndPoint::setValues(bodyindex boxID, bool isMin, uint value) {
this->boxID = boxID;
this->isMin = isMin;
this->value = value;
}
// Set the values of the endpoint
void setValues(bodyindex boxID, bool isMin, uint value) {
this->boxID = boxID;
this->isMin = isMin;
this->value = value;
}
};
// Structure BoxAABB that represents an AABB in the
// Sweep-And-Prune algorithm
struct BoxAABB {
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
};
// Structure AABBInt
// Axis-Aligned Bounding box with integer coordinates
struct AABBInt {
public:
uint min[3]; // Minimum 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 {
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
EndPoint* endPoints[3]; // Array of end-points on the three axis
bodyindex nbBoxes; // Number of AABB boxes in the broad-phase
bodyindex nbMaxBoxes; // Maximum number of boxes in the boxes array
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
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
// -------------------- Methods -------------------- //
// Private copy-constructor
SweepAndPruneAlgorithm(const SweepAndPruneAlgorithm& algorithm);
// Private assignment operator
SweepAndPruneAlgorithm& operator=(const SweepAndPruneAlgorithm& algorithm);
// 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,
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,
luint axis1, uint axis2) const; // Check for 2D box intersection
luint axis1, uint axis2) const;
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
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
// -------------------- Methods -------------------- //
// 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
@ -135,8 +179,10 @@ inline uint encodeFloatIntoInteger(float number) {
// 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
// minimum of box1 cannot be larger that the maximum of box2 on the axis.
inline bool SweepAndPruneAlgorithm::testIntersect1DSortedAABBs(const BoxAABB& box1, const AABBInt& box2,
const EndPoint* const endPointsArray, uint axis) const {
inline bool SweepAndPruneAlgorithm::testIntersect1DSortedAABBs(const BoxAABB& box1,
const AABBInt& box2,
const EndPoint* const endPointsArray,
uint axis) const {
return !(endPointsArray[box1.max[axis]].value < box2.min[axis]);
}

View File

@ -33,7 +33,7 @@ using namespace reactphysics3d;
// Constructor
EPAAlgorithm::EPAAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos)
: memoryPoolContactInfos(memoryPoolContactInfos) {
: mMemoryPoolContactInfos(memoryPoolContactInfos) {
}
@ -45,7 +45,8 @@ EPAAlgorithm::~EPAAlgorithm() {
// 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
// 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
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
// GJK algorithm. The EPA Algorithm will extend this simplex polytope to find
// the correct penetration depth
bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, const CollisionShape* collisionShape1, const Transform& transform1,
const CollisionShape* collisionShape2, const Transform& transform2,
bool EPAAlgorithm::computePenetrationDepthAndContactPoints(const Simplex& simplex,
const CollisionShape* collisionShape1,
const Transform& transform1,
const CollisionShape* collisionShape2,
const Transform& transform2,
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;
// 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();
// 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();
// Get the simplex computed previously by the GJK algorithm
unsigned int nbVertices = simplex.getSimplex(suppPointsA, suppPointsB, points);
@ -113,8 +122,9 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
// The EPA algorithm.
switch(nbVertices) {
case 1:
// Only one point in the simplex (which should be the origin). We have a touching contact
// with zero penetration depth. We drop that kind of contact. Therefore, we return false
// Only one point in the simplex (which should be the origin).
// We have a touching contact with zero penetration depth.
// We drop that kind of contact. Therefore, we return false
return false;
case 2: {
@ -149,17 +159,23 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
// Compute the support point in the direction of v1
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];
// Compute the support point in the direction of v2
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];
// Compute the support point in the direction of v3
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];
// 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];
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
suppPointsA[0] = suppPointsA[4];
suppPointsB[0] = suppPointsB[4];
@ -209,7 +226,8 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
// If the constructed tetrahedron is not correct
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;
}
@ -254,10 +272,13 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
// Compute the two new vertices to obtain a hexahedron
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];
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];
// Construct the triangle faces
@ -314,7 +335,7 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
triangle = triangleHeap[0];
// 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--;
// If the candidate face in the heap is not obsolete
@ -325,9 +346,13 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
break;
}
// Compute the support point of the Minkowski difference (A-B) in the closest point direction
suppPointsA[nbVertices] = collisionShape1->getLocalSupportPoint(triangle->getClosestPoint(), OBJECT_MARGIN);
suppPointsB[nbVertices] = body2Tobody1 * collisionShape2->getLocalSupportPoint(rotateToBody2 * (-triangle->getClosestPoint()), OBJECT_MARGIN);
// Compute the support point of the Minkowski
// difference (A-B) in the closest point direction
suppPointsA[nbVertices] = collisionShape1->getLocalSupportPoint(
triangle->getClosestPoint(), OBJECT_MARGIN);
suppPointsB[nbVertices] = body2Tobody1 * collisionShape2->getLocalSupportPoint(
rotateToBody2 * (-triangle->getClosestPoint()),
OBJECT_MARGIN);
points[nbVertices] = suppPointsA[nbVertices] - suppPointsB[nbVertices];
int indexNewVertex = nbVertices;
@ -377,7 +402,9 @@ bool EPAAlgorithm::computePenetrationDepthAndContactPoints(Simplex simplex, cons
assert(penetrationDepth > 0.0);
// 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;
}

View File

@ -72,35 +72,67 @@ class TriangleComparison {
-------------------------------------------------------------------
*/
class EPAAlgorithm {
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,
uint& nbTriangles, decimal upperBoundSquarePenDepth); // Add a triangle face in the candidate triangle heap
// -------------------- Methods -------------------- //
// 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,
const Vector3& p3, const Vector3& p4) const; // Decide if the origin is in the tetrahedron
const Vector3& p3, const Vector3& p4) const;
public:
EPAAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos); // Constructor
~EPAAlgorithm(); // Destructor
bool computePenetrationDepthAndContactPoints(Simplex simplex, const CollisionShape* collisionShape1, const Transform& transform1,
const CollisionShape* collisionShape2, const Transform& transform2,
Vector3& v, ContactInfo*& contactInfo); // Compute the penetration depth with EPA algorithm
// -------------------- Methods -------------------- //
// 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
inline void EPAAlgorithm::addFaceCandidate(TriangleEPA* triangle, TriangleEPA** heap,
uint& nbTriangles, decimal upperBoundSquarePenDepth) {
// If the closest point of the affine hull of triangle points is internal to the triangle and
// if the distance of the closest point from the origin is at most the penetration depth upper bound
if (triangle->isClosestPointInternalToTriangle() && triangle->getDistSquare() <= upperBoundSquarePenDepth) {
// If the closest point of the affine hull of triangle
// points is internal to the triangle and if the distance
// 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
heap[nbTriangles] = triangle;
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
EdgeEPA::EdgeEPA(TriangleEPA* ownerTriangle, int index)
: ownerTriangle(ownerTriangle), index(index) {
: mOwnerTriangle(ownerTriangle), mIndex(index) {
assert(index >= 0 && index < 3);
}
// Copy-constructor
EdgeEPA::EdgeEPA(const EdgeEPA& edge) {
mOwnerTriangle = edge.mOwnerTriangle;
mIndex = edge.mIndex;
}
// Destructor
EdgeEPA::~EdgeEPA() {
@ -51,21 +57,24 @@ EdgeEPA::~EdgeEPA() {
// Return the index of the source vertex of the edge (vertex starting the edge)
uint EdgeEPA::getSourceVertexIndex() const {
return (*ownerTriangle)[index];
return (*mOwnerTriangle)[mIndex];
}
// Return the index of the target vertex of the edge (vertex ending the edge)
uint EdgeEPA::getTargetVertexIndex() const {
return (*ownerTriangle)[indexOfNextCounterClockwiseEdge(index)];
return (*mOwnerTriangle)[indexOfNextCounterClockwiseEdge(mIndex)];
}
// 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 (!ownerTriangle->getIsObsolete()) {
if (!mOwnerTriangle->getIsObsolete()) {
// If the triangle of this edge is not visible from the given point
if (!ownerTriangle->isVisibleFromVertex(vertices, indexNewVertex)) {
TriangleEPA* triangle = triangleStore.newTriangle(vertices, indexNewVertex, getTargetVertexIndex(), getSourceVertexIndex());
if (!mOwnerTriangle->isVisibleFromVertex(vertices, indexNewVertex)) {
TriangleEPA* triangle = triangleStore.newTriangle(vertices, indexNewVertex,
getTargetVertexIndex(),
getSourceVertexIndex());
// If the triangle has been created
if (triangle) {
@ -77,14 +86,19 @@ bool EdgeEPA::computeSilhouette(const Vector3* vertices, uint indexNewVertex, Tr
}
else {
// The current triangle is visible and therefore obsolete
ownerTriangle->setIsObsolete(true);
mOwnerTriangle->setIsObsolete(true);
int backup = triangleStore.getNbTriangles();
if(!ownerTriangle->getAdjacentEdge(indexOfNextCounterClockwiseEdge(this->index)).computeSilhouette(vertices, indexNewVertex, triangleStore)) {
ownerTriangle->setIsObsolete(false);
if(!mOwnerTriangle->getAdjacentEdge(indexOfNextCounterClockwiseEdge(
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 (triangle) {
@ -94,12 +108,17 @@ bool EdgeEPA::computeSilhouette(const Vector3* vertices, uint indexNewVertex, Tr
return false;
}
else if (!ownerTriangle->getAdjacentEdge(indexOfPreviousCounterClockwiseEdge(this->index)).computeSilhouette(vertices, indexNewVertex, triangleStore)) {
ownerTriangle->setIsObsolete(false);
else if (!mOwnerTriangle->getAdjacentEdge(indexOfPreviousCounterClockwiseEdge(
this->mIndex)).computeSilhouette(vertices,
indexNewVertex,
triangleStore)) {
mOwnerTriangle->setIsObsolete(false);
triangleStore.setNbTriangles(backup);
TriangleEPA* triangle = triangleStore.newTriangle(vertices, indexNewVertex, getTargetVertexIndex(), getSourceVertexIndex());
TriangleEPA* triangle = triangleStore.newTriangle(vertices, indexNewVertex,
getTargetVertexIndex(),
getSourceVertexIndex());
if (triangle) {
halfLink(EdgeEPA(triangle, 1), *this);

View File

@ -44,31 +44,67 @@ class TrianglesStore;
-------------------------------------------------------------------
*/
class EdgeEPA {
private:
TriangleEPA* ownerTriangle; // Pointer to the triangle that contains this edge
int index; // Index of the edge in the triangle (between 0 and 2).
// The edge with index i connect triangle vertices i and (i+1 % 3)
// -------------------- Attributes -------------------- //
// 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:
EdgeEPA(); // Constructor
EdgeEPA(TriangleEPA* ownerTriangle, int index); // Constructor
~EdgeEPA(); // Destructor
TriangleEPA* getOwnerTriangle() const; // Return the pointer to the owner triangle
int getIndex() const; // Return the index of the edge in the triangle
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
bool computeSilhouette(const Vector3* vertices, uint index,
TrianglesStore& triangleStore); // Execute the recursive silhouette algorithm from this edge
// -------------------- Methods -------------------- //
// Constructor
EdgeEPA();
// Constructor
EdgeEPA(TriangleEPA* ownerTriangle, int index);
// 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
inline TriangleEPA* EdgeEPA::getOwnerTriangle() const {
return ownerTriangle;
return mOwnerTriangle;
}
// Return the edge index
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

View File

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

View File

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

View File

@ -30,7 +30,7 @@
using namespace reactphysics3d;
// 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 {
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:
TrianglesStore(); // Constructor
~TrianglesStore(); // Destructor
void clear(); // Clear all the storage
int getNbTriangles() const; // Return the number of triangles
void setNbTriangles(int backup); // Set the number of triangles
TriangleEPA& last(); // Return the last triangle
// -------------------- Methods -------------------- //
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
inline void TrianglesStore::clear() {
nbTriangles = 0;
mNbTriangles = 0;
}
// Return the number of triangles
inline int TrianglesStore::getNbTriangles() const {
return nbTriangles;
return mNbTriangles;
}
inline void TrianglesStore::setNbTriangles(int backup) {
nbTriangles = backup;
mNbTriangles = backup;
}
// Return the last triangle
inline TriangleEPA& TrianglesStore::last() {
assert(nbTriangles > 0);
return triangles[nbTriangles - 1];
assert(mNbTriangles > 0);
return mTriangles[mNbTriangles - 1];
}
// 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;
// If we have not reached the maximum number of triangles
if (nbTriangles != MAX_TRIANGLES) {
newTriangle = &triangles[nbTriangles++];
if (mNbTriangles != MAX_TRIANGLES) {
newTriangle = &mTriangles[mNbTriangles++];
new (newTriangle) TriangleEPA(v0, v1, v2);
if (!newTriangle->computeClosestPoint(vertices)) {
nbTriangles--;
mNbTriangles--;
newTriangle = 0;
}
}
@ -105,9 +136,9 @@ inline TriangleEPA* TrianglesStore::newTriangle(const Vector3* vertices, uint v0
// Access operator
inline TriangleEPA& TrianglesStore::operator[](int i) {
return triangles[i];
return mTriangles[i];
}
} // End of ReactPhysics3D namespace
#endif
#endif

View File

@ -32,15 +32,13 @@
#include <cmath>
#include <cfloat>
#include <cassert>
#include <iostream> // TODO : DELETE THIS
// We want to use the ReactPhysics3D namespace
using namespace reactphysics3d;
// Constructor
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
// 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.
bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Transform& transform1,
const CollisionShape* collisionShape2, const Transform& transform2,
bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1,
const Transform& transform1,
const CollisionShape* collisionShape2,
const Transform& transform2,
ContactInfo*& contactInfo) {
Vector3 suppA; // Support point of object A
@ -71,11 +71,14 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
decimal vDotw;
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;
// 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();
// 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();
// Initialize the margin (sum of margins of both objects)
decimal margin = 2 * OBJECT_MARGIN;
@ -86,7 +89,7 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
Simplex simplex;
// 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
decimal distSquare = DECIMAL_LARGEST;
@ -106,7 +109,7 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
if (vDotw > 0.0 && vDotw * vDotw > distSquare * marginSquare) {
// Cache the current separating axis for frame coherence
currentOverlappingPair->previousSeparatingAxis = v;
mCurrentOverlappingPair->previousSeparatingAxis = v;
// No intersection, we return false
return false;
@ -132,7 +135,9 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
if (penetrationDepth <= 0.0) return false;
// 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
return true;
@ -161,7 +166,9 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
if (penetrationDepth <= 0.0) return false;
// 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
return true;
@ -188,7 +195,9 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
if (penetrationDepth <= 0.0) return false;
// 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
return true;
@ -223,18 +232,22 @@ bool GJKAlgorithm::testCollision(const CollisionShape* collisionShape1, const Tr
if (penetrationDepth <= 0.0) return false;
// 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
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
// enlarged objects to compute a simplex polytope that contains the origin. Then, we give that simplex
// polytope to the EPA algorithm to compute the correct penetration depth and contact points between
// the enlarged objects.
return computePenetrationDepthForEnlargedObjects(collisionShape1, transform1, collisionShape2, transform2, contactInfo, v);
// The objects (without margins) intersect. Therefore, we run the GJK algorithm
// again but on the enlarged objects to compute a simplex polytope that contains
// the origin. Then, we give that simplex polytope to the EPA algorithm to compute
// the correct penetration depth and contact points between the enlarged objects.
return computePenetrationDepthForEnlargedObjects(collisionShape1, transform1, collisionShape2,
transform2, contactInfo, v);
}
// 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
// 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.
bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShape* const collisionShape1, const Transform& transform1,
const CollisionShape* const collisionShape2, const Transform& transform2,
ContactInfo*& contactInfo, Vector3& v) {
bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShape* collisionShape1,
const Transform& transform1,
const CollisionShape* collisionShape2,
const Transform& transform2,
ContactInfo*& contactInfo,
Vector3& v) {
Simplex simplex;
Vector3 suppA;
Vector3 suppB;
@ -253,16 +269,19 @@ bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShap
decimal distSquare = DECIMAL_LARGEST;
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;
// 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 {
// Compute the support points for the enlarged object A and B
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
w = suppA - suppB;
@ -294,9 +313,13 @@ bool GJKAlgorithm::computePenetrationDepthForEnlargedObjects(const CollisionShap
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
// penetration depth and contact points between the two enlarged objects
return algoEPA.computePenetrationDepthAndContactPoints(simplex, collisionShape1, transform1, collisionShape2, transform2, v, contactInfo);
// Give the simplex computed with GJK algorithm to the EPA algorithm
// which will compute the correct penetration depth and contact points
// 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 {
private :
EPAAlgorithm algoEPA; // EPA Algorithm
bool computePenetrationDepthForEnlargedObjects(const CollisionShape* collisionShape1, const Transform& transform1,
const CollisionShape* collisionShape2, const Transform& transform2,
ContactInfo*& contactInfo, Vector3& v); // Compute the penetration depth for enlarged objects
private :
// -------------------- 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 :
GJKAlgorithm(MemoryPool<ContactInfo>& memoryPoolContactInfos); // Constructor
~GJKAlgorithm(); // Destructor
virtual bool testCollision(const CollisionShape* collisionShape1, const Transform& transform1,
const CollisionShape* collisionShape2, const Transform& transform2,
ContactInfo*& contactInfo); // Return true and compute a contact info if the two bounding volume collide
// -------------------- Methods -------------------- //
// 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

View File

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

View File

@ -47,43 +47,117 @@ typedef unsigned int Bits;
-------------------------------------------------------------------
*/
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"
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
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
void computeDeterminants(); // Compute the cached determinant values
Vector3 computeClosestPointForSubset(Bits subset); // Return the closest point "v" in the convex hull of a subset of points
private:
// -------------------- Attributes -------------------- //
// Current points
Vector3 mPoints[4];
// 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:
Simplex(); // Constructor
~Simplex(); // Destructor
bool isFull() const; // Return true if the simplex contains 4 points
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
decimal getMaxLengthSquareOfAPoint() const; // Return the maximum squared length of a point
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
bool isAffinelyDependent() const; // Return true if the set is affinely dependent
void backupClosestPointInSimplex(Vector3& point); // Backup the closest point
void computeClosestPointsOfAandB(Vector3& pA, Vector3& pB) const; // Compute the closest points of object A and B
bool computeClosestPoint(Vector3& v); // Compute the closest point to the origin of the current simplex
// -------------------- Methods -------------------- //
// Constructor
Simplex();
// Destructor
~Simplex();
// Return true if the simplex contains 4 points
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"
@ -98,19 +172,19 @@ inline bool Simplex::isSubset(Bits a, Bits b) const {
// Return true if the simplex contains 4 points
inline bool Simplex::isFull() const {
return (bitsCurrentSimplex == 0xf);
return (mBitsCurrentSimplex == 0xf);
}
// Return true if the simple is empty
inline bool Simplex::isEmpty() const {
return (bitsCurrentSimplex == 0x0);
return (mBitsCurrentSimplex == 0x0);
}
// Return the maximum squared length of a point
inline decimal Simplex::getMaxLengthSquareOfAPoint() const {
return maxLengthSquare;
return mMaxLengthSquare;
}
} // End of the ReactPhysics3D namespace
#endif
#endif

View File

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

View File

@ -47,23 +47,49 @@ namespace reactphysics3d {
-------------------------------------------------------------------
*/
class NarrowPhaseAlgorithm {
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 :
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
virtual bool testCollision(const CollisionShape* collisionShape1, const Transform& transform1,
const CollisionShape* collisionShape2, const Transform& transform2,
ContactInfo*& contactInfo)=0; // Return true and compute a contact info if the two bounding volume collide
// Set the current overlapping pair of bodies
void setCurrentOverlappingPair(BroadPhasePair* overlappingPair);
// 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
inline void NarrowPhaseAlgorithm::setCurrentOverlappingPair(BroadPhasePair *overlappingPair) {
currentOverlappingPair = overlappingPair;
mCurrentOverlappingPair = overlappingPair;
}
} // End of reactphysics3d namespace

View File

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

View File

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

View File

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

View File

@ -44,60 +44,107 @@ class Body;
-------------------------------------------------------------------
*/
class AABB {
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
Body* bodyPointer; // Pointer to the owner body (not the abstract class Body but its derivative which is instanciable)
// -------------------- Attributes -------------------- //
// 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 :
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
const Vector3& getMin() const; // Return the minimum coordinates of the AABB
const Vector3& getMax() const; // Return the maximum coordinates of the AABB
Body* getBodyPointer() const; // Return a pointer to the owner body
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
virtual void update(const Transform& newTransform, const Vector3& extents); // Update the oriented bounding box orientation according to a new orientation of the rigid body
// -------------------- Methods -------------------- //
// Constructor
AABB();
// Constructor
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
virtual void draw() const; // Draw the AABB (only for testing purpose)
// Draw the AABB (only for testing purpose)
virtual void draw() const;
#endif
};
// Return the center point of the AABB in world coordinates
inline Vector3 AABB::getCenter() const {
return (minCoordinates + maxCoordinates) * 0.5;
return (mMinCoordinates + mMaxCoordinates) * 0.5;
}
// Return the minimum coordinates of the AABB
inline const Vector3& AABB::getMin() const {
return minCoordinates;
return mMinCoordinates;
}
// Return the maximum coordinates of the AABB
inline const Vector3& AABB::getMax() const {
return maxCoordinates;
return mMaxCoordinates;
}
// Return a pointer to the owner body
inline Body* AABB::getBodyPointer() const {
return bodyPointer;
return mBodyPointer;
}
// Set the body pointer
inline void AABB::setBodyPointer(Body* bodyPointer) {
this->bodyPointer = bodyPointer;
mBodyPointer = bodyPointer;
}
// 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
inline bool AABB::testCollision(const AABB& aabb) const {
if (maxCoordinates.getX() < aabb.minCoordinates.getX() || aabb.maxCoordinates.getX() < minCoordinates.getX()) return false;
if (maxCoordinates.getY() < aabb.minCoordinates.getY() || aabb.maxCoordinates.getY() < minCoordinates.getY()) return false;
if (maxCoordinates.getZ() < aabb.minCoordinates.getZ() || aabb.maxCoordinates.getZ() < minCoordinates.getZ()) return false;
if (mMaxCoordinates.getX() < aabb.mMinCoordinates.getX() ||
aabb.mMaxCoordinates.getX() < mMinCoordinates.getX()) 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;
}
@ -107,8 +154,8 @@ inline void AABB::update(const Transform& newTransform, const Vector3& extents)
Vector3 worldExtents = Vector3(worldAxis.getColumn(0).dot(extents),
worldAxis.getColumn(1).dot(extents),
worldAxis.getColumn(2).dot(extents));
minCoordinates = newTransform.getPosition() - worldExtents;
maxCoordinates = newTransform.getPosition() + worldExtents;
mMinCoordinates = newTransform.getPosition() - worldExtents;
mMaxCoordinates = newTransform.getPosition() + worldExtents;
}
}; // End of the ReactPhysics3D namespace

View File

@ -46,7 +46,7 @@ using namespace reactphysics3d;
using namespace std;
// 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
void BoxShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const {
decimal factor = (1.0 / 3.0) * mass;
decimal xSquare = extent.getX() * extent.getX();
decimal ySquare = extent.getY() * extent.getY();
decimal zSquare = extent.getZ() * extent.getZ();
decimal xSquare = mExtent.getX() * mExtent.getX();
decimal ySquare = mExtent.getY() * mExtent.getY();
decimal zSquare = mExtent.getZ() * mExtent.getZ();
tensor.setAllValues(factor * (ySquare + zSquare), 0.0, 0.0,
0.0, factor * (xSquare + zSquare), 0.0,
0.0, 0.0, factor * (xSquare + ySquare));
@ -69,9 +69,9 @@ void BoxShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const
#ifdef VISUAL_DEBUG
// Draw the Box (only for testing purpose)
void BoxShape::draw() const {
decimal e1 = extent.getX();
decimal e2 = extent.getY();
decimal e3 = extent.getZ();
decimal e1 = mExtent.getX();
decimal e2 = mExtent.getY();
decimal e3 = mExtent.getZ();
// Draw in red
glColor3f(1.0, 0.0, 0.0);

View File

@ -44,47 +44,76 @@ namespace reactphysics3d {
-------------------------------------------------------------------
*/
class BoxShape : public CollisionShape {
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 :
BoxShape(const Vector3& extent); // Constructor
virtual ~BoxShape(); // Destructor
const Vector3& getExtent() const; // Return the extents of the box
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
virtual Vector3 getLocalSupportPoint(const Vector3& direction, decimal margin=0.0) const; // Return a local support point in a given direction
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const; // Return the local inertia tensor of the collision shape
// -------------------- Methods -------------------- //
// Constructor
BoxShape(const Vector3& extent);
// 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
virtual void draw() const; // Draw the Box (only for testing purpose)
// Draw the Box (only for testing purpose)
virtual void draw() const;
#endif
};
// Return the extents of the box
inline const Vector3& BoxShape::getExtent() const {
return extent;
return mExtent;
}
// Set the extents of the box
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
// This method is used to compute the AABB of the box
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
inline Vector3 BoxShape::getLocalSupportPoint(const Vector3& direction, decimal margin) const {
assert(margin >= 0.0);
return Vector3(direction.getX() < 0.0 ? -extent.getX()-margin : extent.getX()+margin,
direction.getY() < 0.0 ? -extent.getY()-margin : extent.getY()+margin,
direction.getZ() < 0.0 ? -extent.getZ()-margin : extent.getZ()+margin);
return Vector3(direction.getX() < 0.0 ? -mExtent.getX()-margin : mExtent.getX()+margin,
direction.getY() < 0.0 ? -mExtent.getY()-margin : mExtent.getY()+margin,
direction.getZ() < 0.0 ? -mExtent.getZ()-margin : mExtent.getZ()+margin);
}
}; // End of the ReactPhysics3D namespace

View File

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

View File

@ -49,21 +49,46 @@ class Body;
class CollisionShape {
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
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
virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const=0; // Return the local inertia tensor of the collision shapes
// -------------------- Attributes -------------------- //
// Type of the collision shape
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
inline CollisionShapeType CollisionShape::getType() const {
return type;
return mType;
}
}

View File

@ -44,12 +44,13 @@
using namespace reactphysics3d;
// 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(halfHeight > 0.0);
assert(mHalfHeight > 0.0);
// 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
@ -62,20 +63,20 @@ inline Vector3 ConeShape::getLocalSupportPoint(const Vector3& direction, decimal
assert(margin >= 0.0);
const Vector3& v = direction;
decimal sinThetaTimesLengthV = sinTheta * v.length();
decimal sinThetaTimesLengthV = mSinTheta * v.length();
Vector3 supportPoint;
if (v.getY() >= sinThetaTimesLengthV) {
supportPoint = Vector3(0.0, halfHeight, 0.0);
supportPoint = Vector3(0.0, mHalfHeight, 0.0);
}
else {
decimal projectedLength = sqrt(v.getX() * v.getX() + v.getZ() * v.getZ());
if (projectedLength > MACHINE_EPSILON) {
decimal d = radius / projectedLength;
supportPoint = Vector3(v.getX() * d, -halfHeight, v.getZ() * d);
decimal d = mRadius / projectedLength;
supportPoint = Vector3(v.getX() * d, -mHalfHeight, v.getZ() * d);
}
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);
// Draw the sphere
glutWireCone(radius, 2.0 * halfHeight, 50, 50);
glutWireCone(mRadius, 2.0 * mHalfHeight, 50, 50);
}
#endif

View File

@ -44,64 +44,100 @@ namespace reactphysics3d {
-------------------------------------------------------------------
*/
class ConeShape : public CollisionShape {
private :
decimal radius; // Radius of the base
decimal halfHeight; // Half height of the cone
decimal sinTheta; // sine of the semi angle at the apex point
// -------------------- Attributes -------------------- //
// 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 :
ConeShape(decimal radius, decimal height); // Constructor
virtual ~ConeShape(); // Destructor
decimal getRadius() const; // Return the radius
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
// -------------------- Methods -------------------- //
// 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
virtual void draw() const; // Draw the sphere (only for testing purpose)
// Draw the sphere (only for testing purpose)
virtual void draw() const;
#endif
};
// Return the radius
inline decimal ConeShape::getRadius() const {
return radius;
return mRadius;
}
// Set the radius
inline void ConeShape::setRadius(decimal radius) {
this->radius = radius;
mRadius = radius;
// 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
inline decimal ConeShape::getHeight() const {
return 2.0 * halfHeight;
return 2.0 * mHalfHeight;
}
// Set the 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
sinTheta = radius / (sqrt(radius * radius + height * height));
mSinTheta = mRadius / (sqrt(mRadius * mRadius + height * height));
}
// Return the local extents in x,y and z direction
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
inline void ConeShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const {
decimal rSquare = radius * radius;
decimal diagXZ = 0.15 * mass * (rSquare + halfHeight);
decimal rSquare = mRadius * mRadius;
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);
}

View File

@ -44,7 +44,7 @@ using namespace reactphysics3d;
// Constructor
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());
if (lengthW != 0.0) {
if (uDotv < 0.0) supportPoint.setY(-halfHeight);
else supportPoint.setY(halfHeight);
supportPoint += (radius / lengthW) * w;
if (uDotv < 0.0) supportPoint.setY(-mHalfHeight);
else supportPoint.setY(mHalfHeight);
supportPoint += (mRadius / lengthW) * w;
}
else {
if (uDotv < 0.0) supportPoint.setY(-halfHeight);
else supportPoint.setY(halfHeight);
if (uDotv < 0.0) supportPoint.setY(-mHalfHeight);
else supportPoint.setY(mHalfHeight);
}
// Add the margin to the support point
@ -92,6 +92,6 @@ void CylinderShape::draw() const {
glColor3f(1.0, 0.0, 0.0);
// Draw the sphere
glutWireSphere(radius, 50, 50);
glutWireSphere(mRadius, 50, 50);
}
#endif

View File

@ -43,57 +43,92 @@ namespace reactphysics3d {
-------------------------------------------------------------------
*/
class CylinderShape : public CollisionShape {
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 :
CylinderShape(decimal radius, decimal height); // Constructor
virtual ~CylinderShape(); // Destructor
decimal getRadius() const; // Return the radius
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
// -------------------- Methods -------------------- //
// Constructor
CylinderShape(decimal radius, decimal height);
// Destructor
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
virtual void draw() const; // Draw the sphere (only for testing purpose)
// Draw the sphere (only for testing purpose)
virtual void draw() const;
#endif
};
// Return the radius
inline decimal CylinderShape::getRadius() const {
return radius;
return mRadius;
}
// Set the radius
inline void CylinderShape::setRadius(decimal radius) {
this->radius = radius;
this->mRadius = radius;
}
// Return the height
inline decimal CylinderShape::getHeight() const {
return halfHeight * 2.0;
return mHalfHeight * 2.0;
}
// Set the 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
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
inline void CylinderShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const {
decimal height = 2.0 * halfHeight;
decimal diag = (1.0 / 12.0) * mass * (3 * radius * radius + height * height);
tensor.setAllValues(diag, 0.0, 0.0, 0.0, 0.5 * mass * radius * radius, 0.0, 0.0, 0.0, diag);
decimal height = 2.0 * mHalfHeight;
decimal diag = (1.0 / 12.0) * mass * (3 * mRadius * mRadius + height * height);
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

View File

@ -45,7 +45,7 @@ using namespace reactphysics3d;
using namespace std;
// 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);
// Draw the sphere
glutWireSphere(radius, 50, 50);
glutWireSphere(mRadius, 50, 50);
}
#endif

View File

@ -40,32 +40,61 @@ namespace reactphysics3d {
-------------------------------------------------------------------
*/
class SphereShape : public CollisionShape {
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 :
SphereShape(decimal radius); // Constructor
virtual ~SphereShape(); // Destructor
decimal getRadius() const; // Return the radius of the sphere
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
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
// -------------------- Methods -------------------- //
// Constructor
SphereShape(decimal radius);
// 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
virtual void draw() const; // Draw the sphere (only for testing purpose)
// Draw the sphere (only for testing purpose)
virtual void draw() const;
#endif
};
// Get the radius of the sphere
inline decimal SphereShape::getRadius() const {
return radius;
return mRadius;
}
// Set the radius of the sphere
inline void SphereShape::setRadius(decimal radius) {
this->radius = radius;
mRadius = radius;
}
// 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 (length > 0.0) {
// 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
// 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
// This method is used to compute the AABB of the box
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
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);
}

View File

@ -33,7 +33,7 @@
#include "decimal.h"
// 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
#elif defined(__APPLE__) // Apple platform
#define APPLE_OS
@ -44,40 +44,61 @@
// Namespace reactphysics3d
namespace reactphysics3d {
// Type definitions
// ------------------- Type definitions ------------------- //
typedef unsigned int uint;
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;
// Mathematical 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
// ------------------- Constants ------------------- //
// Physics Engine constants
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
const reactphysics3d::decimal DECIMAL_SMALLEST = - std::numeric_limits<decimal>::max();
// GJK Algorithm parameters
const reactphysics3d::decimal OBJECT_MARGIN = 0.04; // Object margin for collision detection in cm
// Maximum decimal value
const reactphysics3d::decimal DECIMAL_LARGEST = std::numeric_limits<decimal>::max();
// Contact constants
const reactphysics3d::decimal FRICTION_COEFFICIENT = 0.4; // Friction coefficient
const reactphysics3d::decimal PERSISTENT_CONTACT_DIST_THRESHOLD = 0.02; // Distance threshold for two contact points for a valid persistent contact
// Machine epsilon
const reactphysics3d::decimal MACHINE_EPSILON = std::numeric_limits<decimal>::epsilon();
// Constraint solver constants
const int NB_MAX_BODIES = 100000; // Maximum number of bodies
const int NB_MAX_CONTACTS = 100000; // Maximum number of contacts (for memory pool allocation)
const int NB_MAX_CONSTRAINTS = 100000; // Maximum number of constraints
// Infinity
const reactphysics3d::decimal DECIMAL_INFINITY = std::numeric_limits<decimal>::infinity();
// Constraint solver constants
const uint DEFAULT_LCP_ITERATIONS = 15; // Number of iterations when solving a LCP problem
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
const reactphysics3d::decimal PENETRATION_DEPTH_THRESHOLD_ERROR_CORRECTION = 0.20; // Contacts with penetration depth (in meters) larger that this use error correction with projection
// Pi constant
const reactphysics3d::decimal PI = 3.14159265;
// Default internal constant timestep in seconds
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;
// Constructor
Constraint::Constraint(RigidBody* const body1, RigidBody* const body2, uint nbConstraints, bool active, ConstraintType type)
:body1(body1), body2(body2), active(active), nbConstraints(nbConstraints), type(type) {
Constraint::Constraint(RigidBody* const body1, RigidBody* const body2,
uint nbConstraints, bool active, ConstraintType type)
:mBody1(body1), mBody2(body2), mActive(active),
mNbConstraints(nbConstraints), mType(type) {
// Initialize the cached lambda values
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 {
protected :
RigidBody* const body1; // Pointer to the first body of the constraint
RigidBody* const body2; // Pointer to the second body of the constraint
bool active; // True if the constraint is active
uint nbConstraints; // Number mathematical constraints associated with this Constraint
const ConstraintType type; // Type of the constraint
std::vector<decimal> cachedLambdas; // Cached lambda values of each mathematical constraint for more precise initializaton of LCP solver
// -------------------- Attributes -------------------- //
// Pointer to the first body of the constraint
RigidBody* const mBody1;
// 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 :
// -------------------- Methods -------------------- //
// Constructor
Constraint(RigidBody* const body1, RigidBody* const body2, uint nbConstraints,
bool active, ConstraintType type); // Constructor // Constructor
virtual ~Constraint(); // Destructor
RigidBody* const getBody1() const; // Return the reference to the body 1
RigidBody* const getBody2() const; // Return the reference to the body 2 // Evaluate the 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
virtual void computeJacobian(int noConstraint, decimal J_sp[NB_MAX_CONSTRAINTS][2*6]) const=0; // Compute the jacobian matrix for all mathematical constraints
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
virtual void computeErrorValue(int noConstraint, decimal errorValues[]) const=0; // Compute the error values for all the mathematical constraints
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
void setCachedLambda(int index, decimal lambda); // Set on cached lambda value
bool active, ConstraintType type);
// Destructor
virtual ~Constraint();
// Return the reference to the body 1
RigidBody* const getBody1() const;
// Return the reference to the body 2
RigidBody* const getBody2() const;
// Return true if the constraint is active
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
inline RigidBody* const Constraint::getBody1() const {
return body1;
return mBody1;
}
// Return the reference to the body 2
inline RigidBody* const Constraint::getBody2() const {
return body2;
return mBody2;
}
// Return true if the constraint is active
inline bool Constraint::isActive() const {
return active;
return mActive;
}
// Return the type of the constraint
inline ConstraintType Constraint::getType() const {
return type;
return mType;
}
// Return the number auxiliary constraints
inline uint Constraint::getNbConstraints() const {
return nbConstraints;
return mNbConstraints;
}
// Get one previous lambda value
inline decimal Constraint::getCachedLambda(int index) const {
assert(index >= 0 && index < nbConstraints);
return cachedLambdas[index];
assert(index >= 0 && index < mNbConstraints);
return mCachedLambdas[index];
}
// Set on cached lambda value
inline void Constraint::setCachedLambda(int index, decimal lambda) {
assert(index >= 0 && index < nbConstraints);
cachedLambdas[index] = lambda;
assert(index >= 0 && index < mNbConstraints);
mCachedLambdas[index] = lambda;
}

View File

@ -31,15 +31,18 @@ using namespace std;
// Constructor
Contact::Contact(RigidBody* const body1, RigidBody* const body2, const ContactInfo* contactInfo)
: Constraint(body1, body2, 3, true, CONTACT), normal(contactInfo->normal), penetrationDepth(contactInfo->penetrationDepth),
localPointOnBody1(contactInfo->localPoint1), localPointOnBody2(contactInfo->localPoint2),
worldPointOnBody1(body1->getTransform() * contactInfo->localPoint1), worldPointOnBody2(body2->getTransform() * contactInfo->localPoint2) {
assert(penetrationDepth > 0.0);
: Constraint(body1, body2, 3, true, CONTACT), mNormal(contactInfo->normal),
mPenetrationDepth(contactInfo->penetrationDepth),
mLocalPointOnBody1(contactInfo->localPoint1),
mLocalPointOnBody2(contactInfo->localPoint2),
mWorldPointOnBody1(body1->getTransform() * contactInfo->localPoint1),
mWorldPointOnBody2(body2->getTransform() * contactInfo->localPoint2) {
assert(mPenetrationDepth > 0.0);
// 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 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
computeFrictionVectors();
@ -56,30 +59,30 @@ Contact::~Contact() {
// of the contact. The argument "noConstraint", is the row were the method have
// to start to fill in the J_sp matrix.
void Contact::computeJacobian(int noConstraint, decimal J_sp[NB_MAX_CONSTRAINTS][2*6]) const {
assert(body1);
assert(body2);
assert(mBody1);
assert(mBody2);
Vector3 body1Position = body1->getTransform().getPosition();
Vector3 body2Position = body2->getTransform().getPosition();
Vector3 body1Position = mBody1->getTransform().getPosition();
Vector3 body2Position = mBody2->getTransform().getPosition();
int currentIndex = noConstraint; // Current constraint index
Vector3 r1 = worldPointOnBody1 - body1Position;
Vector3 r2 = worldPointOnBody2 - body2Position;
Vector3 r1CrossN = r1.cross(normal);
Vector3 r2CrossN = r2.cross(normal);
Vector3 r1 = mWorldPointOnBody1 - body1Position;
Vector3 r2 = mWorldPointOnBody2 - body2Position;
Vector3 r1CrossN = r1.cross(mNormal);
Vector3 r2CrossN = r2.cross(mNormal);
// Compute the jacobian matrix for the body 1 for the contact constraint
J_sp[currentIndex][0] = -normal.getX();
J_sp[currentIndex][1] = -normal.getY();
J_sp[currentIndex][2] = -normal.getZ();
J_sp[currentIndex][0] = -mNormal.getX();
J_sp[currentIndex][1] = -mNormal.getY();
J_sp[currentIndex][2] = -mNormal.getZ();
J_sp[currentIndex][3] = -r1CrossN.getX();
J_sp[currentIndex][4] = -r1CrossN.getY();
J_sp[currentIndex][5] = -r1CrossN.getZ();
// Compute the jacobian matrix for the body 2 for the contact constraint
J_sp[currentIndex][6] = normal.getX();
J_sp[currentIndex][7] = normal.getY();
J_sp[currentIndex][8] = normal.getZ();
J_sp[currentIndex][6] = mNormal.getX();
J_sp[currentIndex][7] = mNormal.getY();
J_sp[currentIndex][8] = mNormal.getZ();
J_sp[currentIndex][9] = r2CrossN.getX();
J_sp[currentIndex][10] = r2CrossN.getY();
J_sp[currentIndex][11] = r2CrossN.getZ();
@ -87,21 +90,21 @@ void Contact::computeJacobian(int noConstraint, decimal J_sp[NB_MAX_CONSTRAINTS]
currentIndex++;
// Compute the jacobian matrix for the body 1 for the first friction constraint
Vector3 r1CrossU1 = r1.cross(frictionVectors[0]);
Vector3 r2CrossU1 = r2.cross(frictionVectors[0]);
Vector3 r1CrossU2 = r1.cross(frictionVectors[1]);
Vector3 r2CrossU2 = r2.cross(frictionVectors[1]);
J_sp[currentIndex][0] = -frictionVectors[0].getX();
J_sp[currentIndex][1] = -frictionVectors[0].getY();
J_sp[currentIndex][2] = -frictionVectors[0].getZ();
Vector3 r1CrossU1 = r1.cross(mFrictionVectors[0]);
Vector3 r2CrossU1 = r2.cross(mFrictionVectors[0]);
Vector3 r1CrossU2 = r1.cross(mFrictionVectors[1]);
Vector3 r2CrossU2 = r2.cross(mFrictionVectors[1]);
J_sp[currentIndex][0] = -mFrictionVectors[0].getX();
J_sp[currentIndex][1] = -mFrictionVectors[0].getY();
J_sp[currentIndex][2] = -mFrictionVectors[0].getZ();
J_sp[currentIndex][3] = -r1CrossU1.getX();
J_sp[currentIndex][4] = -r1CrossU1.getY();
J_sp[currentIndex][5] = -r1CrossU1.getZ();
// Compute the jacobian matrix for the body 2 for the first friction constraint
J_sp[currentIndex][6] = frictionVectors[0].getX();
J_sp[currentIndex][7] = frictionVectors[0].getY();
J_sp[currentIndex][8] = frictionVectors[0].getZ();
J_sp[currentIndex][6] = mFrictionVectors[0].getX();
J_sp[currentIndex][7] = mFrictionVectors[0].getY();
J_sp[currentIndex][8] = mFrictionVectors[0].getZ();
J_sp[currentIndex][9] = r2CrossU1.getX();
J_sp[currentIndex][10] = r2CrossU1.getY();
J_sp[currentIndex][11] = r2CrossU1.getZ();
@ -109,17 +112,17 @@ void Contact::computeJacobian(int noConstraint, decimal J_sp[NB_MAX_CONSTRAINTS]
currentIndex++;
// Compute the jacobian matrix for the body 1 for the second friction constraint
J_sp[currentIndex][0] = -frictionVectors[1].getX();
J_sp[currentIndex][1] = -frictionVectors[1].getY();
J_sp[currentIndex][2] = -frictionVectors[1].getZ();
J_sp[currentIndex][0] = -mFrictionVectors[1].getX();
J_sp[currentIndex][1] = -mFrictionVectors[1].getY();
J_sp[currentIndex][2] = -mFrictionVectors[1].getZ();
J_sp[currentIndex][3] = -r1CrossU2.getX();
J_sp[currentIndex][4] = -r1CrossU2.getY();
J_sp[currentIndex][5] = -r1CrossU2.getZ();
// Compute the jacobian matrix for the body 2 for the second friction constraint
J_sp[currentIndex][6] = frictionVectors[1].getX();
J_sp[currentIndex][7] = frictionVectors[1].getY();
J_sp[currentIndex][8] = frictionVectors[1].getZ();
J_sp[currentIndex][6] = mFrictionVectors[1].getX();
J_sp[currentIndex][7] = mFrictionVectors[1].getY();
J_sp[currentIndex][8] = mFrictionVectors[1].getZ();
J_sp[currentIndex][9] = r2CrossU2.getX();
J_sp[currentIndex][10] = r2CrossU2.getY();
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
// this methods has to fill in this vector starting from the row "noConstraint"
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 + 1] = -mu_mc_g; // Lower bound for the first friction constraint
lowerBounds[noConstraint + 2] = -mu_mc_g; // Lower bound for the second friction constraint
lowerBounds[noConstraint] = 0.0; // Lower bound for the contact constraint
lowerBounds[noConstraint + 1] = -mMu_mc_g; // Lower bound for the first 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
// 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"
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 + 1] = mu_mc_g; // Upper bound for the first friction constraint
upperBounds[noConstraint + 2] = mu_mc_g; // Upper bound for the second friction constraint
upperBounds[noConstraint] = DECIMAL_INFINITY; // Upper bound for the contact constraint
upperBounds[noConstraint + 1] = mMu_mc_g; // Upper bound for the first 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
// "errorValues" is the error values vector of the constraint solver and this
// method has to fill in this vector starting from the row "noConstraint"
void Contact::computeErrorValue(int noConstraint, decimal errorValues[]) const {
assert(body1);
assert(body2);
assert(mBody1);
assert(mBody2);
// TODO : Do we need this casting anymore ?
RigidBody* rigidBody1 = dynamic_cast<RigidBody*>(body1);
RigidBody* rigidBody2 = dynamic_cast<RigidBody*>(body2);
RigidBody* rigidBody1 = dynamic_cast<RigidBody*>(mBody1);
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
Vector3 velocity1 = rigidBody1->getLinearVelocity();
Vector3 velocity2 = rigidBody2->getLinearVelocity();
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
errorValues[noConstraint] = errorValue; // Error value for contact constraint

View File

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

View File

@ -32,7 +32,7 @@ using namespace reactphysics3d;
using namespace std;
// Constructor
CollisionWorld::CollisionWorld() : collisionDetection(this), currentBodyID(0) {
CollisionWorld::CollisionWorld() : mCollisionDetection(this), mCurrentBodyID(0) {
}
// Destructor
@ -53,7 +53,8 @@ void CollisionWorld::notifyRemovedOverlappingPair(const BroadPhasePair* removedP
}
// 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
}
@ -64,7 +65,8 @@ inline void CollisionWorld::updateOverlappingPair(const BroadPhasePair* pair) {
}
// 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
bodyindex bodyID = computeNextAvailableBodyID();
@ -73,13 +75,14 @@ CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform, C
assert(bodyID < std::numeric_limits<reactphysics3d::bodyindex>::max());
// 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
bodies.insert(collisionBody);
mBodies.insert(collisionBody);
// Add the collision body to the collision detection
collisionDetection.addBody(collisionBody);
mCollisionDetection.addBody(collisionBody);
// Return the pointer to the rigid body
return collisionBody;
@ -89,19 +92,19 @@ CollisionBody* CollisionWorld::createCollisionBody(const Transform& transform, C
void CollisionWorld::destroyCollisionBody(CollisionBody* collisionBody) {
// Remove the body from the collision detection
collisionDetection.removeBody(collisionBody);
mCollisionDetection.removeBody(collisionBody);
// 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
collisionBody->CollisionBody::~CollisionBody();
// 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
memoryPoolCollisionBodies.freeObject(collisionBody);
mMemoryPoolCollisionBodies.freeObject(collisionBody);
}
// Return the next available body ID
@ -109,13 +112,13 @@ bodyindex CollisionWorld::computeNextAvailableBodyID() {
// Compute the body ID
bodyindex bodyID;
if (!freeBodiesIDs.empty()) {
bodyID = freeBodiesIDs.back();
freeBodiesIDs.pop_back();
if (!mFreeBodiesIDs.empty()) {
bodyID = mFreeBodiesIDs.back();
mFreeBodiesIDs.pop_back();
}
else {
bodyID = currentBodyID;
currentBodyID++;
bodyID = mCurrentBodyID;
mCurrentBodyID++;
}
return bodyID;

View File

@ -51,41 +51,86 @@ namespace reactphysics3d {
class CollisionWorld {
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
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
// -------------------- Attributes -------------------- //
// 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 :
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;
};
// Return an iterator to the beginning of the bodies of the physics world
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
inline std::set<CollisionBody*>::iterator CollisionWorld::getBodiesEndIterator() {
return bodies.end();
return mBodies.end();
}
} // End of the ReactPhysics3D namespace

View File

@ -32,8 +32,8 @@ using namespace std;
// Constructor
DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_TIMESTEP)
: CollisionWorld(), timer(timeStep), gravity(gravity), isGravityOn(true), constraintSolver(this),
isDeactivationActive(DEACTIVATION_ENABLED) {
: CollisionWorld(), mTimer(timeStep), mGravity(gravity), mIsGravityOn(true), mConstraintSolver(this),
mIsDeactivationActive(DEACTIVATION_ENABLED) {
}
@ -41,10 +41,10 @@ DynamicsWorld::DynamicsWorld(const Vector3 &gravity, decimal timeStep = DEFAULT_
DynamicsWorld::~DynamicsWorld() {
// 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
(*it).second->OverlappingPair::~OverlappingPair();
memoryPoolOverlappingPairs.freeObject((*it).second);
mMemoryPoolOverlappingPairs.freeObject((*it).second);
}
}
@ -52,31 +52,31 @@ DynamicsWorld::~DynamicsWorld() {
void DynamicsWorld::update() {
bool existCollision = false;
assert(timer.getIsRunning());
assert(mTimer.getIsRunning());
// Compute the time since the last update() call and update the timer
timer.update();
mTimer.update();
// Apply the gravity force to all bodies
applyGravity();
// While the time accumulator is not empty
while(timer.isPossibleToTakeStep()) {
while(mTimer.isPossibleToTakeStep()) {
existCollision = false;
removeAllContactConstraints();
// Compute the collision detection
if (collisionDetection.computeCollisionDetection()) {
if (mCollisionDetection.computeCollisionDetection()) {
existCollision = true;
// Solve constraints
constraintSolver.solve(timer.getTimeStep());
mConstraintSolver.solve(mTimer.getTimeStep());
}
// Update the timer
timer.nextStep();
mTimer.nextStep();
// Reset the movement boolean variable of each body to false
resetBodiesMovementVariable();
@ -86,7 +86,7 @@ void DynamicsWorld::update() {
// Cleanup of the constraint solver
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
// orientation of the body
void DynamicsWorld::updateAllBodiesMotion() {
decimal dt = timer.getTimeStep();
decimal dt = mTimer.getTimeStep();
Vector3 newLinearVelocity;
Vector3 newAngularVelocity;
Vector3 linearVelocityErrorCorrection;
@ -124,13 +124,13 @@ void DynamicsWorld::updateAllBodiesMotion() {
angularVelocityErrorCorrection.setAllValues(0.0, 0.0, 0.0);
// 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
newLinearVelocity = constraintSolver.getConstrainedLinearVelocityOfBody(*it);
newAngularVelocity = constraintSolver.getConstrainedAngularVelocityOfBody(*it);
newLinearVelocity = mConstraintSolver.getConstrainedLinearVelocityOfBody(*it);
newAngularVelocity = mConstraintSolver.getConstrainedAngularVelocityOfBody(*it);
linearVelocityErrorCorrection = constraintSolver.getErrorConstrainedLinearVelocityOfBody(rigidBody);
angularVelocityErrorCorrection = constraintSolver.getErrorConstrainedAngularVelocityOfBody(rigidBody);
linearVelocityErrorCorrection = mConstraintSolver.getErrorConstrainedLinearVelocityOfBody(rigidBody);
angularVelocityErrorCorrection = mConstraintSolver.getErrorConstrainedAngularVelocityOfBody(rigidBody);
}
// 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
void DynamicsWorld::updatePositionAndOrientationOfBody(RigidBody* rigidBody, const Vector3& newLinVelocity, const Vector3& newAngVelocity,
const Vector3& linearVelocityErrorCorrection, const Vector3& angularVelocityErrorCorrection) {
decimal dt = timer.getTimeStep();
decimal dt = mTimer.getTimeStep();
assert(rigidBody);
@ -187,7 +187,7 @@ void DynamicsWorld::updatePositionAndOrientationOfBody(RigidBody* rigidBody, con
void DynamicsWorld::setInterpolationFactorToAllBodies() {
// Compute the interpolation factor
decimal factor = timer.computeInterpolationFactor();
decimal factor = mTimer.computeInterpolationFactor();
assert(factor >= 0.0 && factor <= 1.0);
// Set the factor to all bodies
@ -210,9 +210,9 @@ void DynamicsWorld::applyGravity() {
assert(rigidBody);
// If the gravity force is on
if(isGravityOn) {
if(mIsGravityOn) {
// 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());
// 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
bodies.insert(rigidBody);
rigidBodies.insert(rigidBody);
mBodies.insert(rigidBody);
mRigidBodies.insert(rigidBody);
// Add the rigid body to the collision detection
collisionDetection.addBody(rigidBody);
mCollisionDetection.addBody(rigidBody);
// Return the pointer to the rigid body
return rigidBody;
@ -246,27 +246,27 @@ RigidBody* DynamicsWorld::createRigidBody(const Transform& transform, decimal ma
void DynamicsWorld::destroyRigidBody(RigidBody* rigidBody) {
// Remove the body from the collision detection
collisionDetection.removeBody(rigidBody);
mCollisionDetection.removeBody(rigidBody);
// 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
rigidBody->RigidBody::~RigidBody();
// Remove the rigid body from the list of rigid bodies
bodies.erase(rigidBody); // TOOD : Maybe use a set to make this faster
rigidBodies.erase(rigidBody); // TOOD : Maybe use a set to make this faster
mBodies.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
memoryPoolRigidBodies.freeObject(rigidBody);
mMemoryPoolRigidBodies.freeObject(rigidBody);
}
// Remove all collision contacts constraints
// TODO : This method should be in the collision detection class
void DynamicsWorld::removeAllContactConstraints() {
// 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
Contact* contact = dynamic_cast<Contact*>(*it);
@ -274,7 +274,7 @@ void DynamicsWorld::removeAllContactConstraints() {
// If the constraint is a contact
if (contact) {
// Remove it from the constraints of the physics world
it = constraints.erase(it);
it = mConstraints.erase(it);
}
else {
++it;
@ -284,7 +284,7 @@ void DynamicsWorld::removeAllContactConstraints() {
// Remove all constraints in the physics world
void DynamicsWorld::removeAllConstraints() {
constraints.clear();
mConstraints.clear();
}
// 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();
// Add the pair into the set of overlapping pairs (if not there yet)
OverlappingPair* newPair = new (memoryPoolOverlappingPairs.allocateObject()) OverlappingPair(addedPair->body1, addedPair->body2, memoryPoolContacts);
std::pair<map<std::pair<bodyindex, bodyindex>, OverlappingPair*>::iterator, bool> check = overlappingPairs.insert(make_pair(indexPair, newPair));
OverlappingPair* newPair = new (mMemoryPoolOverlappingPairs.allocateObject()) OverlappingPair(addedPair->body1, addedPair->body2, mMemoryPoolContacts);
std::pair<map<std::pair<bodyindex, bodyindex>, OverlappingPair*>::iterator, bool> check = mOverlappingPairs.insert(make_pair(indexPair, newPair));
assert(check.second);
}
@ -306,9 +306,9 @@ void DynamicsWorld::notifyRemovedOverlappingPair(const BroadPhasePair* removedPa
std::pair<bodyindex, bodyindex> indexPair = removedPair->getBodiesIndexPair();
// Remove the overlapping pair from the memory pool
overlappingPairs[indexPair]->OverlappingPair::~OverlappingPair();
memoryPoolOverlappingPairs.freeObject(overlappingPairs[indexPair]);
overlappingPairs.erase(indexPair);
mOverlappingPairs[indexPair]->OverlappingPair::~OverlappingPair();
mMemoryPoolOverlappingPairs.freeObject(mOverlappingPairs[indexPair]);
mOverlappingPairs.erase(indexPair);
}
// Notify the world about a new narrow-phase contact
@ -321,12 +321,12 @@ void DynamicsWorld::notifyNewContact(const BroadPhasePair* broadPhasePair, const
assert(rigidBody2);
// Create a new contact
Contact* contact = new (memoryPoolContacts.allocateObject()) Contact(rigidBody1, rigidBody2, contactInfo);
Contact* contact = new (mMemoryPoolContacts.allocateObject()) Contact(rigidBody1, rigidBody2, contactInfo);
assert(contact);
// Get the corresponding overlapping pair
pair<bodyindex, bodyindex> indexPair = broadPhasePair->getBodiesIndexPair();
OverlappingPair* overlappingPair = overlappingPairs[indexPair];
OverlappingPair* overlappingPair = mOverlappingPairs[indexPair];
assert(overlappingPair);
// Add the contact to the contact cache of the corresponding overlapping pair

View File

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

View File

@ -30,8 +30,10 @@ using namespace reactphysics3d;
// Constructor
OverlappingPair::OverlappingPair(CollisionBody* body1, CollisionBody* body2, MemoryPool<Contact>& memoryPoolContacts)
: body1(body1), body2(body2), contactsCache(body1, body2, memoryPoolContacts), cachedSeparatingAxis(1.0, 1.0, 1.0) {
OverlappingPair::OverlappingPair(CollisionBody* body1, CollisionBody* body2,
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 {
private:
CollisionBody* const body1; // Pointer to the first body of the contact
CollisionBody* const body2; // Pointer to the second body of the contact
PersistentContactCache contactsCache; // Persistent contact cache
Vector3 cachedSeparatingAxis; // Cached previous separating axis
// -------------------- Attributes -------------------- //
// 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:
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
CollisionBody* const getBody2() const; // Return the pointer to second body
void addContact(Contact* contact); // Add a contact to the contact cache
void update(); // Update the contact cache
Vector3 getCachedSeparatingAxis() const; // Return the cached separating axis
void setCachedSeparatingAxis(const Vector3& axis); // Set the cached separating axis
uint getNbContacts() const; // Return the number of contacts in the cache
Contact* getContact(uint index) const; // Return a contact of the cache
// Return the pointer to first body
CollisionBody* const getBody1() const;
// Return the pointer to second body
CollisionBody* const getBody2() const;
// Add a contact to the contact 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
inline CollisionBody* const OverlappingPair::getBody1() const {
return body1;
return mBody1;
}
// Return the pointer to second body
inline CollisionBody* const OverlappingPair::getBody2() const {
return body2;
return mBody2;
}
// Add a contact to the contact cache
inline void OverlappingPair::addContact(Contact* contact) {
contactsCache.addContact(contact);
mContactsCache.addContact(contact);
}
// Update the contact cache
inline void OverlappingPair::update() {
contactsCache.update(body1->getTransform(), body2->getTransform());
mContactsCache.update(mBody1->getTransform(), mBody2->getTransform());
}
// Return the cached separating axis
inline Vector3 OverlappingPair::getCachedSeparatingAxis() const {
return cachedSeparatingAxis;
return mCachedSeparatingAxis;
}
// Set the cached separating axis
inline void OverlappingPair::setCachedSeparatingAxis(const Vector3& axis) {
cachedSeparatingAxis = axis;
mCachedSeparatingAxis = axis;
}
// Return the number of contacts in the cache
inline uint OverlappingPair::getNbContacts() const {
return contactsCache.getNbContacts();
return mContactsCache.getNbContacts();
}
// Return a contact of the cache
inline Contact* OverlappingPair::getContact(uint index) const {
return contactsCache.getContact(index);
return mContactsCache.getContact(index);
}
} // End of the ReactPhysics3D namespace

View File

@ -30,7 +30,7 @@ using namespace reactphysics3d;
// Constructor
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
void PersistentContactCache::addContact(Contact* contact) {
int indexNewContact = nbContacts;
int indexNewContact = mNbContacts;
// 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
// 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
contact->Contact::~Contact();
memoryPoolContacts.freeObject(contact);
mMemoryPoolContacts.freeObject(contact);
return;
}
}
// If the contact cache is full
if (nbContacts == MAX_CONTACTS_IN_CACHE) {
if (mNbContacts == MAX_CONTACTS_IN_CACHE) {
int indexMaxPenetration = getIndexOfDeepestPenetration(contact);
int indexToRemove = getIndexToRemove(indexMaxPenetration, contact->getLocalPointOnBody1());
removeContact(indexToRemove);
@ -66,26 +66,26 @@ void PersistentContactCache::addContact(Contact* contact) {
}
// Add the new contact in the cache
contacts[indexNewContact] = contact;
nbContacts++;
mContacts[indexNewContact] = contact;
mNbContacts++;
}
// Remove a contact from the cache
void PersistentContactCache::removeContact(int index) {
assert(index >= 0 && index < nbContacts);
assert(nbContacts > 0);
assert(index >= 0 && index < mNbContacts);
assert(mNbContacts > 0);
// Call the destructor explicitly and tell the memory pool that
// the corresponding memory block is now free
contacts[index]->Contact::~Contact();
memoryPoolContacts.freeObject(contacts[index]);
mContacts[index]->Contact::~Contact();
mMemoryPoolContacts.freeObject(mContacts[index]);
// If we don't remove the last index
if (index < nbContacts - 1) {
contacts[index] = contacts[nbContacts - 1];
if (index < mNbContacts - 1) {
mContacts[index] = mContacts[mNbContacts - 1];
}
nbContacts--;
mNbContacts--;
}
// 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
// contact normal
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
for (int i=0; i<nbContacts; i++) {
contacts[i]->setWorldPointOnBody1(transform1 * contacts[i]->getLocalPointOnBody1());
contacts[i]->setWorldPointOnBody2(transform2 * contacts[i]->getLocalPointOnBody2());
contacts[i]->setPenetrationDepth((contacts[i]->getWorldPointOnBody1() - contacts[i]->getWorldPointOnBody2()).dot(contacts[i]->getNormal()));
for (int i=0; i<mNbContacts; i++) {
mContacts[i]->setWorldPointOnBody1(transform1 * mContacts[i]->getLocalPointOnBody1());
mContacts[i]->setWorldPointOnBody2(transform2 * mContacts[i]->getLocalPointOnBody2());
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
for (int i=nbContacts-1; i>=0; i--) {
assert(i>= 0 && i < nbContacts);
for (int i=mNbContacts-1; i>=0; i--) {
assert(i>= 0 && i < mNbContacts);
// 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);
}
else {
// 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 projDifference = contacts[i]->getWorldPointOnBody2() - projOfPoint1;
Vector3 projOfPoint1 = mContacts[i]->getWorldPointOnBody1() - mContacts[i]->getNormal() * mContacts[i]->getPenetrationDepth();
Vector3 projDifference = mContacts[i]->getWorldPointOnBody2() - projOfPoint1;
// 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) {
@ -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
// the new contact is the deepest.
int PersistentContactCache::getIndexOfDeepestPenetration(Contact* newContact) const {
assert(nbContacts == MAX_CONTACTS_IN_CACHE);
assert(mNbContacts == MAX_CONTACTS_IN_CACHE);
int indexMaxPenetrationDepth = -1;
decimal maxPenetrationDepth = newContact->getPenetrationDepth();
// 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 (contacts[i]->getPenetrationDepth() > maxPenetrationDepth) {
maxPenetrationDepth = contacts[i]->getPenetrationDepth();
if (mContacts[i]->getPenetrationDepth() > maxPenetrationDepth) {
maxPenetrationDepth = mContacts[i]->getPenetrationDepth();
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
// kept.
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 area1 = 0.0; // Area with contact 0,2,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) {
// Compute the area
Vector3 vector1 = newPoint - contacts[1]->getLocalPointOnBody1();
Vector3 vector2 = contacts[3]->getLocalPointOnBody1() - contacts[2]->getLocalPointOnBody1();
Vector3 vector1 = newPoint - mContacts[1]->getLocalPointOnBody1();
Vector3 vector2 = mContacts[3]->getLocalPointOnBody1() - mContacts[2]->getLocalPointOnBody1();
Vector3 crossProduct = vector1.cross(vector2);
area0 = crossProduct.lengthSquare();
}
if (indexMaxPenetration != 1) {
// Compute the area
Vector3 vector1 = newPoint - contacts[0]->getLocalPointOnBody1();
Vector3 vector2 = contacts[3]->getLocalPointOnBody1() - contacts[2]->getLocalPointOnBody1();
Vector3 vector1 = newPoint - mContacts[0]->getLocalPointOnBody1();
Vector3 vector2 = mContacts[3]->getLocalPointOnBody1() - mContacts[2]->getLocalPointOnBody1();
Vector3 crossProduct = vector1.cross(vector2);
area1 = crossProduct.lengthSquare();
}
if (indexMaxPenetration != 2) {
// Compute the area
Vector3 vector1 = newPoint - contacts[0]->getLocalPointOnBody1();
Vector3 vector2 = contacts[3]->getLocalPointOnBody1() - contacts[1]->getLocalPointOnBody1();
Vector3 vector1 = newPoint - mContacts[0]->getLocalPointOnBody1();
Vector3 vector2 = mContacts[3]->getLocalPointOnBody1() - mContacts[1]->getLocalPointOnBody1();
Vector3 crossProduct = vector1.cross(vector2);
area2 = crossProduct.lengthSquare();
}
if (indexMaxPenetration != 3) {
// Compute the area
Vector3 vector1 = newPoint - contacts[0]->getLocalPointOnBody1();
Vector3 vector2 = contacts[2]->getLocalPointOnBody1() - contacts[1]->getLocalPointOnBody1();
Vector3 vector1 = newPoint - mContacts[0]->getLocalPointOnBody1();
Vector3 vector2 = mContacts[2]->getLocalPointOnBody1() - mContacts[1]->getLocalPointOnBody1();
Vector3 crossProduct = vector1.cross(vector2);
area3 = crossProduct.lengthSquare();
}
@ -216,12 +216,12 @@ int PersistentContactCache::getMaxArea(decimal area0, decimal area1, decimal are
// Clear the cache
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
// the corresponding memory block is now free
contacts[i]->Contact::~Contact();
memoryPoolContacts.freeObject(contacts[i]);
mContacts[i]->Contact::~Contact();
mMemoryPoolContacts.freeObject(mContacts[i]);
}
nbContacts = 0;
mNbContacts = 0;
}

View File

@ -35,7 +35,7 @@
namespace reactphysics3d {
// 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 {
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
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
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
private:
// -------------------- Attributes -------------------- //
// 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:
PersistentContactCache(Body* const body1, Body* const body2, MemoryPool<Contact>& memoryPoolContacts); // Constructor
~PersistentContactCache(); // Destructor
void addContact(Contact* contact); // Add a contact
void update(const Transform& transform1, const Transform& transform2); // Update the contact cache
void clear(); // Clear the cache
uint getNbContacts() const; // Return the number of contacts in the cache
Contact* getContact(uint index) const; // Return a contact of the cache
// -------------------- Methods -------------------- //
// Constructor
PersistentContactCache(Body* const mBody1, Body* const mBody2,
MemoryPool<Contact>& mMemoryPoolContacts);
// 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
inline uint PersistentContactCache::getNbContacts() const {
return nbContacts;
return mNbContacts;
}
// Return a contact of the cache
inline Contact* PersistentContactCache::getContact(uint index) const {
assert(index >= 0 && index < nbContacts);
return contacts[index];
assert(index >= 0 && index < mNbContacts);
return mContacts[index];
}
// 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;
return (approxEqual(vector1.getX(), vector2.getX(), epsilon) &&
approxEqual(vector1.getY(), vector2.getY(), epsilon) &&

View File

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

View File

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

View File

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

View File

@ -33,25 +33,25 @@ using namespace reactphysics3d;
// Constructor of the class
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
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)
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
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;
// Compute the quaternion
x = (array[2][0] + array[0][2])*s;
y = (array[1][2] + array[2][1])*s;
z = 0.5*r;
w = (array[1][0] - array[0][1])*s;
mX = (array[2][0] + array[0][2])*s;
mY = (array[1][2] + array[2][1])*s;
mZ = 0.5*r;
mW = (array[1][0] - array[0][1])*s;
}
else {
r = sqrt(array[1][1] - array[2][2] - array[0][0] + 1.0);
s = 0.5 / r;
// Compute the quaternion
x = (array[0][1] + array[1][0])*s;
y = 0.5 * r;
z = (array[1][2] + array[2][1])*s;
w = (array[0][2] - array[2][0])*s;
mX = (array[0][1] + array[1][0])*s;
mY = 0.5 * r;
mZ = (array[1][2] + array[2][1])*s;
mW = (array[0][2] - array[2][0])*s;
}
}
else if (array[2][2] > array[0][0]) {
@ -99,20 +99,20 @@ Quaternion::Quaternion(const Matrix3x3& matrix) {
s = 0.5 / r;
// Compute the quaternion
x = (array[2][0] + array[0][2])*s;
y = (array[1][2] + array[2][1])*s;
z = 0.5 * r;
w = (array[1][0] - array[0][1])*s;
mX = (array[2][0] + array[0][2])*s;
mY = (array[1][2] + array[2][1])*s;
mZ = 0.5 * r;
mW = (array[1][0] - array[0][1])*s;
}
else {
r = sqrt(array[0][0] - array[1][1] - array[2][2] + 1.0);
s = 0.5 / r;
// Compute the quaternion
x = 0.5 * r;
y = (array[0][1] + array[1][0])*s;
z = (array[2][0] - array[0][2])*s;
w = (array[2][1] - array[1][2])*s;
mX = 0.5 * r;
mY = (array[0][1] + array[1][0])*s;
mZ = (array[2][0] - array[0][2])*s;
mW = (array[2][1] - array[1][2])*s;
}
}
else {
@ -120,10 +120,10 @@ Quaternion::Quaternion(const Matrix3x3& matrix) {
s = 0.5/r;
// Compute the quaternion
x = (array[2][1]-array[1][2])*s;
y = (array[0][2]-array[2][0])*s;
z = (array[1][0]-array[0][1])*s;
w = 0.5 * r;
mX = (array[2][1]-array[1][2])*s;
mY = (array[0][2]-array[2][0])*s;
mZ = (array[1][0]-array[0][1])*s;
mW = 0.5 * r;
}
}
@ -148,10 +148,10 @@ void Quaternion::getRotationAngleAxis(decimal& angle, Vector3& axis) const {
}
// Compute the roation angle
angle = acos(quaternion.w) * 2.0;
angle = acos(quaternion.mW) * 2.0;
// 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
rotationAxis = rotationAxis.getUnit();
@ -163,7 +163,7 @@ void Quaternion::getRotationAngleAxis(decimal& angle, Vector3& axis) const {
// Return the orientation matrix corresponding to this quaternion
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;
if (nQ > 0.0) {
@ -171,18 +171,18 @@ Matrix3x3 Quaternion::getMatrix() const {
}
// Computations used for optimization (less multiplications)
decimal xs = x*s;
decimal ys = y*s;
decimal zs = z*s;
decimal wxs = w*xs;
decimal wys = w*ys;
decimal wzs = w*zs;
decimal xxs = x*xs;
decimal xys = x*ys;
decimal xzs = x*zs;
decimal yys = y*ys;
decimal yzs = y*zs;
decimal zzs = z*zs;
decimal xs = mX*s;
decimal ys = mY*s;
decimal zs = mZ*s;
decimal wxs = mW*xs;
decimal wys = mW*ys;
decimal wzs = mW*zs;
decimal xxs = mX*xs;
decimal xys = mX*ys;
decimal xzs = mX*zs;
decimal yys = mY*ys;
decimal yzs = mY*zs;
decimal zzs = mZ*zs;
// Create the matrix corresponding to the quaternion
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.
// 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);
decimal invert = 1.0;
@ -206,7 +207,8 @@ Quaternion Quaternion::slerp(const Quaternion& quaternion1, const Quaternion& qu
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
const decimal epsilon = 0.00001;
if(1-cosineTheta < epsilon) {

View File

@ -42,99 +42,159 @@ namespace reactphysics3d {
-------------------------------------------------------------------
*/
class Quaternion {
private :
decimal x; // Component x of the quaternion
decimal y; // Component y of the quaternion
decimal z; // Component z of the quaternion
decimal w; // Component w of the quaternion
// -------------------- Attributes -------------------- //
// Components of the quaternion
decimal mX, mY, mZ, mW;
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 --- //
Quaternion operator+(const Quaternion& quaternion) const; // Overloaded operator for the addition
Quaternion operator-(const Quaternion& quaternion) const; // Overloaded operator for the substraction
Quaternion operator*(decimal nb) const; // Overloaded operator for the multiplication with a constant
Quaternion operator*(const Quaternion& quaternion) const; // Overloaded operator for the multiplication
Quaternion& operator=(const Quaternion& quaternion); // Overloaded operator for assignment
bool operator==(const Quaternion& quaternion) const; // Overloaded operator for equality condition
// -------------------- Methods -------------------- //
// Constructor
Quaternion();
// Constructor with arguments
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)
inline decimal Quaternion::getX() const {
return x;
return mX;
}
// Get the value y (inline)
inline decimal Quaternion::getY() const {
return y;
return mY;
}
// Get the value z (inline)
inline decimal Quaternion::getZ() const {
return z;
return mZ;
}
// Get the value w (inline)
inline decimal Quaternion::getW() const {
return w;
return mW;
}
// Set the value x (inline)
inline void Quaternion::setX(decimal x) {
this->x = x;
mX = x;
}
// Set the value y (inline)
inline void Quaternion::setY(decimal y) {
this->y = y;
mY = y;
}
// Set the value z (inline)
inline void Quaternion::setZ(decimal z) {
this->z = z;
mZ = z;
}
// Set the value w (inline)
inline void Quaternion::setW(decimal w) {
this->w = w;
mW = w;
}
// Return the vector v=(x y z) of the quaternion
inline Vector3 Quaternion::vectorV() const {
// Return the vector v
return Vector3(x, y, z);
return Vector3(mX, mY, mZ);
}
// Return the length of the quaternion (inline)
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
@ -145,7 +205,8 @@ inline Quaternion Quaternion::getUnit() const {
assert (lengthQuaternion != 0.0);
// 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
@ -155,7 +216,7 @@ inline Quaternion Quaternion::identity() {
// Return the conjugate of the quaternion (inline)
inline Quaternion Quaternion::getConjugate() const {
return Quaternion(-x, -y, -z, w);
return Quaternion(-mX, -mY, -mZ, mW);
}
// Return the inverse of the quaternion (inline)
@ -166,46 +227,51 @@ inline Quaternion Quaternion::getInverse() const {
assert (lengthQuaternion != 0.0);
// 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
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
inline Quaternion Quaternion::operator+(const Quaternion& quaternion) const {
// 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
inline Quaternion Quaternion::operator-(const Quaternion& quaternion) const {
// 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
inline Quaternion Quaternion::operator*(decimal nb) const {
// 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
inline Quaternion Quaternion::operator*(const Quaternion& quaternion) const {
// 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
inline Quaternion& Quaternion::operator=(const Quaternion& quaternion) {
// Check for self-assignment
if (this != &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;
}
// Return this quaternion
@ -214,7 +280,8 @@ inline Quaternion& Quaternion::operator=(const Quaternion& quaternion) {
// Overloaded operator for equality condition
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

View File

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

View File

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

View File

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

View File

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

View File

@ -38,412 +38,4 @@
#include <cassert>
#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

View File

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

View File

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