summaryrefslogtreecommitdiff
path: root/hw2/src/boundingBox.cpp
blob: 9708093539a5596c3c657a839aa7cbc23d178403 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/******************************************************************/
/* 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;
  }
}


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


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