Line data Source code
1 : /*
2 : * Copyright (c) 2006-2016, Visualization and Multimedia Lab,
3 : * University of Zurich <http://vmml.ifi.uzh.ch>,
4 : * Eyescale Software GmbH,
5 : * Blue Brain Project, EPFL
6 : *
7 : * This file is part of VMMLib <https://github.com/VMML/vmmlib/>
8 : *
9 : * Redistribution and use in source and binary forms, with or without
10 : * modification, are permitted provided that the following conditions are met:
11 : *
12 : * Redistributions of source code must retain the above copyright notice, this
13 : * list of conditions and the following disclaimer. Redistributions in binary
14 : * form must reproduce the above copyright notice, this list of conditions and
15 : * the following disclaimer in the documentation and/or other materials provided
16 : * with the distribution. Neither the name of the Visualization and Multimedia
17 : * Lab, University of Zurich nor the names of its contributors may be used to
18 : * endorse or promote products derived from this software without specific prior
19 : * written permission.
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 : * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 : * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 : * POSSIBILITY OF SUCH DAMAGE.
31 : */
32 : #ifndef __VMML__AXIS_ALIGNED_BOUNDING_BOX__HPP__
33 : #define __VMML__AXIS_ALIGNED_BOUNDING_BOX__HPP__
34 :
35 : #include <limits>
36 : #include <vmmlib/vector.hpp>
37 :
38 : namespace lunchbox
39 : {
40 : template <class T>
41 : void byteswap(T&);
42 : }
43 :
44 : namespace vmml
45 : {
46 : template <typename T>
47 : class AABB;
48 : }
49 : namespace staticjson
50 : {
51 : class ObjectHandler;
52 : template <typename U>
53 : void init(vmml::AABB<U>*, ObjectHandler*);
54 : }
55 :
56 : namespace vmml
57 : {
58 : /**
59 : * An axis-aligned bounding box.
60 : *
61 : * An empty bounding box has undefined, implementation-specific values. Read
62 : * operations (getMin(), getMax(), getSize(), isIn(), etc.) have undefined
63 : * semantics on an empty bounding box. set() and merge() operations will define
64 : * the bounding box correctly.
65 : */
66 : template <typename T>
67 : class AABB
68 : {
69 : public:
70 : /** Create an empty bounding box. */
71 : AABB();
72 :
73 : /** Create a new bounding box from two corner points */
74 : AABB(const vector<3, T>& pMin, const vector<3, T>& pMax);
75 :
76 : /** Create a new bounding box from a bounding sphere */
77 : AABB(const vector<4, T>& sphere);
78 :
79 : /** @return true if the given point is within this bounding box. */
80 : bool isIn(const vector<3, T>& point) const;
81 :
82 : /** @return true if the given sphere is within this bounding box. */
83 : bool isIn(const vector<4, T>& sphere) const;
84 :
85 : /**
86 : * @return true if this bounding box is in front of the given plane
87 : * ([normal.x|y|z, d] notation).
88 : */
89 : bool isInFront(const vector<4, T>& plane) const;
90 :
91 : /** @return the minimum corner point */
92 : const vector<3, T>& getMin() const;
93 :
94 : /** @return the maximum corner point */
95 : const vector<3, T>& getMax() const;
96 :
97 : /** Create the union of this and the given bounding box */
98 : void merge(const AABB<T>& aabb);
99 :
100 : /** Create the union of this and the given point */
101 : void merge(const vector<3, T>& point);
102 :
103 : /** Clear this bounding box */
104 : void reset();
105 :
106 : /** @return true if this bounding box has not been set */
107 : bool isEmpty() const;
108 :
109 : /** @return true if this and the other bounding box are identical */
110 : bool operator==(const AABB<T>& other) const;
111 :
112 : /** @return true if this and the other bounding box are not identical */
113 : bool operator!=(const AABB<T>& other) const;
114 :
115 : /** @return the center of this bounding box */
116 : vector<3, T> getCenter() const;
117 :
118 : /** @return the size of this bounding box */
119 : vector<3, T> getSize() const;
120 :
121 : /**
122 : * Compute the nearest and furthest point of this box relative to the given
123 : * plane.
124 : */
125 : void computeNearFar(const vector<4, T>& plane, vector<3, T>& nearPoint,
126 : vector<3, T>& farPoint) const;
127 :
128 : /** @return a bounding box of size one with the minimum point at zero. */
129 : static AABB<T> makeUnitBox();
130 :
131 : #ifdef __INTEL_COMPILER
132 : // For some reason, ICC does not understand the friend declarations and
133 : // generates compilation issues. Making the attributes public is not great
134 : // but it still is consistent with the rest of the vmmlib library (Vectors
135 : // and Quaternions also expose public class members)
136 : public:
137 : vector<3, T> _min;
138 : vector<3, T> _max;
139 : #else
140 : private:
141 : vector<3, T> _min;
142 : vector<3, T> _max;
143 : template <class U>
144 : friend void lunchbox::byteswap(U&);
145 : friend void staticjson::init(AABB<float>*, staticjson::ObjectHandler*);
146 : friend void staticjson::init(AABB<double>*, staticjson::ObjectHandler*);
147 : #endif
148 : };
149 :
150 : template <typename T>
151 0 : inline std::ostream& operator<<(std::ostream& os, const AABB<T>& aabb)
152 : {
153 0 : return os << aabb.getMin() << " - " << aabb.getMax();
154 : }
155 :
156 : template <typename T>
157 : AABB<T>::AABB()
158 : : _min(std::numeric_limits<T>::max())
159 : , _max(std::numeric_limits<T>::min())
160 : {
161 : }
162 :
163 : template <>
164 1 : inline AABB<float>::AABB()
165 2 : : _min(std::numeric_limits<float>::max())
166 2 : , _max(-std::numeric_limits<float>::max())
167 : {
168 1 : }
169 :
170 : template <>
171 : inline AABB<double>::AABB()
172 : : _min(std::numeric_limits<double>::max())
173 : , _max(-std::numeric_limits<double>::max())
174 : {
175 : }
176 :
177 : template <typename T>
178 9 : AABB<T>::AABB(const vector<3, T>& pMin, const vector<3, T>& pMax)
179 18 : : _min(vector<3, T>(std::min(pMin[0], pMax[0]), std::min(pMin[1], pMax[1]),
180 9 : std::min(pMin[2], pMax[2])))
181 18 : , _max(vector<3, T>(std::max(pMin[0], pMax[0]), std::max(pMin[1], pMax[1]),
182 45 : std::max(pMin[2], pMax[2])))
183 : {
184 9 : }
185 :
186 : template <typename T>
187 : AABB<T>::AABB(const vector<4, T>& sphere)
188 : {
189 : _max = _min = sphere.getCenter();
190 : _max += sphere.getRadius();
191 : _min -= sphere.getRadius();
192 : }
193 :
194 : template <typename T>
195 : inline bool AABB<T>::isIn(const vector<3, T>& pos) const
196 : {
197 : if (pos.x() > _max.x() || pos.y() > _max.y() || pos.z() > _max.z() ||
198 : pos.x() < _min.x() || pos.y() < _min.y() || pos.z() < _min.z())
199 : {
200 : return false;
201 : }
202 : return true;
203 : }
204 :
205 : template <typename T>
206 : inline bool AABB<T>::isIn(const vector<4, T>& sphere) const
207 : {
208 : const vector<3, T>& sv = sphere.getCenter();
209 : sv += sphere.getRadius();
210 : if (sv.x() > _max.x() || sv.y() > _max.y() || sv.z() > _max.z())
211 : return false;
212 : sv -= sphere.getRadius() * 2.0f;
213 : if (sv.x() < _min.x() || sv.y() < _min.y() || sv.z() < _min.z())
214 : return false;
215 : return true;
216 : }
217 :
218 : template <typename T>
219 6 : inline bool AABB<T>::isInFront(const vector<4, T>& plane) const
220 : {
221 6 : const auto& extent = getSize() * 0.5f;
222 6 : const float d = plane.dot(getCenter());
223 12 : const float n = extent.x() * std::abs(plane.x()) +
224 6 : extent.y() * std::abs(plane.y()) +
225 6 : extent.z() * std::abs(plane.z());
226 :
227 6 : return !(d - n >= 0 || d + n > 0);
228 : }
229 :
230 : template <typename T>
231 4 : inline const vector<3, T>& AABB<T>::getMin() const
232 : {
233 4 : return _min;
234 : }
235 :
236 : template <typename T>
237 4 : inline const vector<3, T>& AABB<T>::getMax() const
238 : {
239 4 : return _max;
240 : }
241 :
242 : template <typename T>
243 1 : inline bool AABB<T>::operator==(const AABB<T>& other) const
244 : {
245 1 : return _min == other._min && _max == other._max;
246 : }
247 :
248 : template <typename T>
249 : inline bool AABB<T>::operator!=(const AABB<T>& other) const
250 : {
251 : return _min != other._min || _max != other._max;
252 : }
253 :
254 : template <typename T>
255 13 : vector<3, T> AABB<T>::getCenter() const
256 : {
257 13 : return (_min + _max) * 0.5f;
258 : }
259 :
260 : template <typename T>
261 15 : vector<3, T> AABB<T>::getSize() const
262 : {
263 15 : return _max - _min;
264 : }
265 :
266 : template <typename T>
267 1 : void AABB<T>::merge(const AABB<T>& aabb)
268 : {
269 1 : const vector<3, T>& min = aabb.getMin();
270 1 : const vector<3, T>& max = aabb.getMax();
271 :
272 1 : if (min.x() < _min.x())
273 1 : _min.x() = min.x();
274 1 : if (min.y() < _min.y())
275 1 : _min.y() = min.y();
276 1 : if (min.z() < _min.z())
277 1 : _min.z() = min.z();
278 :
279 1 : if (max.x() > _max.x())
280 0 : _max.x() = max.x();
281 1 : if (max.y() > _max.y())
282 0 : _max.y() = max.y();
283 1 : if (max.z() > _max.z())
284 0 : _max.z() = max.z();
285 1 : }
286 :
287 : template <typename T>
288 2 : void AABB<T>::merge(const vector<3, T>& point)
289 : {
290 2 : if (point.x() < _min.x())
291 1 : _min.x() = point.x();
292 2 : if (point.y() < _min.y())
293 1 : _min.y() = point.y();
294 2 : if (point.z() < _min.z())
295 1 : _min.z() = point.z();
296 :
297 2 : if (point.x() > _max.x())
298 2 : _max.x() = point.x();
299 2 : if (point.y() > _max.y())
300 2 : _max.y() = point.y();
301 2 : if (point.z() > _max.z())
302 2 : _max.z() = point.z();
303 2 : }
304 :
305 : template <typename T>
306 : inline void AABB<T>::reset()
307 : {
308 : _min = std::numeric_limits<T>::max();
309 : _max = -std::numeric_limits<T>::max();
310 : }
311 :
312 : template <typename T>
313 4 : inline bool AABB<T>::isEmpty() const
314 : {
315 4 : return _min.x() >= _max.x() || _min.y() >= _max.y() || _min.z() >= _max.x();
316 : }
317 :
318 : template <typename T>
319 : inline void AABB<T>::computeNearFar(const vector<4, T>& plane,
320 : vector<3, T>& nearPoint,
321 : vector<3, T>& farPoint) const
322 : {
323 : for (size_t i = 0; i < 3; ++i)
324 : {
325 : if (plane[i] >= 0.0)
326 : {
327 : nearPoint[i] = _min[i];
328 : farPoint[i] = _max[i];
329 : }
330 : else
331 : {
332 : nearPoint[i] = _max[i];
333 : farPoint[i] = _min[i];
334 : }
335 : }
336 : }
337 :
338 : template <typename T>
339 2 : AABB<T> AABB<T>::makeUnitBox()
340 : {
341 2 : return AABB(vector<3, T>(), vector<3, T>(1));
342 : }
343 : }
344 :
345 : #endif
|