World of Rigid Bodies (WoRB)
|
Encapsulates a cuboid (rectangular parallelepiped). More...
#include <Geometry.h>
Public Member Functions | |
Cuboid () | |
double | Volume () const |
Gets the volume of the cuboid. | |
void | SetMass (double mass) |
Sets body mass and principal moment of inertia of the cuboid. | |
bool | Intersects (const HalfSpace &plane) const |
Tests for intersection of the cuboid and a half-space. | |
bool | Intersects (const Cuboid &B) const |
Tests for intersection between this and some other cuboid. | |
unsigned | Check (CollisionResolver &owner, const HalfSpace &plane) const |
Checks for collision between the cuboid and a half-space. | |
unsigned | Check (CollisionResolver &owner, const Quaternion &point) const |
Checks for collision between the cuboid and a point. | |
unsigned | Check (CollisionResolver &owner, const Cuboid &B) const |
Checks for collision between this and some other cuboid. | |
unsigned | Check (CollisionResolver &owner, const Sphere &B) const |
Checks for collision between the cuboid and a sphere. | |
Data Fields | |
Quaternion | HalfExtent |
Holds the half-extent of the cuboid along each of its local axes. | |
Private methods: Intersection detection related | |
static double | Clamp (double x, double max) |
Clamps the given value to some +/- max value. | |
static Quaternion | FindContactPointOnEdges (const Quaternion &pt_A, const Quaternion &axis_A, double size_A, const Quaternion &pt_B, const Quaternion &axis_B, double size_B, bool use_A) |
Finds point of contact between two points on two cuboid edges. | |
double | ProjectOn (const Quaternion &vector) const |
Gets the sum of cuboid's half-extent's projections on the given vector. | |
double | GetPenetrationOnAxis (const Cuboid &B, const Quaternion &axis, const Quaternion &displacement) const |
Checks if this and another cuboid overlap along the given direction. | |
bool | IsOverlapOnAxis (const Cuboid &B, const Quaternion &direction, const Quaternion &displacement) const |
Checks if this and another cuboid overlap along the given direction. | |
bool | CheckOverlapOnAxis (const Cuboid &B, const Quaternion &direction, const Quaternion &displacement, double &smallestPenetration, unsigned tag_A, unsigned tag_B, unsigned &indexTag_A, unsigned &indexTag_B) const |
Checks for overlap along the given direction. | |
unsigned | RegisterContactOnAxis_Thorough (CollisionResolver &owner, const Cuboid &B, const Quaternion &displacement, unsigned axis) const |
Registers a contact between this and the other cuboid body along an axis. | |
unsigned | RegisterContactOnAxis (CollisionResolver &owner, const Cuboid &B, const Quaternion &displacement, const Quaternion &axis, double penetration) const |
Registers a contact between this and the other cuboid body along an axis. |
Encapsulates a cuboid (rectangular parallelepiped).
Definition at line 230 of file Geometry.h.
WoRB::Cuboid::Cuboid | ( | ) | [inline] |
Definition at line 234 of file Geometry.h.
: Geometry( Geometry::_Cuboid ) { }
unsigned Cuboid::Check | ( | CollisionResolver & | owner, |
const HalfSpace & | plane | ||
) | const |
Checks for collision between the cuboid and a half-space.
Definition at line 557 of file CollisionDetection.cpp.
References WoRB::Geometry::Axis(), WoRB::Geometry::Body, WoRB::Quaternion::ComponentWiseProduct(), WoRB::HalfSpace::Direction, WoRB::Quaternion::Dot(), HalfExtent, WoRB::CollisionResolver::HasSpaceForMoreContacts(), Intersects(), WoRB::HalfSpace::Offset, WoRB::CollisionResolver::RegisterNewContact(), and WoRB::RigidBody::ToWorld.
{ if ( ! owner.HasSpaceForMoreContacts () ) { return 0; // We do not have space left for new contacts } else if ( ! Intersects( plane ) ) { return 0; // No intersection between the cuboid and the half-space } // The contact point with the largest penetration // By default zero, meaning the mid-point on all edges of the cuboid. // Quaternion contactPoint; // Find if there exist edges/faces of the cuboid parallel to the plane Quaternion axis_n( 0, Axis(0).Dot( plane.Direction ), Axis(1).Dot( plane.Direction ), Axis(2).Dot( plane.Direction ) ); unsigned parallelCount = 0; for ( unsigned i = 0; i < 3; ++i ) // for each axis in B { // In case of cuboid's edge that is almost parallel to the plane // we take a mid-point of the edge. // Otherwise, if parallel, we take the vertex which is the closest. // if ( fabs( axis_n[i] ) < 1e-4 ) // almost parallel edge & plane { ++parallelCount; } else // if cuboid's edge is not almost parallel to the plane { // Select the closest vertex // contactPoint[i] = axis_n[i] < 0 ? HalfExtent[i] : -HalfExtent[i]; } } // In case if there are edges/faces parallel to the plane, // just register the found mid-contact point and return. // if ( parallelCount > 0 ) { // Switch to world coordinates and find out penetration of the // contact point into the half-space // contactPoint = Body->ToWorld( contactPoint ); double penetration = plane.Offset - contactPoint.Dot( plane.Direction ); // Register a new contact at the point of contact // return owner.RegisterNewContact( /* a */ Body, /* b */ 0, // scenery /* X */ contactPoint + 0.5 * penetration * plane.Direction, /* N */ plane.Direction, /* d */ penetration ); } // Proceede with the thorough investigation by scanning all vertices // Find the intersection points by checking all vertices. // If the cuboid is resting on a plane or on an edge, it will be reported // as four or two contact points. // Go through each combination of +/- for each half-size // unsigned contactCount = 0; for ( unsigned i = 0; i < 8 && owner.HasSpaceForMoreContacts (); ++i ) { // Calculate the position of each vertex // static const double vertices[8][3] = { { 1, 1, 1 }, { -1, 1, 1 }, { 1, -1, 1 }, { -1, -1, 1 }, { 1, 1, -1 }, { -1, 1, -1 }, { 1, -1, -1 }, { -1, -1, -1 } }; Quaternion vertexPos( 0, vertices[i][0], vertices[i][1], vertices[i][2] ); vertexPos = vertexPos.ComponentWiseProduct( HalfExtent ); vertexPos = Body->ToWorld( vertexPos ); // Calculate the penetration of the vertex into the half-space // double penetration = plane.Offset - vertexPos.Dot( plane.Direction ); if ( penetration >= 0 ) // In case of penetration... { // Register a new contact where the point of contact is half-way between // the vertex and the plane // contactCount += owner.RegisterNewContact( /* a */ Body, /* b */ 0, // scenery /* X */ vertexPos + 0.5 * penetration * plane.Direction, /* N */ plane.Direction, /* d */ penetration ); } } return contactCount; }
unsigned Cuboid::Check | ( | CollisionResolver & | owner, |
const Quaternion & | point | ||
) | const |
Checks for collision between the cuboid and a point.
Definition at line 475 of file CollisionDetection.cpp.
References WoRB::Geometry::Axis(), WoRB::Geometry::Body, HalfExtent, WoRB::Const::Max, WoRB::CollisionResolver::RegisterNewContact(), WoRB::RigidBody::ToWorld, and WoRB::QTensor::TransformInverse().
{ // Transform the point into cuboid coordinates i.e. body-fixed frame // Quaternion pointInBodySpace = Body->ToWorld.TransformInverse( point ); Quaternion normal; double min_depth = Const::Max; // Check each axis, looking for the axis on which the penetration is least deep. // for ( unsigned i = 0; i < 3; ++i ) { double depth = HalfExtent[i] - fabs( pointInBodySpace[i] ); if ( depth < 0 ) { return 0; } else if ( depth < min_depth ) { min_depth = depth; normal = pointInBodySpace[i] < 0 ? -Axis(i) : Axis(i); } } return owner.RegisterNewContact( /* a */ Body, /* b */ 0, // == scenery /* X */ point, /* N */ normal, /* d */ min_depth ); }
unsigned Cuboid::Check | ( | CollisionResolver & | owner, |
const Cuboid & | B | ||
) | const |
Checks for collision between this and some other cuboid.
Definition at line 351 of file CollisionDetection.cpp.
References WoRB::Geometry::Axis(), WoRB::Geometry::Body, WoRB::Quaternion::Cross(), WoRB::Quaternion::Dot(), FindContactPointOnEdges(), HalfExtent, WoRB::Const::Max, WoRB::Geometry::Position(), Quit_If_No_Overlaps, RegisterContactOnAxis(), WoRB::CollisionResolver::RegisterNewContact(), WoRB::RigidBody::ToWorld, and WoRB::Quaternion::Unit().
{ // Find the displacement between the two centra // Quaternion displacement = B.Position() - Position(); // Assume that there is no contact // double penetration = Const::Max; unsigned int axisIndex_A = 0xFF; unsigned int axisIndex_B = 0xFF; #define Quit_If_No_Overlaps( axis, indexA, indexB ) \ if ( ! CheckOverlapOnAxis( B, (axis), displacement, penetration, \ (indexA), (indexB), axisIndex_A, axisIndex_B ) ) { \ return 0; \ } // Check each body axes, keeping track of the axis with the smallest penetration // Quit_If_No_Overlaps( Axis(0) , 0, 0xFF ); Quit_If_No_Overlaps( Axis(1) , 1, 0xFF ); Quit_If_No_Overlaps( Axis(2) , 2, 0xFF ); Quit_If_No_Overlaps( B.Axis(0), 0xFF, 0 ); Quit_If_No_Overlaps( B.Axis(1), 0xFF, 1 ); Quit_If_No_Overlaps( B.Axis(2), 0xFF, 2 ); // Remember the single axis with the smallest penetration // bool use_A = axisIndex_B != 0xFF; // Continue with the axes cross products // Quit_If_No_Overlaps( Axis(0).Cross( B.Axis(0) ), 0, 0 ); Quit_If_No_Overlaps( Axis(0).Cross( B.Axis(1) ), 0, 1 ); Quit_If_No_Overlaps( Axis(0).Cross( B.Axis(2) ), 0, 2 ); Quit_If_No_Overlaps( Axis(1).Cross( B.Axis(0) ), 1, 0 ); Quit_If_No_Overlaps( Axis(1).Cross( B.Axis(1) ), 1, 1 ); Quit_If_No_Overlaps( Axis(1).Cross( B.Axis(2) ), 1, 2 ); Quit_If_No_Overlaps( Axis(2).Cross( B.Axis(0) ), 2, 0 ); Quit_If_No_Overlaps( Axis(2).Cross( B.Axis(1) ), 2, 1 ); Quit_If_No_Overlaps( Axis(2).Cross( B.Axis(2) ), 2, 2 ); #undef Quit_If_No_Overlaps // At this point we have detected a collision! if ( axisIndex_B == 0xFF ) // single axis A { // The collision between cuboid B's vertex and this cuboid's face // return this->RegisterContactOnAxis( owner, B, displacement, Axis( axisIndex_A ), penetration ); } else if ( axisIndex_A == 0xFF ) // single axis B { // The collision between this cuboid's vertex and cuboid B's face // return B.RegisterContactOnAxis( owner, *this, -displacement, B.Axis( axisIndex_B ), penetration ); } // It is an edge-edge collision; get the involved axes from indices // Quaternion axis_A = Axis( axisIndex_A ); Quaternion axis_B = B.Axis( axisIndex_B ); Quaternion normal = axis_A.Cross( axis_B ).Unit (); // Make the normal always point from A to B // if ( normal.Dot( displacement ) > 0 ) { normal = -normal; } // Find the closest point on the involved edges to the other axes. // By default the closest point is mid-point on the edge. // @note Compare to RegisterContactOnAxis algorithm. // Quaternion ptOn_Edge_A; // = zero (mid-point on all edges by default) Quaternion ptOn_Edge_B; // = zero (mid-point on all edges by default) for ( unsigned i = 0; i < 3; ++i ) // foreach axis in A and B { if ( i != axisIndex_A ) { double axis_An = Axis(i).Dot( normal ); if ( fabs( axis_An ) > 1e-4 ) { ptOn_Edge_A[i] = axis_An > 0 ? -HalfExtent[i] : HalfExtent[i]; } } if ( i != axisIndex_B ) { double axis_Bn = B.Axis(i).Dot( normal ); if ( fabs( axis_Bn ) > 1e-4 ) { ptOn_Edge_B[i] = axis_Bn > 0 ? B.HalfExtent[i] : -B.HalfExtent[i]; } } } // At this moment we have a point and a direction for the colliding edges. // Now, find out the contact point i.e. the closest approach of B's line-segments. // (Note that, from here, we continue in world coordinates.) // Quaternion contactPoint_world = FindContactPointOnEdges( Body->ToWorld( ptOn_Edge_A ), axis_A, HalfExtent[ axisIndex_A ], B.Body->ToWorld( ptOn_Edge_B ), axis_B, B.HalfExtent[ axisIndex_B ], use_A ); return owner.RegisterNewContact( /* a */ Body, /* b */ B.Body, /* X */ contactPoint_world, /* N */ normal, /* d */ penetration ); }
unsigned Cuboid::Check | ( | CollisionResolver & | owner, |
const Sphere & | B | ||
) | const |
Checks for collision between the cuboid and a sphere.
Definition at line 510 of file CollisionDetection.cpp.
References WoRB::Geometry::Body, Clamp(), HalfExtent, WoRB::Geometry::Position(), WoRB::Sphere::Radius, WoRB::CollisionResolver::RegisterNewContact(), WoRB::RigidBody::ToWorld, WoRB::QTensor::TransformInverse(), WoRB::Quaternion::Unit(), WoRB::Quaternion::x, WoRB::Quaternion::y, and WoRB::Quaternion::z.
{ // Transform the center of the sphere into cuboid coordinates // Quaternion center = B.Position (); Quaternion relCenter = Body->ToWorld.TransformInverse( center ); // Early out check to see if we can exclude the contact // if ( fabs( relCenter.x ) - B.Radius > HalfExtent.x || fabs( relCenter.y ) - B.Radius > HalfExtent.y || fabs( relCenter.z ) - B.Radius > HalfExtent.z ) { return 0; } // Clamp each coordinate to the cuboid // Quaternion closestPoint( 0, Clamp( relCenter.x, HalfExtent.x ), Clamp( relCenter.y, HalfExtent.y ), Clamp( relCenter.z, HalfExtent.z ) ); // Check we're in contact // double distance = ( closestPoint - relCenter ).ImSquaredNorm(); if ( distance > B.Radius * B.Radius ) { return 0; } distance = sqrt( distance ); // New contact at the closest point in world coordinates // Quaternion closestPointWorld = Body->ToWorld( closestPoint ); return owner.RegisterNewContact( /* a */ Body, /* b */ B.Body, /* X */ closestPointWorld, /* N */ ( closestPointWorld - center ).Unit (), /* d */ B.Radius - distance ); }
bool WoRB::Cuboid::CheckOverlapOnAxis | ( | const Cuboid & | B, |
const Quaternion & | direction, | ||
const Quaternion & | displacement, | ||
double & | smallestPenetration, | ||
unsigned | tag_A, | ||
unsigned | tag_B, | ||
unsigned & | indexTag_A, | ||
unsigned & | indexTag_B | ||
) | const [inline, private] |
Checks for overlap along the given direction.
Keeps track of the smallest penetration.
Definition at line 386 of file Geometry.h.
References GetPenetrationOnAxis(), and WoRB::Quaternion::ImSquaredNorm().
{ // Skip almost parallel axes. if ( direction.ImSquaredNorm() < 1e-4 ) { return true; } // Get penetration depth on axis. double penetration = GetPenetrationOnAxis( B, direction, displacement ); if ( penetration < 0 ) { // no penetration return false; } else if ( penetration < smallestPenetration /*- 1e-6 */ ) { smallestPenetration = penetration; indexTag_A = tag_A; indexTag_B = tag_B; } return true; }
static double WoRB::Cuboid::Clamp | ( | double | x, |
double | max | ||
) | [inline, static, private] |
Clamps the given value to some +/- max value.
Definition at line 338 of file Geometry.h.
Referenced by Check().
{
return x > max ? max : x < -max ? -max : x;
}
Quaternion Cuboid::FindContactPointOnEdges | ( | const Quaternion & | pt_A, |
const Quaternion & | axis_A, | ||
double | size_A, | ||
const Quaternion & | pt_B, | ||
const Quaternion & | axis_B, | ||
double | size_B, | ||
bool | use_A | ||
) | [inline, static, private] |
Finds point of contact between two points on two cuboid edges.
pt_A | Point on the edge of the cuboid A |
axis_A | Axis of the cuboid A |
size_A | Half-extent of A's axis |
pt_B | Point on the edge of the cuboid B |
axis_B | Axis of the cuboid B |
size_B | Half-extent of B's axis |
use_A | Which cuboid to use, if point is on the edge |
Definition at line 180 of file CollisionDetection.cpp.
References WoRB::Quaternion::Dot(), and WoRB::Quaternion::ImSquaredNorm().
Referenced by Check().
{ // If use_A is true, and the contact point is outside the edge (in the case of // an edge-face contact) then we use 'this' cuboid's midpoint, otherwise we use B's. double sqNorm_dA = axis_A.ImSquaredNorm(); // d_A = Axis A double sqNorm_dB = axis_B.ImSquaredNorm(); // d_B = Axis B double axis_AB = axis_B.Dot( axis_A ); // Scalar product axis_A and axis_B // Displacement between point on edge of this cuboid (A) and point on edge B // Quaternion p_AB = ptOn_A - ptOn_B; double dpSta_A = p_AB.Dot( axis_A ); double dpSta_B = p_AB.Dot( axis_B ); double denominator = sqNorm_dA * sqNorm_dB - axis_AB * axis_AB; // In case of parallel lines // if ( fabs( denominator ) < 1e-4 ) { return use_A ? ptOn_A : ptOn_B; } double mu_A = ( axis_AB * dpSta_B - sqNorm_dB * dpSta_A ) / denominator; double mu_B = ( sqNorm_dA * dpSta_B - axis_AB * dpSta_A ) / denominator; // If either of the edges has the nearest point out of bounds, // then the edges aren't crossed, we have an edge-face contact. // if ( mu_A > edge_A || mu_A < -edge_A || mu_B > edge_B || mu_B < -edge_B ) { // Our point is on the edge of body which we know from the use_A parameter. return use_A ? ptOn_A : ptOn_B; } else { return ( ptOn_A + axis_A * mu_A ) * 0.5 + ( ptOn_B + axis_B * mu_B ) * 0.5; } }
double WoRB::Cuboid::GetPenetrationOnAxis | ( | const Cuboid & | B, |
const Quaternion & | axis, | ||
const Quaternion & | displacement | ||
) | const [inline, private] |
Checks if this and another cuboid overlap along the given direction.
Definition at line 354 of file Geometry.h.
References WoRB::Quaternion::Dot(), ProjectOn(), and WoRB::Quaternion::Unit().
Referenced by CheckOverlapOnAxis(), and IsOverlapOnAxis().
{ Quaternion direction = axis.Unit (); // Project the half-extents and displacement onto axis double proj_A = ProjectOn( direction ); double proj_B = B.ProjectOn( direction ); double distance = fabs( displacement.Dot( direction ) ); // Return the overlap return proj_A + proj_B - distance; }
bool WoRB::Cuboid::Intersects | ( | const HalfSpace & | plane | ) | const [inline] |
Tests for intersection of the cuboid and a half-space.
Definition at line 272 of file Geometry.h.
References WoRB::HalfSpace::Direction, WoRB::Quaternion::Dot(), WoRB::HalfSpace::Offset, WoRB::Geometry::Position(), and ProjectOn().
Referenced by Check().
{ // Calculate the projected radius of the cuboid onto the plane direction double projectedRadius = ProjectOn( plane.Direction ); // Calculate how far the cuboid is from the origin double distance = plane.Direction.Dot( Position() ) - projectedRadius; // Check for the intersection return distance <= plane.Offset; }
bool WoRB::Cuboid::Intersects | ( | const Cuboid & | B | ) | const [inline] |
Tests for intersection between this and some other cuboid.
Definition at line 286 of file Geometry.h.
References WoRB::Geometry::Axis(), WoRB::Quaternion::Cross(), IsOverlapOnAxis(), and WoRB::Geometry::Position().
{ // Find the displacement between the centra of two cuboids // Quaternion displacement = B.Position() - Position(); // Now, first, check axes of A, then axes of B, and finally their cross products // return IsOverlapOnAxis( B, Axis(0), displacement ) && IsOverlapOnAxis( B, Axis(1), displacement ) && IsOverlapOnAxis( B, Axis(2), displacement ) && IsOverlapOnAxis( B, B.Axis(0), displacement ) && IsOverlapOnAxis( B, B.Axis(1), displacement ) && IsOverlapOnAxis( B, B.Axis(2), displacement ) && IsOverlapOnAxis( B, Axis(0).Cross( B.Axis(0) ), displacement ) && IsOverlapOnAxis( B, Axis(0).Cross( B.Axis(1) ), displacement ) && IsOverlapOnAxis( B, Axis(0).Cross( B.Axis(2) ), displacement ) && IsOverlapOnAxis( B, Axis(1).Cross( B.Axis(0) ), displacement ) && IsOverlapOnAxis( B, Axis(1).Cross( B.Axis(1) ), displacement ) && IsOverlapOnAxis( B, Axis(1).Cross( B.Axis(2) ), displacement ) && IsOverlapOnAxis( B, Axis(2).Cross( B.Axis(0) ), displacement ) && IsOverlapOnAxis( B, Axis(2).Cross( B.Axis(1) ), displacement ) && IsOverlapOnAxis( B, Axis(2).Cross( B.Axis(2) ), displacement ); }
bool WoRB::Cuboid::IsOverlapOnAxis | ( | const Cuboid & | B, |
const Quaternion & | direction, | ||
const Quaternion & | displacement | ||
) | const [inline, private] |
Checks if this and another cuboid overlap along the given direction.
Definition at line 371 of file Geometry.h.
References GetPenetrationOnAxis(), and WoRB::Quaternion::ImSquaredNorm().
Referenced by Intersects().
{ // Skip almost parallel axes. if ( direction.ImSquaredNorm() < 1e-4 ) { return true; } return GetPenetrationOnAxis( B, direction, displacement ) > 0; }
double WoRB::Cuboid::ProjectOn | ( | const Quaternion & | vector | ) | const [inline, private] |
Gets the sum of cuboid's half-extent's projections on the given vector.
Definition at line 344 of file Geometry.h.
References WoRB::Geometry::Axis(), WoRB::Quaternion::Dot(), HalfExtent, WoRB::Quaternion::x, WoRB::Quaternion::y, and WoRB::Quaternion::z.
Referenced by GetPenetrationOnAxis(), and Intersects().
{ return HalfExtent.x * fabs( vector.Dot( Axis(0) ) ) + HalfExtent.y * fabs( vector.Dot( Axis(1) ) ) + HalfExtent.z * fabs( vector.Dot( Axis(2) ) ); }
unsigned Cuboid::RegisterContactOnAxis | ( | CollisionResolver & | owner, |
const Cuboid & | B, | ||
const Quaternion & | displacement, | ||
const Quaternion & | axis, | ||
double | penetration | ||
) | const [private] |
Registers a contact between this and the other cuboid body along an axis.
Faster variant that does not check every vertex but the closest one.
owner | The collision registry |
B | The second cuboid |
displacement | The displacement between B and A centra |
axis | The axis of this couboid (cuboid A) |
penetration | The penetration depth |
Definition at line 283 of file CollisionDetection.cpp.
References WoRB::Geometry::Axis(), WoRB::Geometry::Body, WoRB::Quaternion::Dot(), HalfExtent, WoRB::CollisionResolver::RegisterNewContact(), and WoRB::RigidBody::ToWorld.
Referenced by Check().
{ // Find out which of the B faces is on the specified axis. // Quaternion normal = axis; if ( normal.Dot( displacement ) > 0 ) { normal = -normal; } Quaternion axis_Bn( 0, B.Axis(0).Dot( normal ), B.Axis(1).Dot( normal ), B.Axis(2).Dot( normal ) ); // Find out which vertex of cuboid B we are colliding with. Quaternion contactPointOn_B; // = zero for ( unsigned i = 0; i < 3; ++i ) // for each axis in B { // In case of B's edge that is almost normal to the contact normal // we take a mid-point of A's & B's edges intersection projected on B.Axis(i). // Otherwise, if not normal, we take the vertex which is the closest. // if ( fabs( axis_Bn[i] ) < 1e-4 ) { // Project the A's half-extents and displacement onto B's axis // deltaCenter +/- halfExtent_A describes A's vertices in B's frame of ref. // double distance_BA = -displacement.Dot( B.Axis(i) ); double halfExtent_A = ProjectOn( B.Axis(i) ); double halfExtent_B = B.HalfExtent[i]; // Get mid-point of A's & B's projections' intersection on B's axis // double vxL = std::max( distance_BA - halfExtent_A, -halfExtent_B ); double vxR = std::min( distance_BA + halfExtent_A, halfExtent_B ); double vxM = 0.5 * ( vxL + vxR ); contactPointOn_B[i] = fabs( vxM ) < 1e-4 ? 0 : vxM; } else // if B's edge is not almost normal to the contact normal { // Select the closest vertex // contactPointOn_B[i] = axis_Bn[i] > 0 ? B.HalfExtent[i] : -B.HalfExtent[i]; } } // No parallel axes with faces found; single collision point // return owner.RegisterNewContact( /* a */ Body, /* b */ B.Body, /* X */ B.Body->ToWorld( contactPointOn_B ), /* N */ normal, /* d */ penetration ); }
unsigned Cuboid::RegisterContactOnAxis_Thorough | ( | CollisionResolver & | owner, |
const Cuboid & | B, | ||
const Quaternion & | displacement, | ||
unsigned | axis | ||
) | const [private] |
Registers a contact between this and the other cuboid body along an axis.
owner | The collision registry |
B | The second cuboid |
displacement | The displacement between B and A centra |
axis | A's axis |
Definition at line 228 of file CollisionDetection.cpp.
References WoRB::Geometry::Body, WoRB::Quaternion::ComponentWiseProduct(), WoRB::Quaternion::Dot(), HalfExtent, WoRB::CollisionResolver::HasSpaceForMoreContacts(), WoRB::CollisionResolver::RegisterNewContact(), and WoRB::RigidBody::ToWorld.
{ Quaternion En = Axis( axis ); bool onRight = En.Dot( displacement ) > 0; // Go through each combination of +/- for each half-size // unsigned contactCount = 0; for ( unsigned i = 0; i < 8 && owner.HasSpaceForMoreContacts (); ++i ) { // Calculate the position of each vertex // static const double vertices[8][3] = { { 1, 1, 1 }, { -1, 1, 1 }, { 1, -1, 1 }, { -1, -1, 1 }, { 1, 1, -1 }, { -1, 1, -1 }, { 1, -1, -1 }, { -1, -1, -1 } }; Quaternion vertexPos( 0, vertices[i][0], vertices[i][1], vertices[i][2] ); vertexPos = vertexPos.ComponentWiseProduct( B.HalfExtent ); vertexPos = B.Body->ToWorld( vertexPos ); // Calculate the distance between the B's vertex and the A's center // projected on A's axis // double distance = ( vertexPos - Position() ).Dot( En ); // Compare this to the A's face distance from A's center // if ( ( onRight && distance <= HalfExtent[ axis ] ) || ( !onRight && distance >= -HalfExtent[ axis ] ) ) { // New contact with the vertex as the point of contact // contactCount += owner.RegisterNewContact( /* a */ Body, /* b */ B.Body, /* X */ vertexPos, /* N */ onRight ? -En : En, /* d */ onRight ? HalfExtent[ axis ] - distance : distance - HalfExtent[ axis ] ); } } return contactCount; }
void WoRB::Cuboid::SetMass | ( | double | mass | ) | [inline] |
Sets body mass and principal moment of inertia of the cuboid.
Definition at line 252 of file Geometry.h.
References WoRB::Geometry::Body, WoRB::RigidBody::CalculateDerivedQuantities(), WoRB::Quaternion::ComponentWiseProduct(), HalfExtent, WoRB::RigidBody::SetMomentOfInertia(), WoRB::RigidBody::SetupMass(), WoRB::Quaternion::x, WoRB::Quaternion::y, and WoRB::Quaternion::z.
Referenced by WoRB::Box::Box(), and WoRB_TestBed::ReconfigureTestBed().
{ Body->SetupMass( mass ); Quaternion extent = 2.0 * HalfExtent; Quaternion sq = extent.ComponentWiseProduct( extent ); Body->SetMomentOfInertia( QTensor( mass * ( sq.y + sq.z ) / 12, mass * ( sq.x + sq.z ) / 12, mass * ( sq.x + sq.y ) / 12 ) ); Body->CalculateDerivedQuantities( /*fromMomenta*/ false ); }
double WoRB::Cuboid::Volume | ( | ) | const [inline] |
Gets the volume of the cuboid.
Definition at line 245 of file Geometry.h.
References HalfExtent, WoRB::Quaternion::x, WoRB::Quaternion::y, and WoRB::Quaternion::z.
{ return 8.0 * HalfExtent.x * HalfExtent.y * HalfExtent.z; }
Holds the half-extent of the cuboid along each of its local axes.
Definition at line 241 of file Geometry.h.
Referenced by WoRB::Box::Box(), Check(), WoRB_TestBed::Dump(), ProjectOn(), RegisterContactOnAxis(), RegisterContactOnAxis_Thorough(), WoRB::Box::Render(), WoRB::Box::RenderWireframe(), SetMass(), and Volume().