-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBoundingBox.hpp
203 lines (182 loc) · 6.03 KB
/
BoundingBox.hpp
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#pragma once
/** @file BoundingBox.hpp
* @brief Define the BoundingBox class for 3D bounding boxes. */
#include <iostream>
#include <algorithm>
#include <cmath>
#include "Point.hpp"
/** @class BoundingBox
* @brief Class representing 3D bounding boxes.
*
* A BoundingBox is a 3D volume. Its fundamental operations are contains(),
* which tests whether a point is in the volume, and operator+=(), which
* extends the volume as necessary to ensure that the volume contains a point.
*
* BoundingBoxes are implemented as boxes -- 3D rectangular cuboids -- whose
* sides are aligned with the principal axes.
*/
class BoundingBox {
public:
static constexpr unsigned DIM = 3;
typedef Point point_type;
/** Construct an empty bounding box. */
BoundingBox()
: empty_(true), min_(), max_() {
}
/** Construct the minimal bounding box containing @a p.
* @post contains(@a p) && min() == @a p && max() == @a p */
explicit BoundingBox(const point_type& p)
: empty_(false), min_(p), max_(p) {
}
/** Construct the minimal bounding box containing @a p1 and @a p2.
* @post contains(@a p1) && contains(@a p2) */
BoundingBox(const point_type& p1, const point_type& p2)
: empty_(false), min_(p1), max_(p1) {
*this |= p2;
}
/** Construct a bounding box containing the points in [first, last). */
template <typename PointIter>
BoundingBox(PointIter first, PointIter last)
: empty_(true), min_(), max_() {
insert(first, last);
}
/** Test if the bounding box is empty (contains no points). */
bool empty() const {
return empty_;
}
/** Test if the bounding box is nonempty.
*
* This function lets you write code such as "if (b) { ... }" or
* "if (box1 & box2) std::cout << "box1 and box2 intersect\n". */
operator bool() const {
return empty();
}
/** Return the minimum corner of the bounding box.
* @post empty() || contains(min())
* @note An empty box has min() == point_type(). */
const point_type& min() const {
return min_;
}
/** Return the maximum corner of the bounding box.
* @post empty() || contains(max())
* @note An empty box has max() == point_type(). */
const point_type& max() const {
return max_;
}
/** Test if point @a p is in the bounding box. */
bool contains(const point_type& p) const {
if (empty())
return false;
for (unsigned i = 0; i != DIM; ++i)
if (p[i] < min_[i] || p[i] > max_[i])
return false;
return true;
}
/** Test if @a b is entirely within this bounding box.
* @returns true if all @a p with @a b.contains(@a p) implies contains(@a p) */
bool contains(const BoundingBox& b) const {
if (empty() || b.empty())
return false;
for (unsigned i = 0; i != DIM; ++i)
if (b.min_[i] < min_[i] || b.min_[i] > max_[i] ||
b.max_[i] < min_[i] || b.max_[i] > max_[i])
return false;
return true;
}
/** Test if @a b intersects this bounding box.
* @returns true if there exists @a p such that
* contains(@a p) && b.contains(@a p) */
bool intersects(const BoundingBox& b) const {
if (empty() || b.empty())
return false;
for (unsigned i = 0; i != DIM; ++i)
if (b.min_[i] > max_[i] || b.max_[i] < min_[i])
return false;
return true;
}
/** Extend the bounding box to contain @a p.
* @post contains(@a p) is true
* @post For all @a x with old contains(@a x),
then new contains(@a x) is true. */
BoundingBox& operator|=(const point_type& p) {
if (empty()) {
empty_ = false;
min_ = max_ = p;
} else {
for (unsigned i = 0; i != DIM; ++i) {
if (p[i] < min_[i]) min_[i] = p[i];
if (p[i] > max_[i]) max_[i] = p[i];
}
}
return *this;
}
/** Extend the bounding box to contain @a b.
* @post contains(@a b) || @a b.empty()
* @post For all @a x with old contains(@a x) or @a b.contains(@a x),
* then new contains(@a x) is true. */
BoundingBox& operator|=(const BoundingBox& b) {
if (!b.empty())
(*this |= b.min()) |= b.max();
return *this;
}
/** Extend the bounding box to contain the points in [first, last).
* @post For all @a p in [@a first, @a last), contains(@a p) is true.
* @post For all @a x with old contains(@a x),
* then new contains(@a x) is true. */
template <typename PointIter>
BoundingBox& insert(PointIter first, PointIter last) {
for ( ; first != last; ++first)
*this |= *first;
return *this;
}
/** Intersect this bounding box with another bounding box @a b.
* @post For all @a x with old contains(@a x) and @a b.contains(@a x),
* then new contains(@a x) is true. */
BoundingBox& operator&=(const BoundingBox& b) {
if (!intersects(b))
return clear();
for (unsigned i = 0; i != DIM; ++i) {
if (min_[i] < b.min_[i]) min_[i] = b.min_[i];
if (max_[i] > b.max_[i]) max_[i] = b.max_[i];
}
return *this;
}
/** Clear the bounding box.
* @post empty() */
BoundingBox& clear() {
empty_ = true;
min_ = max_ = point_type();
return *this;
}
private:
bool empty_;
point_type min_;
point_type max_;
};
/** Write a BoundingBox to an output stream.
*
* An empty BoundingBox is written as "[]". A nonempty BoundingBox is
* written as "[minx miny minz : maxx maxy maxz]", where all coordinates
* are double-precision numbers.
*/
std::ostream& operator<<(std::ostream& s, const BoundingBox& box) {
if (box.empty())
return s << '[' << ']';
return s << '[' << box.min() << " : " << box.max() << ']';
}
/** Return a bounding box that contains @a b and @a p. */
BoundingBox operator|(BoundingBox b, const Point& p) {
return b |= p;
}
/** Return the union of @a b1 and @a b2. */
BoundingBox operator|(BoundingBox b1, const BoundingBox& b2) {
return b1 |= b2;
}
/** Return a bounding box that contains @a p1 and @a p2. */
BoundingBox operator|(const Point& p1, const Point& p2) {
return BoundingBox(p1, p2);
}
/** Return the intersection of @a b1 and @a b2. */
BoundingBox operator&(BoundingBox b1, const BoundingBox& b2) {
return b1 &= b2;
}