/******************************************************************/ /* 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; }