From 9d9142af30ab05fbbe02118102da245c22d442e9 Mon Sep 17 00:00:00 2001 From: Daniel Chappuis Date: Wed, 10 Jul 2013 00:18:55 +0200 Subject: [PATCH] Add the CapsuleShape class for the capsule collision shape --- src/collision/shapes/CapsuleShape.cpp | 125 +++++++++++++++++++++++ src/collision/shapes/CapsuleShape.h | 140 ++++++++++++++++++++++++++ src/reactphysics3d.h | 2 + 3 files changed, 267 insertions(+) create mode 100644 src/collision/shapes/CapsuleShape.cpp create mode 100644 src/collision/shapes/CapsuleShape.h diff --git a/src/collision/shapes/CapsuleShape.cpp b/src/collision/shapes/CapsuleShape.cpp new file mode 100644 index 00000000..6397b693 --- /dev/null +++ b/src/collision/shapes/CapsuleShape.cpp @@ -0,0 +1,125 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +// Libraries +#include "CapsuleShape.h" +#include "../../configuration.h" +#include + +using namespace reactphysics3d; + +// Constructor +CapsuleShape::CapsuleShape(decimal radius, decimal height) + : CollisionShape(CAPSULE, radius), mRadius(radius), mHalfHeight(height * decimal(0.5)) { + assert(radius > decimal(0.0)); + assert(height > decimal(0.0)); +} + +// Private copy-constructor +CapsuleShape::CapsuleShape(const CapsuleShape& shape) + : CollisionShape(shape), mRadius(shape.mRadius), mHalfHeight(shape.mHalfHeight) { + +} + +// Destructor +CapsuleShape::~CapsuleShape() { + +} + +// Return a local support point in a given direction with the object margin. +/// A capsule is the convex hull of two spheres S1 and S2. The support point in the direction "d" +/// of the convex hull of a set of convex objects is the support point "p" in the set of all +/// support points from all the convex objects with the maximum dot product with the direction "d". +/// Therefore, in this method, we compute the support points of both top and bottom spheres of +/// the capsule and return the point with the maximum dot product with the direction vector. Note +/// that the object margin is implicitly the radius and height of the capsule. +Vector3 CapsuleShape::getLocalSupportPointWithMargin(const Vector3& direction) const { + + // If the direction vector is not the zero vector + if (direction.lengthSquare() >= MACHINE_EPSILON * MACHINE_EPSILON) { + + Vector3 unitDirection = direction.getUnit(); + + // Support point top sphere + Vector3 centerTopSphere(0, mHalfHeight, 0); + Vector3 topSpherePoint = centerTopSphere + unitDirection * mRadius; + decimal dotProductTop = topSpherePoint.dot(direction); + + // Support point bottom sphere + Vector3 centerBottomSphere(0, -mHalfHeight, 0); + Vector3 bottomSpherePoint = centerBottomSphere + unitDirection * mRadius; + decimal dotProductBottom = bottomSpherePoint.dot(direction); + + // Return the point with the maximum dot product + if (dotProductTop > dotProductBottom) { + return topSpherePoint; + } + else { + return bottomSpherePoint; + } + } + + // If the direction vector is the zero vector we return a point on the + // boundary of the capsule + return Vector3(0, mRadius, 0); +} + +// Return a local support point in a given direction without the object margin. +Vector3 CapsuleShape::getLocalSupportPointWithoutMargin(const Vector3& direction) const { + + // If the dot product of the direction and the local Y axis (dotProduct = direction.y) + // is positive + if (direction.y > 0.0) { + + // Return the top sphere center point + return Vector3(0, mHalfHeight, 0); + } + else { + + // Return the bottom sphere center point + return Vector3(0, -mHalfHeight, 0); + } +} + +// Return the local inertia tensor of the capsule +void CapsuleShape::computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const { + + // The inertia tensor formula for a capsule can be found in : Game Engine Gems, Volume 1 + + decimal height = mHalfHeight + mHalfHeight; + decimal radiusSquare = mRadius * mRadius; + decimal heightSquare = height * height; + decimal radiusSquareDouble = radiusSquare + radiusSquare; + decimal factor1 = decimal(2.0) * mRadius / (decimal(4.0) * mRadius + decimal(3.0) * height); + decimal factor2 = decimal(3.0) * height / (decimal(4.0) * mRadius + decimal(3.0) * height); + decimal sum1 = decimal(0.4) * radiusSquareDouble; + decimal sum2 = decimal(0.75) * height * mRadius + decimal(0.5) * heightSquare; + decimal sum3 = decimal(0.25) * radiusSquare + decimal(1.0 / 12.0) * heightSquare; + decimal IxxAndzz = factor1 * mass * (sum1 + sum2) + factor2 * mass * sum3; + decimal Iyy = factor1 * mass * sum1 + factor2 * mass * decimal(0.25) * radiusSquareDouble; + tensor.setAllValues(IxxAndzz, 0.0, 0.0, + 0.0, Iyy, 0.0, + 0.0, 0.0, IxxAndzz); +} diff --git a/src/collision/shapes/CapsuleShape.h b/src/collision/shapes/CapsuleShape.h new file mode 100644 index 00000000..dc7592e1 --- /dev/null +++ b/src/collision/shapes/CapsuleShape.h @@ -0,0 +1,140 @@ +/******************************************************************************** +* ReactPhysics3D physics library, http://code.google.com/p/reactphysics3d/ * +* Copyright (c) 2010-2013 Daniel Chappuis * +********************************************************************************* +* * +* This software is provided 'as-is', without any express or implied warranty. * +* In no event will the authors be held liable for any damages arising from the * +* use of this software. * +* * +* Permission is granted to anyone to use this software for any purpose, * +* including commercial applications, and to alter it and redistribute it * +* freely, subject to the following restrictions: * +* * +* 1. The origin of this software must not be misrepresented; you must not claim * +* that you wrote the original software. If you use this software in a * +* product, an acknowledgment in the product documentation would be * +* appreciated but is not required. * +* * +* 2. Altered source versions must be plainly marked as such, and must not be * +* misrepresented as being the original software. * +* * +* 3. This notice may not be removed or altered from any source distribution. * +* * +********************************************************************************/ + +#ifndef REACTPHYSICS3D_CAPSULE_SHAPE_H +#define REACTPHYSICS3D_CAPSULE_SHAPE_H + +// Libraries +#include "CollisionShape.h" +#include "../../mathematics/mathematics.h" + +// ReactPhysics3D namespace +namespace reactphysics3d { + +// Class CapsuleShape +/** + * This class represents a capsule collision shape that is defined around the Y axis. + * A capsule shape can be seen as the convex hull of two spheres. + * The capsule shape is defined by its radius (radius of the two spheres of the capsule) + * and its height (distance between the centers of the two spheres). This collision shape + * does not have an explicit object margin distance. The margin is implicitly the radius + * and height of the shape. Therefore, no need to specify an object margin for a + * capsule shape. + */ +class CapsuleShape : public CollisionShape { + + private : + + // -------------------- Attributes -------------------- // + + /// Radius of the two spheres of the capsule + decimal mRadius; + + /// Half height of the capsule (height = distance between the centers of the two spheres) + decimal mHalfHeight; + + // -------------------- Methods -------------------- // + + /// Private copy-constructor + CapsuleShape(const CapsuleShape& shape); + + /// Private assignment operator + CapsuleShape& operator=(const CapsuleShape& shape); + + public : + + // -------------------- Methods -------------------- // + + /// Constructor + CapsuleShape(decimal radius, decimal height); + + /// Destructor + virtual ~CapsuleShape(); + + /// Allocate and return a copy of the object + virtual CapsuleShape* clone(void* allocatedMemory) const; + + /// Return the radius of the capsule + decimal getRadius() const; + + /// Return the height of the capsule + decimal getHeight() const; + + /// Return the number of bytes used by the collision shape + virtual size_t getSizeInBytes() const; + + /// Return a local support point in a given direction with the object margin. + virtual Vector3 getLocalSupportPointWithMargin(const Vector3& direction) const; + + /// Return a local support point in a given direction without the object margin + virtual Vector3 getLocalSupportPointWithoutMargin(const Vector3& direction) const; + + /// Return the local extents in x,y and z direction + virtual Vector3 getLocalExtents() const; + + /// Return the local inertia tensor of the collision shape + virtual void computeLocalInertiaTensor(Matrix3x3& tensor, decimal mass) const; + + /// Test equality between two capsule shapes + virtual bool isEqualTo(const CollisionShape& otherCollisionShape) const; +}; + +/// Allocate and return a copy of the object +inline CapsuleShape* CapsuleShape::clone(void* allocatedMemory) const { + return new (allocatedMemory) CapsuleShape(*this); +} + +// Get the radius of the capsule +inline decimal CapsuleShape::getRadius() const { + return mRadius; +} + +// Return the height of the capsule +inline decimal CapsuleShape::getHeight() const { + return mHalfHeight + mHalfHeight; +} + +// Return the number of bytes used by the collision shape +inline size_t CapsuleShape::getSizeInBytes() const { + return sizeof(CapsuleShape); +} + +// 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 CapsuleShape::getLocalExtents() const { + return Vector3(mRadius, + mHalfHeight + mRadius, + mRadius); +} + +// Test equality between two capsule shapes +inline bool CapsuleShape::isEqualTo(const CollisionShape& otherCollisionShape) const { + const CapsuleShape& otherShape = dynamic_cast(otherCollisionShape); + return (mRadius == otherShape.mRadius && mHalfHeight == otherShape.mHalfHeight); +} + +} + +#endif diff --git a/src/reactphysics3d.h b/src/reactphysics3d.h index e24c2b82..2bf3885c 100644 --- a/src/reactphysics3d.h +++ b/src/reactphysics3d.h @@ -41,11 +41,13 @@ #include "body/RigidBody.h" #include "engine/DynamicsWorld.h" #include "engine/CollisionWorld.h" +#include "engine/Material.h" #include "collision/shapes/CollisionShape.h" #include "collision/shapes/BoxShape.h" #include "collision/shapes/SphereShape.h" #include "collision/shapes/ConeShape.h" #include "collision/shapes/CylinderShape.h" +#include "collision/shapes/CapsuleShape.h" #include "collision/shapes/AABB.h" #include "constraint/BallAndSocketJoint.h" #include "constraint/SliderJoint.h"