blob: 96b22615bcdf340df058a321bce435c5ac055d12 (
plain) (
tree)
|
|
/******************************************************************/
/* This file is part of the homework assignments for CSCI-427/527 */
/* at The College of William & Mary and authored by Pieter Peers. */
/* No part of this file, whether altered or in original form, can */
/* be distributed or used outside the context of CSCI-427/527 */
/* without consent of either the College of William & Mary or */
/* Pieter Peers. */
/******************************************************************/
#include "interval.h"
#include "constants.h"
#include "boundingBox.h"
/////////////////
// Constructor //
/////////////////
boundingBox::boundingBox(void)
{
// create an empty box (i.e., 'left' lies right of 'right')
_lfb = vec3d(+LARGE);
_rbt = vec3d(-LARGE);
}
boundingBox::boundingBox(const vec3d& lfb, const vec3d& rbt)
{
_lfb = lfb;
_rbt = rbt;
// Make sure each component in _lfb is smaller than _rbt
for(unsigned int i=0; i < vec3d::size(); i++)
if(_rbt[i] < _lfb[i]) std::swap(_rbt[i], _lfb[i]);
// Done.
}
boundingBox::boundingBox(const boundingBox& bb)
{
_lfb = bb._lfb;
_rbt = bb._rbt;
}
//////////////
// Operator //
//////////////
boundingBox& boundingBox::operator=(const boundingBox& src)
{
_assign(src);
return *this;
}
boundingBox& boundingBox::operator+=(const boundingBox& bb)
{
// compute the union of two bounding boxes
for(unsigned int i=0; i < vec3d::size(); i++)
{
if(_lfb[i] > bb._lfb[i]) _lfb[i] = bb._lfb[i];
if(_rbt[i] < bb._rbt[i]) _rbt[i] = bb._rbt[i];
}
return *this;
}
boundingBox boundingBox::operator+(const boundingBox& bb) const
{
boundingBox result(*this);
result += bb;
return result;
}
boundingBox& boundingBox::operator+=(const vec3d& point)
{
// expand the bounding box to include 'point' (+ a small epsilon)
for(unsigned int i=0; i < vec3d::size(); i++)
{
if(_lfb[i] > point[i]-EPSILON) _lfb[i] = point[i]-EPSILON;
if(_rbt[i] < point[i]+EPSILON) _rbt[i] = point[i]+EPSILON;
}
return *this;
}
/////////////
// Methods //
/////////////
bool boundingBox::isHit(const ray& r) const
{
// init
interval boxInterval(0, +LARGE);
// for every slab
for(unsigned int i=0; i != vec3d::size(); i++)
{
// compute the slab
interval slab(_lfb[i], _rbt[i]);
slab -= r.origin()[i];
// check for the case where the ray is parallel to the slab
if(fabs(r.direction()[i]) < EPSILON)
{
// if identical signs => no hit
if((slab.lower() < 0.0f) == (slab.upper() < 0.0f))
return false;
// skip remainder to this iteration
continue;
}
else
slab /= r.direction()[i];
// intersect
boxInterval.intersect(slab);
if(boxInterval.empty())
return false;
}
// Done.
return true;
}
vec3d boundingBox::center(void) const
{
return 0.5f * (_lfb + _rbt);
}
vec3d boundingBox::corner(bool left, bool front, bool bottom) const
{
return vec3d( left ? _lfb.x : _rbt.x,
front ? _lfb.y : _rbt.y,
bottom ? _lfb.z : _rbt.z );
}
vec3d boundingBox::size(void) const
{
vec3d s = (_rbt - _lfb);
if(s.x < 0 || s.y < 0 || s.z < 0) return vec3d();
else return s;
}
//////////////
// Mutators //
//////////////
boundingBox& boundingBox::transform(const transformation3d& t)
{
boundingBox result;
for(unsigned int i=0; i <= 1; i++)
for(unsigned int j=0; j <= 1; j++)
for(unsigned int k=0; k <= 1; k++)
result += t.transformPoint(corner(i,j,k));
// Done.
_swap(result);
return *this;
}
boundingBox& boundingBox::inverseTransform(const transformation3d& t)
{
boundingBox result;
for(unsigned int i=0; i <= 1; i++)
for(unsigned int j=0; j <= 1; j++)
for(unsigned int k=0; k <= 1; k++)
result += t.inverseTransformPoint(corner(i,j,k));
// Done.
_swap(result);
return *this;
}
/////////////////////
// Private Methods //
/////////////////////
void boundingBox::_swap(boundingBox& bb)
{
swap(_lfb, bb._lfb);
swap(_rbt, bb._rbt);
}
void boundingBox::_assign(const boundingBox& bb)
{
_lfb = bb._lfb;
_rbt = bb._rbt;
}
|