1 /*
2 Copyright (C) 2010-2014 Kristian Duske
3
4 This file is part of TrenchBroom.
5
6 TrenchBroom is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 TrenchBroom is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifndef TrenchBroom_BBox_h
21 #define TrenchBroom_BBox_h
22
23 #include "Mat.h"
24 #include "Plane.h"
25 #include "Quat.h"
26 #include "Vec.h"
27
28 template <typename T, size_t S>
29 class BBox {
30 public:
31 typedef enum {
32 Corner_Min,
33 Corner_Max
34 } Corner;
35
36 class RelativePosition {
37 public:
38 typedef enum {
39 Range_Less,
40 Range_Within,
41 Range_Greater
42 } Range;
43 private:
44 Range m_positions[S];
45 public:
RelativePosition(const Range positions[S])46 RelativePosition(const Range positions[S]) {
47 for (size_t i = 0; i < S; ++i)
48 m_positions[i] = positions[i];
49 }
50
51 const Range& operator[] (const size_t index) const {
52 assert(index >= 0 && index < S);
53 return m_positions[index];
54 }
55 };
56
57 Vec<T,S> min;
58 Vec<T,S> max;
59
BBox()60 BBox() :
61 min(Vec<T,S>::Null),
62 max(Vec<T,S>::Null) {}
63
BBox(const Vec<T,S> & i_min,const Vec<T,S> & i_max)64 BBox(const Vec<T,S>& i_min, const Vec<T,S>& i_max) :
65 min(i_min),
66 max(i_max) {}
67
BBox(const T i_minMax)68 BBox(const T i_minMax) {
69 min.set(-i_minMax);
70 max.set(+i_minMax);
71 }
72
BBox(const T i_min,const T i_max)73 BBox(const T i_min, const T i_max) {
74 min.set(i_min);
75 max.set(i_max);
76 }
77
BBox(const Vec<T,S> & center,const T size)78 BBox(const Vec<T,S>& center, const T size) {
79 for (size_t i = 0; i < S; ++i) {
80 min[i] = center[i] - size;
81 max[i] = center[i] + size;
82 }
83 }
84
BBox(const typename Vec<T,S>::List & vertices)85 BBox(const typename Vec<T,S>::List& vertices) {
86 assert(vertices.size() > 0);
87 min = max = vertices[0];
88 for (size_t i = 0; i < vertices.size(); ++i)
89 mergeWith(vertices[i]);
90 }
91
92 template <typename I, typename G>
BBox(I cur,I end,G get)93 BBox(I cur, I end, G get) {
94 assert(cur != end);
95 min = max = get(*cur++);
96 while (cur != end)
97 mergeWith(get(*cur++));
98 }
99
100 template <typename U>
BBox(const BBox<U,S> & other)101 BBox(const BBox<U,S>& other) :
102 min(other.min),
103 max(other.max) {}
104
105 bool operator==(const BBox<T,S>& right) const {
106 return min == right.min && max == right.max;
107 }
108
109 bool operator!= (const BBox<T,S>& right) const {
110 return min != right.min || max != right.max;
111 }
112
empty()113 bool empty() const {
114 for (size_t i = 0; i < S; ++i)
115 if (min[i] >= max[i])
116 return true;
117 return false;
118 }
119
center()120 const Vec<T,S> center() const {
121 return (min + max) / static_cast<T>(2.0);
122 }
123
size()124 const Vec<T,S> size() const {
125 return max - min;
126 }
127
vertex(const Corner c[S])128 const Vec<T,S> vertex(const Corner c[S]) const {
129 Vec<T,S> result;
130 for (size_t i = 0; i < S; ++i)
131 result[i] = c[i] == Corner_Min ? min[i] : max[i];
132 return result;
133 }
134
vertex(const Corner x,const Corner y,const Corner z)135 const Vec<T,3> vertex(const Corner x, const Corner y, const Corner z) const {
136 Corner c[] = { x, y, z };
137 return vertex(c);
138 }
139
mergeWith(const BBox<T,S> & right)140 BBox<T,S>& mergeWith(const BBox<T,S>& right) {
141 for (size_t i = 0; i < S; ++i) {
142 min[i] = std::min(min[i], right.min[i]);
143 max[i] = std::max(max[i], right.max[i]);
144 }
145 return *this;
146 }
147
mergedWith(const BBox<T,S> & right)148 const BBox<T,S> mergedWith(const BBox<T,S>& right) const {
149 return BBox<T,S>(*this).mergeWith(right);
150 }
151
152
mergeWith(const Vec<T,S> & right)153 BBox<T,S>& mergeWith(const Vec<T,S>& right) {
154 for (size_t i = 0; i < S; ++i) {
155 min[i] = std::min(min[i], right[i]);
156 max[i] = std::max(max[i], right[i]);
157 }
158 return *this;
159 }
160
mergedWith(const Vec<T,S> & right)161 const BBox<T,S> mergedWith(const Vec<T,S>& right) const {
162 return BBox<T,S>(*this).mergeWith(right);
163 }
164
intersectWith(const BBox<T,S> & right)165 BBox<T,S>& intersectWith(const BBox<T,S>& right) {
166 for (size_t i = 0; i < S; ++i) {
167 min[i] = std::max(min[i], right.min[i]);
168 max[i] = std::min(max[i], right.max[i]);
169 }
170 return *this;
171 }
172
intersectedWith(const BBox<T,S> & right)173 const BBox<T,S> intersectedWith(const BBox<T,S>& right) const {
174 return BBox<T,S>(*this).insersectWith(right);
175 }
176
mix(const BBox<T,S> & box,const Vec<T,S> & factor)177 BBox<T,S>& mix(const BBox<T,S>& box, const Vec<T,S>& factor) {
178 min.mix(box.min, factor);
179 max.mix(box.max, factor);
180 return *this;
181 }
182
mixed(const BBox<T,S> & box,const Vec<T,S> & factor)183 BBox<T,S> mixed(const BBox<T,S>& box, const Vec<T,S>& factor) const {
184 return BBox<T,S>(*this).mix(box, factor);
185 }
186
translateToOrigin()187 BBox<T,S>& translateToOrigin() {
188 const Vec<T,S> c = center();
189 min -= c;
190 max -= c;
191 return *this;
192 }
193
translatedToOrigin()194 const BBox<T,S> translatedToOrigin() const {
195 return BBox<T,S>(*this).translateToOrigin();
196 }
197
repair()198 BBox<T,S>& repair() {
199 using std::swap;
200 for (size_t i = 0; i < S; ++i)
201 if (min[i] > max[i])
202 swap(min[i], max[i]);
203 return *this;
204 }
205
repaired()206 const BBox<T,S> repaired() const {
207 return BBox<T,S>(*this).repair();
208 }
209
contains(const Vec<T,S> & point)210 bool contains(const Vec<T,S>& point) const {
211 for (size_t i = 0; i < S; ++i)
212 if (point[i] < min[i] || point[i] > max[i])
213 return false;
214 return true;
215 }
216
relativePosition(const Vec<T,S> & point)217 const RelativePosition relativePosition(const Vec<T,S>& point) const {
218 typename RelativePosition::Range p[S];
219 for (size_t i = 0; i < S; ++i) {
220 if (point[i] < min[i])
221 p[i] = RelativePosition::Range_Less;
222 else if (point[i] > max[i])
223 p[i] = RelativePosition::Range_Greater;
224 else
225 p[i] = RelativePosition::Range_Within;
226 }
227
228 return RelativePosition(p);
229 }
230
contains(const BBox<T,S> & bounds)231 bool contains(const BBox<T,S>& bounds) const {
232 for (size_t i = 0; i < S; ++i)
233 if (bounds.min[i] < min[i] || bounds.max[i] > max[i])
234 return false;
235 return true;
236 }
237
intersects(const BBox<T,S> & bounds)238 bool intersects(const BBox<T,S>& bounds) const {
239 for (size_t i = 0; i < S; ++i)
240 if (bounds.max[i] < min[i] || bounds.min[i] > max[i])
241 return false;
242 return true;
243
244 }
245
246 T intersectWithRay(const Ray<T,S>& ray, Vec<T,S>* sideNormal = NULL) const {
247 const bool inside = contains(ray.origin);
248
249 for (size_t i = 0; i < S; ++i) {
250 if (ray.direction[i] == static_cast<T>(0.0))
251 continue;
252
253 Vec<T,S> normal, position;
254 normal[i] = ray.direction[i] < static_cast<T>(0.0) ? static_cast<T>(1.0) : static_cast<T>(-1.0);
255 if (inside)
256 position = ray.direction[i] < static_cast<T>(0.0) ? min : max;
257 else
258 position = ray.direction[i] < static_cast<T>(0.0) ? max : min;
259
260 const Plane<T,S> plane(position, normal);
261 const T distance = plane.intersectWithRay(ray);
262 if (Math::isnan(distance))
263 continue;
264
265 const Vec<T,S> point = ray.pointAtDistance(distance);
266 for (size_t j = 0; j < S; ++j)
267 if (i != j && !Math::between(point[j], min[j], max[j]))
268 goto cont;
269
270 if (sideNormal != NULL)
271 *sideNormal = inside ? -normal : normal;
272 return distance;
273
274 cont:;
275 }
276
277 return std::numeric_limits<T>::quiet_NaN();
278 }
279
expand(const T f)280 BBox<T,S>& expand(const T f) {
281 for (size_t i = 0; i < S; ++i) {
282 min[i] -= f;
283 max[i] += f;
284 }
285 return *this;
286 }
287
expanded(const T f)288 const BBox<T,S> expanded(const T f) const {
289 return BBox<T,S>(*this).expand(f);
290 }
291
translate(const Vec<T,S> & delta)292 BBox<T,S>& translate(const Vec<T,S>& delta) {
293 min += delta;
294 max += delta;
295 return *this;
296 }
297
translated(const Vec<T,S> & delta)298 const BBox<T,S> translated(const Vec<T,S>& delta) const {
299 return BBox<T,S>(*this).translate(delta);
300 }
301 };
302
303 template <typename T, class Op>
eachBBoxFace(const BBox<T,3> & bbox,Op & op)304 void eachBBoxFace(const BBox<T,3>& bbox, Op& op) {
305 const Vec<T,3> size = bbox.size();
306 const Vec<T,3> x(size.x(), static_cast<T>(0.0), static_cast<T>(0.0));
307 const Vec<T,3> y(static_cast<T>(0.0), size.y(), static_cast<T>(0.0));
308 const Vec<T,3> z(static_cast<T>(0.0), static_cast<T>(0.0), size.z());
309
310 op(bbox.max, bbox.max - y, bbox.max - y - x, bbox.max - x, Vec<T,3>( 0.0, 0.0, +1.0)); // top
311 op(bbox.min, bbox.min + x, bbox.min + x + y, bbox.min + y, Vec<T,3>( 0.0, 0.0, -1.0)); // bottom
312 op(bbox.min, bbox.min + z, bbox.min + z + x, bbox.min + x, Vec<T,3>( 0.0, -1.0, 0.0)); // front
313 op(bbox.max, bbox.max - x, bbox.max - x - z, bbox.max - z, Vec<T,3>( 0.0, +1.0, 0.0)); // back
314 op(bbox.min, bbox.min + y, bbox.min + y + z, bbox.min + z, Vec<T,3>(-1.0, 0.0, 0.0)); // left
315 op(bbox.max, bbox.max - z, bbox.max - z - y, bbox.max - y, Vec<T,3>(+1.0, 0.0, 0.0)); // right
316 }
317
318 template <typename T, class Op>
eachBBoxEdge(const BBox<T,3> & bbox,Op & op)319 void eachBBoxEdge(const BBox<T,3>& bbox, Op& op) {
320 const Vec<T,3> size = bbox.size();
321 const Vec<T,3> x(size.x(), static_cast<T>(0.0), static_cast<T>(0.0));
322 const Vec<T,3> y(static_cast<T>(0.0), size.y(), static_cast<T>(0.0));
323 const Vec<T,3> z(static_cast<T>(0.0), static_cast<T>(0.0), size.z());
324
325 Vec<T,3> v1, v2;
326
327 // top edges clockwise (viewed from above)
328 op(bbox.max, bbox.max - y );
329 op(bbox.max - y, bbox.max - y - x);
330 op(bbox.max - y - x, bbox.max - x );
331 op(bbox.max - x, bbox.max );
332
333 // bottom edges clockwise (viewed from below)
334 op(bbox.min, bbox.min + x );
335 op(bbox.min + x, bbox.min + x + y);
336 op(bbox.min + x + y, bbox.min + y );
337 op(bbox.min + y, bbox.min );
338
339 // side edges clockwise (viewed from above)
340 op(bbox.min, bbox.min + z );
341 op(bbox.min + y, bbox.min + y + z );
342 op(bbox.min + x + y, bbox.min + x + y + z);
343 op(bbox.min + x, bbox.min + x + z );
344 }
345
346 template <typename T>
bBoxVertices(const BBox<T,3> & bbox)347 typename Vec<T,3>::List bBoxVertices(const BBox<T,3>& bbox) {
348 const Vec<T,3> size = bbox.size();
349 const Vec<T,3> x(size.x(), static_cast<T>(0.0), static_cast<T>(0.0));
350 const Vec<T,3> y(static_cast<T>(0.0), size.y(), static_cast<T>(0.0));
351 const Vec<T,3> z(static_cast<T>(0.0), static_cast<T>(0.0), size.z());
352
353 typename Vec<T,3>::List vertices(8);
354
355 // top vertices clockwise (viewed from above)
356 vertices[0] = bbox.max;
357 vertices[1] = bbox.max-y;
358 vertices[2] = bbox.min+z;
359 vertices[3] = bbox.max-x;
360
361 // bottom vertices clockwise (viewed from below)
362 vertices[4] = bbox.min;
363 vertices[5] = bbox.min+x;
364 vertices[6] = bbox.max-z;
365 vertices[7] = bbox.min+y;
366 return vertices;
367 }
368
369 template <typename T, class Op>
eachBBoxVertex(const BBox<T,3> & bbox,Op & op)370 void eachBBoxVertex(const BBox<T,3>& bbox, Op& op) {
371 const Vec<T,3> size = bbox.size();
372 const Vec<T,3> x(size.x(), static_cast<T>(0.0), static_cast<T>(0.0));
373 const Vec<T,3> y(static_cast<T>(0.0), size.y(), static_cast<T>(0.0));
374 const Vec<T,3> z(static_cast<T>(0.0), static_cast<T>(0.0), size.z());
375
376 // top vertices clockwise (viewed from above)
377 op(bbox.max);
378 op(bbox.max-y);
379 op(bbox.min+z);
380 op(bbox.max-x);
381
382 // bottom vertices clockwise (viewed from below)
383 op(bbox.min);
384 op(bbox.min+x);
385 op(bbox.max-z);
386 op(bbox.min+y);
387 }
388
389 template <typename T>
390 struct RotateBBox {
391 Quat<T> rotation;
392 bool first;
393 BBox<T,3> bbox;
394
RotateBBoxRotateBBox395 RotateBBox(const Quat<T>& i_rotation) :
396 rotation(i_rotation),
397 first(true) {}
398
operatorRotateBBox399 void operator()(const Vec<T,3>& vertex) {
400 if (first) {
401 bbox.min = bbox.max = rotation * vertex;
402 first = false;
403 } else {
404 bbox.mergeWith(rotation * vertex);
405 }
406 }
407 };
408
409 template <typename T>
410 BBox<T,3> rotateBBox(const BBox<T,3>& bbox, const Quat<T>& rotation, const Vec<T,3>& center = Vec<T,3>::Null) {
411 RotateBBox<T> rotator(rotation);
412 eachBBoxVertex(bbox.translated(-center), rotator);
413 return rotator.bbox.translated(center);
414 }
415
416 template <typename T>
417 struct TransformBBox {
418 Mat<T,4,4> transformation;
419 bool first;
420 BBox<T,3> bbox;
421
TransformBBoxTransformBBox422 TransformBBox(const Mat<T,4,4>& i_transformation) :
423 transformation(i_transformation),
424 first(true) {}
425
operatorTransformBBox426 void operator()(const Vec<T,3>& vertex) {
427 if (first) {
428 bbox.min = bbox.max = transformation * vertex;
429 first = false;
430 } else {
431 bbox.mergeWith(transformation * vertex);
432 }
433 }
434 };
435
436 template <typename T>
rotateBBox(const BBox<T,3> & bbox,const Mat<T,4,4> & transformation)437 BBox<T,3> rotateBBox(const BBox<T,3>& bbox, const Mat<T,4,4>& transformation) {
438 TransformBBox<T> transformator(transformation);
439 eachBBoxVertex(bbox, transformator);
440 return transformator.bbox;
441 }
442
443
444 typedef BBox<float,1> BBox1f;
445 typedef BBox<double,1> BBox1d;
446 typedef BBox<float,2> BBox2f;
447 typedef BBox<double,2> BBox2d;
448 typedef BBox<float,3> BBox3f;
449 typedef BBox<double,3> BBox3d;
450
451 #endif
452