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:
parent
f47298d7eb
commit
4ca42f9392
|
@ -31,7 +31,7 @@
|
|||
using namespace reactphysics3d;
|
||||
|
||||
// Constructor
|
||||
Body::Body(bodyindex id) : id(id) {
|
||||
Body::Body(bodyindex id) : mID(id) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -31,7 +31,7 @@ using namespace reactphysics3d;
|
|||
|
||||
// Constructor
|
||||
BroadPhaseAlgorithm::BroadPhaseAlgorithm(CollisionDetection& collisionDetection)
|
||||
:pairManager(collisionDetection), collisionDetection(collisionDetection) {
|
||||
:mPairManager(collisionDetection), mCollisionDetection(collisionDetection) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
using namespace reactphysics3d;
|
||||
|
||||
// Constructor
|
||||
TrianglesStore::TrianglesStore() : nbTriangles(0) {
|
||||
TrianglesStore::TrianglesStore() : mNbTriangles(0) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -31,7 +31,7 @@ using namespace reactphysics3d;
|
|||
|
||||
// Constructor
|
||||
NarrowPhaseAlgorithm::NarrowPhaseAlgorithm(MemoryPool<ContactInfo>& memoryPool)
|
||||
:memoryPoolContactInfos(memoryPool), currentOverlappingPair(0) {
|
||||
:mMemoryPoolContactInfos(memoryPool), mCurrentOverlappingPair(0) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
using namespace reactphysics3d;
|
||||
|
||||
// Constructor
|
||||
CollisionShape::CollisionShape(CollisionShapeType type) : type(type) {
|
||||
CollisionShape::CollisionShape(CollisionShapeType type) : mType(type) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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) &&
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user