World of Rigid Bodies (WoRB)
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
WoRB::Cuboid Class Reference

Encapsulates a cuboid (rectangular parallelepiped). More...

#include <Geometry.h>

Inheritance diagram for WoRB::Cuboid:
Collaboration diagram for WoRB::Cuboid:

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.

Detailed Description

Encapsulates a cuboid (rectangular parallelepiped).

Definition at line 230 of file Geometry.h.


Constructor & Destructor Documentation

WoRB::Cuboid::Cuboid ( ) [inline]

Definition at line 234 of file Geometry.h.


Member Function Documentation

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.

Parameters:
pt_APoint on the edge of the cuboid A
axis_AAxis of the cuboid A
size_AHalf-extent of A's axis
pt_BPoint on the edge of the cuboid B
axis_BAxis of the cuboid B
size_BHalf-extent of B's axis
use_AWhich 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.

Returns:
The ammount of penetration, where positive value indicates overlap.

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.

Returns:
1 if ok, 0 if failed to allocate space for the contact.
Parameters:
ownerThe collision registry
BThe second cuboid
displacementThe displacement between B and A centra
axisThe axis of this couboid (cuboid A)
penetrationThe 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.

Returns:
1 if ok, 0 if failed to allocate space for the contact.
Parameters:
ownerThe collision registry
BThe second cuboid
displacementThe displacement between B and A centra
axisA'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;
        }

Field Documentation


The documentation for this class was generated from the following files: