forked from 0ad/0ad
162 lines
3.7 KiB
C++
162 lines
3.7 KiB
C++
|
#include "BoundingObjects.h"
|
||
|
|
||
|
bool CBoundingObject::intersects( CBoundingObject* obj )
|
||
|
{
|
||
|
CVector2D delta = pos - obj->pos;
|
||
|
if( !delta.within( trivialRejectionRadius + obj->trivialRejectionRadius ) )
|
||
|
return( false );
|
||
|
|
||
|
if( obj->type > type )
|
||
|
{
|
||
|
return( obj->_intersects( this, &delta ) );
|
||
|
}
|
||
|
else
|
||
|
return( _intersects( obj, &delta ) );
|
||
|
}
|
||
|
|
||
|
void CBoundingCircle::setPosition( float _x, float _y )
|
||
|
{
|
||
|
pos.x = _x; pos.y = _y;
|
||
|
}
|
||
|
|
||
|
void CBoundingCircle::setRadius( float _radius )
|
||
|
{
|
||
|
r = _radius;
|
||
|
trivialRejectionRadius = _radius * _radius;
|
||
|
}
|
||
|
|
||
|
bool CBoundingCircle::_intersects( CBoundingObject* obj, CVector2D* delta )
|
||
|
{
|
||
|
// Easy enough. Trivial rejection is sufficient.
|
||
|
return( true );
|
||
|
}
|
||
|
|
||
|
CBoundingBox::CBoundingBox( float _x, float _y, float _orientation, float _width, float _height )
|
||
|
{
|
||
|
setPosition( _x, _y );
|
||
|
setDimensions( _width, _height );
|
||
|
setOrientation( _orientation );
|
||
|
}
|
||
|
|
||
|
void CBoundingBox::setPosition( float _x, float _y )
|
||
|
{
|
||
|
pos.x = _x; pos.y = _y;
|
||
|
}
|
||
|
|
||
|
void CBoundingBox::setDimensions( float _width, float _height )
|
||
|
{
|
||
|
w = _width / 2.0f;
|
||
|
h = _height / 2.0f;
|
||
|
trivialRejectionRadius = ( w * w ) + ( h * h );
|
||
|
}
|
||
|
|
||
|
void CBoundingBox::setOrientation( float _orientation )
|
||
|
{
|
||
|
u.x = sin( _orientation );
|
||
|
u.y = cos( _orientation );
|
||
|
v.x = u.y;
|
||
|
v.y = -u.x;
|
||
|
}
|
||
|
|
||
|
bool CBoundingBox::_intersects( CBoundingObject* obj, CVector2D* delta )
|
||
|
{
|
||
|
if( obj->type == BOUND_CIRCLE )
|
||
|
{
|
||
|
// Imperfect but quick...
|
||
|
|
||
|
CBoundingCircle* c = (CBoundingCircle*)obj;
|
||
|
float deltah = fabs( delta->dot( u ) );
|
||
|
if( deltah > ( h + c->r ) ) return( false );
|
||
|
float deltaw = fabs( delta->dot( v ) );
|
||
|
if( deltaw > ( w + c->r ) ) return( false );
|
||
|
return( true );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Another OABB:
|
||
|
|
||
|
// Seperable axis theorem. (Optimizations: Algorithmic done, really low-level stuff not.)
|
||
|
// Debugging this can often be quite entertaining.
|
||
|
|
||
|
CBoundingBox* b = (CBoundingBox*)obj;
|
||
|
|
||
|
// SAT in a nutshell: If two boxes are disjoint, there's an axis where their projections don't overlap
|
||
|
// That axis (in 2D) will run parallel to a side of one of the boxes
|
||
|
|
||
|
// This code computes projections of boxes onto each axis in turn - hopefully quickly
|
||
|
// then does simple max/min checks to determine overlap
|
||
|
|
||
|
// uv, vu, uu, vv are dot-products of our u- and v- axes of each box.
|
||
|
// prj1, prj2 are two coordinates locating the projections of two corners of a box onto an axis.
|
||
|
// dm is the distance between the boxes, projected onto the axis.
|
||
|
|
||
|
// Lots of nice symmetries used to help speed things up
|
||
|
|
||
|
// Note that a trivial-rejection test has already taken place by this point.
|
||
|
|
||
|
float uv, vu, uu, vv, prj1, prj2, dm;
|
||
|
uv = u.dot( b->v );
|
||
|
vu = v.dot( b->u );
|
||
|
uu = u.dot( b->u );
|
||
|
vv = v.dot( b->v );
|
||
|
|
||
|
// Project box 2 onto v-axis of box 1
|
||
|
|
||
|
prj1 = fabs( vu * b->h + vv * b->w );
|
||
|
prj2 = fabs( vu * b->h - vv * b->h );
|
||
|
dm = delta->dot( v );
|
||
|
|
||
|
if( prj1 > prj2 )
|
||
|
{
|
||
|
if( ( dm - prj1 ) > w ) return( false );
|
||
|
}
|
||
|
else
|
||
|
if( ( dm - prj2 ) > w ) return( false );
|
||
|
|
||
|
// Project box 2 onto u-axis of box 1
|
||
|
|
||
|
prj1 = fabs( uu * b->h + uv * b->w );
|
||
|
prj2 = fabs( uu * b->h - uv * b->w );
|
||
|
dm = delta->dot( u );
|
||
|
|
||
|
if( prj1 > prj2 )
|
||
|
{
|
||
|
if( ( dm - prj1 ) > h ) return( false );
|
||
|
}
|
||
|
else
|
||
|
if( ( dm - prj2 ) > h ) return( false );
|
||
|
|
||
|
// Project box 1 onto v-axis of box 2
|
||
|
|
||
|
prj1 = fabs( uv * h + vv * w );
|
||
|
prj2 = fabs( uv * h - vv * w );
|
||
|
|
||
|
if( prj1 > prj2 )
|
||
|
{
|
||
|
if( ( dm - prj1 ) > b->w ) return( false );
|
||
|
}
|
||
|
else
|
||
|
if( ( dm - prj2 ) > b->w ) return( false );
|
||
|
|
||
|
// Project box 1 onto u-axis of box 2
|
||
|
|
||
|
prj1 = fabs( uu * h + vu * w );
|
||
|
prj2 = fabs( uu * h - vu * w );
|
||
|
|
||
|
if( prj1 > prj2 )
|
||
|
{
|
||
|
if( ( dm - prj1 ) > b->h ) return( false );
|
||
|
}
|
||
|
else
|
||
|
if( ( dm - prj2 ) > b->h ) return( false );
|
||
|
|
||
|
// And a partridge in a pear tree...
|
||
|
|
||
|
return( true );
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|