852b923c21
git-svn-id: https://reactphysics3d.googlecode.com/svn/trunk@391 92aac97c-a6ce-11dd-a772-7fcde58d38e6
179 lines
9.7 KiB
C++
179 lines
9.7 KiB
C++
/********************************************************************************
|
|
* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ *
|
|
* Copyright (c) 2010 Daniel Chappuis *
|
|
*********************************************************************************
|
|
* *
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy *
|
|
* of this software and associated documentation files (the "Software"), to deal *
|
|
* in the Software without restriction, including without limitation the rights *
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *
|
|
* copies of the Software, and to permit persons to whom the Software is *
|
|
* furnished to do so, subject to the following conditions: *
|
|
* *
|
|
* The above copyright notice and this permission notice shall be included in *
|
|
* all copies or substantial portions of the Software. *
|
|
* *
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN *
|
|
* THE SOFTWARE. *
|
|
********************************************************************************/
|
|
|
|
#ifndef AABB_H
|
|
#define AABB_H
|
|
|
|
// Libraries
|
|
#include "BroadBoundingVolume.h"
|
|
#include "../mathematics/mathematics.h"
|
|
|
|
// ReactPhysics3D namespace
|
|
namespace reactphysics3d {
|
|
|
|
/* -------------------------------------------------------------------
|
|
Class AABB :
|
|
This class represents a bounding volume of type "Axis Aligned
|
|
Bounding Box". It's a box where all the edges are always aligned
|
|
with the world coordinate system. The AABB is defined by a center
|
|
point and three extent size in the x,y and z directions.
|
|
-------------------------------------------------------------------
|
|
*/
|
|
class AABB : public BroadBoundingVolume {
|
|
protected :
|
|
Vector3D center; // Center point of the AABB
|
|
double extent[3]; // Three extents size in the x, y and z directions
|
|
double originalAABBExtent[3]; // Extents of the original AABB (this is used to update the AABB)
|
|
|
|
public :
|
|
AABB(const Vector3D& center, double extentX, double extentY, double extentZ); // Constructor
|
|
virtual ~AABB(); // Destructor
|
|
|
|
Vector3D getCenter() const; // Return the center point
|
|
void setCenter(const Vector3D& center); // Set the center point
|
|
Vector3D getVertex(uint index) const throw (std::invalid_argument); // Return a vertex of the AABB
|
|
double getExtent(uint index) const throw(std::invalid_argument); // Return an extent value
|
|
void setExtent(uint index, double extent) throw(std::invalid_argument); // Set an extent value
|
|
double getMinValueOnAxis(uint axis) const throw(std::invalid_argument); // Return the minimum position value on the given axis
|
|
double getMaxValueOnAxis(uint axis) const throw(std::invalid_argument); // Return the maximum position value on the given axis
|
|
bool testCollision(const AABB& aabb) const; // Return true if the current AABB is overlapping is the AABB in argument
|
|
virtual void update(const Vector3D& newCenter, const Quaternion& rotationQuaternion); // Update the oriented bounding box orientation according to a new orientation of the rigid body
|
|
virtual void draw() const; // Draw the AABB (only for testing purpose)
|
|
static AABB* computeFromVertices(const std::vector<Vector3D>& vertices, const Vector3D& center); // Compute an AABB from a set of vertices
|
|
};
|
|
|
|
// Return the center point
|
|
inline Vector3D AABB::getCenter() const {
|
|
return center;
|
|
}
|
|
|
|
// Set the center point
|
|
inline void AABB::setCenter(const Vector3D& center) {
|
|
this->center = center;
|
|
}
|
|
|
|
// Return one of the 8 vertices of the AABB
|
|
inline Vector3D AABB::getVertex(unsigned int index) const throw (std::invalid_argument) {
|
|
// Check if the index value is valid
|
|
if (index >= 0 && index <8) {
|
|
switch(index) {
|
|
case 0 : return center + Vector3D(extent[0], extent[1], -extent[2]);
|
|
case 1 : return center + Vector3D(extent[0], extent[1], extent[2]);
|
|
case 2 : return center + Vector3D(-extent[0], extent[1], extent[2]);
|
|
case 3 : return center + Vector3D(-extent[0], extent[1], -extent[2]);
|
|
case 4 : return center + Vector3D(extent[0], -extent[1], -extent[2]);
|
|
case 5 : return center + Vector3D(extent[0], -extent[1], extent[2]);
|
|
case 6 : return center + Vector3D(-extent[0], -extent[1], extent[2]);
|
|
case 7 : return center + Vector3D(-extent[0], -extent[1], -extent[2]);
|
|
}
|
|
}
|
|
else {
|
|
// The index value is not valid, we throw an exception
|
|
throw std::invalid_argument("Exception : The index value has to be between 0 and 8");
|
|
}
|
|
}
|
|
|
|
|
|
// Return an extent value
|
|
inline double AABB::getExtent(unsigned int index) const throw(std::invalid_argument) {
|
|
// Check if the index value is valid
|
|
if (index >= 0 && index <3) {
|
|
return extent[index];
|
|
}
|
|
else {
|
|
// The index value is not valid, we throw an exception
|
|
throw std::invalid_argument("Exception : The index value has to be between 0 and 2");
|
|
}
|
|
}
|
|
|
|
// Set an extent value
|
|
inline void AABB::setExtent(unsigned int index, double extent) throw(std::invalid_argument) {
|
|
// Check if the index value is valid
|
|
if (index >= 0 && index <3) {
|
|
this->extent[index] = extent;
|
|
}
|
|
else {
|
|
// The index value is not valid, we throw an exception
|
|
throw std::invalid_argument("Exception : The index value has to be between 0 and 2");
|
|
}
|
|
}
|
|
|
|
// Return the minimum position value on the given axis
|
|
inline double AABB::getMinValueOnAxis(uint axis) const throw(std::invalid_argument) {
|
|
switch (axis) {
|
|
case 0: return center.getX() - extent[0];
|
|
case 1: return center.getY() - extent[1];
|
|
case 2: return center.getZ() - extent[2];
|
|
default: // The index value is not valid, we throw an exception
|
|
throw std::invalid_argument("Exception : The index value has to be between 0 and 2");
|
|
}
|
|
}
|
|
|
|
// Return the maximum position value on the given axis
|
|
inline double AABB::getMaxValueOnAxis(uint axis) const throw(std::invalid_argument) {
|
|
switch (axis) {
|
|
case 0: return center.getX() + extent[0];
|
|
case 1: return center.getY() + extent[1];
|
|
case 2: return center.getZ() + extent[2];
|
|
default: // The index value is not valid, we throw an exception
|
|
throw std::invalid_argument("Exception : The index value has to be between 0 and 2");
|
|
}
|
|
}
|
|
|
|
// Return true if the current AABB is overlapping is 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 {
|
|
Vector3D center2 = aabb.getCenter();
|
|
if (std::abs(center.getX() - center2.getX()) > (extent[0] + aabb.getExtent(0))) return false;
|
|
if (std::abs(center.getY() - center2.getY()) > (extent[1] + aabb.getExtent(1))) return false;
|
|
if (std::abs(center.getZ() - center2.getZ()) > (extent[2] + aabb.getExtent(2))) return false;
|
|
return true;
|
|
}
|
|
|
|
// Update the orientation of the AABB according to the orientation of the rigid body
|
|
// In order to compute the new AABB we use the original AABB (represented by the originalAABBExtent
|
|
// values). The goal is to rotate the original AABB according to the current rotation (rotationQuaternion)
|
|
// and then compute the new extent values from the rotated axis of the original AABB. The three columns of
|
|
// the rotation matrix correspond to the rotated axis of the rotated original AABB. The we have to compute
|
|
// the projections of the three rotated axis onto the x, y and z axis. The projections are easy to compute
|
|
// because for instance if the size of the projection of the vector (4, 5, 6) onto the x axis is simply 4.
|
|
inline void AABB::update(const Vector3D& newCenter, const Quaternion& rotationQuaternion) {
|
|
// Update the center of the AABB
|
|
center = newCenter;
|
|
|
|
// Recompute the new extents size from the rotated AABB
|
|
Matrix rotationMatrix = rotationQuaternion.getMatrix(); // Rotation matrix
|
|
for (int i=0; i<3; i++) { // For each x, y and z axis
|
|
extent[i] = 0.0;
|
|
for (int j=0; j<3; j++) { // For each rotated axis of the rotated original AABB
|
|
// Add the size of the projection of the current rotated axis to the extent of the current (x, y, or z) axis
|
|
extent[i] += std::abs(rotationMatrix.getValue(i, j)) * originalAABBExtent[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
}; // End of the ReactPhysics3D namespace
|
|
|
|
#endif
|