summaryrefslogblamecommitdiff
path: root/hw6/src/boundingBox.cpp
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;
}