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