fixed Box::Extend(Vec3f&)
[MicroTrace.git] / Box.cxx
1 #include "Box.hxx"
2 #include "InfinitePlane.hxx"
3
4 Box::Box() : m_min(Infinity, Infinity, Infinity),
5 m_max(-Infinity, -Infinity, -Infinity)
6 {
7 }
8
9 Box::Box(Vec3f min, Vec3f max) : m_min(min), m_max(max)
10 {
11 }
12
13 Box::~Box()
14 {
15 }
16
17 Box::Box(const Box& b)
18 {
19 m_min = b.m_min;
20 m_max = b.m_max;
21 }
22
23 Box&
24 Box::operator=(const Box& b)
25 {
26 m_min = b.m_min;
27 m_max = b.m_max;
28 return *this;
29 }
30
31 void
32 Box::Clear()
33 {
34 m_min = Vec3f(Infinity, Infinity, Infinity);
35 m_max = Vec3f(-Infinity, -Infinity, -Infinity);
36 }
37
38 void
39 Box::Extend(const Vec3f& a)
40 {
41 // for all three coordinates, move m_max or m_min to the point
42 for(size_t i = 0; i < 3; i++) {
43 if(a[i] > m_max[i]) {
44 m_max[i] = a[i];
45 }
46 if(a[i] < m_min[i]) {
47 m_min[i] = a[i];
48 } // else: do nothing, coordinate is inside the box
49 }
50 }
51
52 void
53 Box::Extend(const Box& box)
54 {
55 Extend(box.min());
56 Extend(box.max());
57 }
58
59 bool Box::OverlapsHelper(Box b) const {
60 bool overlaps = true;
61 for(size_t i = 0; i < 3; i++) {
62 overlaps &=
63 (m_min[i] < b.min()[i] && b.min()[i] < m_max[i]) ||
64 (m_min[i] < b.max()[i] && b.min()[i] < m_max[i]) ||
65 (m_min[i] > b.min()[i] && b.min()[i] > m_max[i]) ||
66 (m_min[i] > b.max()[i] && b.min()[i] > m_max[i]);
67 }
68 return overlaps;
69 }
70
71 bool
72 Box::Overlaps(const Box& b) const
73 {
74 // Boxes overlap if b.m_min or b.m_max are between our m_max and m_min
75 // for all dimensions
76 bool overlaps = OverlapsHelper(b);
77
78 // if that is not enough, swap y coordinates, we could have the following
79 // (sample for 2-dimensional case):
80 // o----------
81 // | | + denotes crossing,
82 // -----+----o | o denotes min/max point
83 // | | | |
84 // | -----+----o
85 // | |
86 // o----------
87 if(!overlaps) {
88 Vec3f min = b.min();
89 Vec3f max = b.max();
90 Vec3f new_min(min[0], max[1], min[2]);
91 Vec3f new_max(max[0], min[1], max[2]);
92 Box new_y_box(new_min, new_max);
93 overlaps = OverlapsHelper(new_y_box);
94
95 // and now for y and z coordinates also
96 if(!overlaps) {
97 min = new_y_box.min();
98 max = new_y_box.max();
99 new_min = Vec3f(min[0], min[1], max[2]);
100 new_max = Vec3f(max[0], max[1], min[2]);
101 Box new_yz_box(new_min, new_max);
102 overlaps = OverlapsHelper(new_yz_box);
103
104 // and now for only z coordinates
105 if(!overlaps) {
106 min = new_y_box.min();
107 max = new_y_box.max();
108 new_min = Vec3f(min[0], max[1], min[2]);
109 new_max = Vec3f(max[0], min[1], max[2]);
110 Box new_z_box(new_min, new_max);
111 overlaps = OverlapsHelper(new_z_box);
112 // at this point, we do not need to swap further, as either m_max or
113 // m_min has been tested inside b.
114 }
115 }
116 }
117
118 return overlaps;
119 }
120
121 void
122 Box::Clip(const Ray& ray, float& tnear, float& tfar) const
123 {
124 // Note: equations here are the same as in InfinitePlane::Intersect()
125 // t = ((o-a)*n) / (d*n)
126 // o = ray.origin(), d = ray.direction(),
127 // n = surface normal of plane, a = anchor point of plane
128 Vec3f diff_min = m_min - ray.origin(); // o-a
129 Vec3f diff_max = m_max - ray.origin();
130
131 float cos_theta, temp;
132 float tx_near = -Infinity, tx_far = Infinity,
133 ty_near = -Infinity, ty_far = Infinity,
134 tz_near = -Infinity, tz_far = Infinity;
135
136 // clip along x axis
137 if((cos_theta = ray.direction().dot(Vec3f(1,0,0))) != 0) // if not parallel...
138 tx_near = diff_min.dot(Vec3f(1,0,0)) / cos_theta;
139 if((cos_theta = ray.direction().dot(Vec3f(1,0,0))) != 0)
140 tx_far = diff_max.dot(Vec3f(1,0,0)) / cos_theta;
141
142 // we don't know which is nearer, m_min or m_max, so swap them if neccessary
143 if(tx_near > tx_far) {
144 temp = tx_near;
145 tx_near = tx_far;
146 tx_far = temp;
147 }
148
149 // do the same for y axis
150 if((cos_theta = ray.direction().dot(Vec3f(0,1,0))) != 0)
151 ty_near = diff_min.dot(Vec3f(0,1,0)) / cos_theta;
152 if((cos_theta = ray.direction().dot(Vec3f(0,1,0))) != 0)
153 ty_far = diff_max.dot(Vec3f(0,1,0)) / cos_theta;
154 if(ty_near > ty_far) {
155 temp = ty_near;
156 ty_near = ty_far;
157 ty_far = temp;
158 }
159
160 // ...and for z axis
161 if((cos_theta = ray.direction().dot(Vec3f(0,0,1))) != 0)
162 tz_near = diff_min.dot(Vec3f(0,0,1)) / cos_theta;
163 if((cos_theta = ray.direction().dot(Vec3f(0,0,1))) != 0)
164 tz_far = diff_max.dot(Vec3f(0,0,1)) / cos_theta;
165 if(tz_near > tz_far) {
166 temp = tz_near;
167 tz_near = tz_far;
168 tz_far = temp;
169 }
170
171 // now the maximum of "near"s is the entry point of the ray, the minimum
172 // of "far"s is the ray's exit point. Visually speaking: the ray must cross
173 // all three "near" planes before it can be inside the box.
174 // Note: If t_near_max > t_far_min, the ray does not intersect the box
175 tnear = fmax(fmax(tx_near, ty_near), tz_near);
176 tfar = fmin(fmin(tx_far, ty_far), tz_far);
177 }
178
179 const Vec3f&
180 Box::min() const
181 {
182 return m_min;
183 }
184
185 const Vec3f&
186 Box::max() const
187 {
188 return m_max;
189 }
This page took 0.075177 seconds and 5 git commands to generate.