/src/ogre/OgreMain/include/OgreAxisAlignedBox.h
Line | Count | Source |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | #ifndef __AxisAlignedBox_H_ |
29 | | #define __AxisAlignedBox_H_ |
30 | | |
31 | | #include <array> |
32 | | |
33 | | // Precompiler options |
34 | | #include "OgrePrerequisites.h" |
35 | | |
36 | | #include "OgreMatrix4.h" |
37 | | |
38 | | namespace Ogre { |
39 | | /** \addtogroup Core |
40 | | * @{ |
41 | | */ |
42 | | /** \addtogroup Math |
43 | | * @{ |
44 | | */ |
45 | | |
46 | | /** A 3D box aligned with the x/y/z axes. |
47 | | |
48 | | This class represents a simple box which is aligned with the |
49 | | axes. Internally it only stores 2 points as the extremeties of |
50 | | the box, one which is the minima of all 3 axes, and the other |
51 | | which is the maxima of all 3 axes. This class is typically used |
52 | | for an axis-aligned bounding box (AABB) for collision and |
53 | | visibility determination. |
54 | | */ |
55 | | class _OgreExport AxisAlignedBox |
56 | | { |
57 | | public: |
58 | | enum Extent |
59 | | { |
60 | | EXTENT_NULL, |
61 | | EXTENT_FINITE, |
62 | | EXTENT_INFINITE |
63 | | }; |
64 | | private: |
65 | | |
66 | | Vector3 mMinimum; |
67 | | Vector3 mMaximum; |
68 | | Extent mExtent; |
69 | | |
70 | | public: |
71 | | /* |
72 | | 1-------2 |
73 | | /| /| |
74 | | / | / | |
75 | | 5-------4 | |
76 | | | 0----|--3 |
77 | | | / | / |
78 | | |/ |/ |
79 | | 6-------7 |
80 | | */ |
81 | | enum CornerEnum { |
82 | | FAR_LEFT_BOTTOM = 0, |
83 | | FAR_LEFT_TOP = 1, |
84 | | FAR_RIGHT_TOP = 2, |
85 | | FAR_RIGHT_BOTTOM = 3, |
86 | | NEAR_RIGHT_BOTTOM = 7, |
87 | | NEAR_LEFT_BOTTOM = 6, |
88 | | NEAR_LEFT_TOP = 5, |
89 | | NEAR_RIGHT_TOP = 4 |
90 | | }; |
91 | | typedef std::array<Vector3, 8> Corners; |
92 | | |
93 | | AxisAlignedBox() |
94 | 0 | { |
95 | 0 | // Default to a null box |
96 | 0 | setMinimum( -0.5, -0.5, -0.5 ); |
97 | 0 | setMaximum( 0.5, 0.5, 0.5 ); |
98 | 0 | mExtent = EXTENT_NULL; |
99 | 0 | } |
100 | | AxisAlignedBox(Extent e) |
101 | 0 | { |
102 | 0 | setMinimum( -0.5, -0.5, -0.5 ); |
103 | 0 | setMaximum( 0.5, 0.5, 0.5 ); |
104 | 0 | mExtent = e; |
105 | 0 | } |
106 | | |
107 | | AxisAlignedBox( const Vector3& min, const Vector3& max ) |
108 | 0 | { |
109 | 0 | setExtents( min, max ); |
110 | 0 | } |
111 | | |
112 | | AxisAlignedBox(Real mx, Real my, Real mz, Real Mx, Real My, Real Mz) |
113 | 0 | { |
114 | 0 | setExtents( mx, my, mz, Mx, My, Mz ); |
115 | 0 | } |
116 | | |
117 | | /** Gets the minimum corner of the box. |
118 | | */ |
119 | | inline const Vector3& getMinimum(void) const |
120 | 0 | { |
121 | 0 | return mMinimum; |
122 | 0 | } |
123 | | |
124 | | /** Gets a modifiable version of the minimum |
125 | | corner of the box. |
126 | | */ |
127 | | inline Vector3& getMinimum(void) |
128 | 0 | { |
129 | 0 | return mMinimum; |
130 | 0 | } |
131 | | |
132 | | /** Gets the maximum corner of the box. |
133 | | */ |
134 | | inline const Vector3& getMaximum(void) const |
135 | 0 | { |
136 | 0 | return mMaximum; |
137 | 0 | } |
138 | | |
139 | | /** Gets a modifiable version of the maximum |
140 | | corner of the box. |
141 | | */ |
142 | | inline Vector3& getMaximum(void) |
143 | 0 | { |
144 | 0 | return mMaximum; |
145 | 0 | } |
146 | | |
147 | | |
148 | | /** Sets the minimum corner of the box. |
149 | | */ |
150 | | inline void setMinimum( const Vector3& vec ) |
151 | 0 | { |
152 | 0 | mExtent = EXTENT_FINITE; |
153 | 0 | mMinimum = vec; |
154 | 0 | } |
155 | | |
156 | | inline void setMinimum( Real x, Real y, Real z ) |
157 | 0 | { |
158 | 0 | mExtent = EXTENT_FINITE; |
159 | 0 | mMinimum.x = x; |
160 | 0 | mMinimum.y = y; |
161 | 0 | mMinimum.z = z; |
162 | 0 | } |
163 | | |
164 | | /** Changes one of the components of the minimum corner of the box |
165 | | used to resize only one dimension of the box |
166 | | */ |
167 | | inline void setMinimumX(Real x) |
168 | 0 | { |
169 | 0 | mMinimum.x = x; |
170 | 0 | } |
171 | | |
172 | | inline void setMinimumY(Real y) |
173 | 0 | { |
174 | 0 | mMinimum.y = y; |
175 | 0 | } |
176 | | |
177 | | inline void setMinimumZ(Real z) |
178 | 0 | { |
179 | 0 | mMinimum.z = z; |
180 | 0 | } |
181 | | |
182 | | /** Sets the maximum corner of the box. |
183 | | */ |
184 | | inline void setMaximum( const Vector3& vec ) |
185 | 0 | { |
186 | 0 | mExtent = EXTENT_FINITE; |
187 | 0 | mMaximum = vec; |
188 | 0 | } |
189 | | |
190 | | inline void setMaximum( Real x, Real y, Real z ) |
191 | 0 | { |
192 | 0 | mExtent = EXTENT_FINITE; |
193 | 0 | mMaximum.x = x; |
194 | 0 | mMaximum.y = y; |
195 | 0 | mMaximum.z = z; |
196 | 0 | } |
197 | | |
198 | | /** Changes one of the components of the maximum corner of the box |
199 | | used to resize only one dimension of the box |
200 | | */ |
201 | | inline void setMaximumX( Real x ) |
202 | 0 | { |
203 | 0 | mMaximum.x = x; |
204 | 0 | } |
205 | | |
206 | | inline void setMaximumY( Real y ) |
207 | 0 | { |
208 | 0 | mMaximum.y = y; |
209 | 0 | } |
210 | | |
211 | | inline void setMaximumZ( Real z ) |
212 | 0 | { |
213 | 0 | mMaximum.z = z; |
214 | 0 | } |
215 | | |
216 | | /** Sets both minimum and maximum extents at once. |
217 | | */ |
218 | | inline void setExtents( const Vector3& min, const Vector3& max ) |
219 | 0 | { |
220 | 0 | assert( (min.x <= max.x && min.y <= max.y && min.z <= max.z) && |
221 | 0 | "The minimum corner of the box must be less than or equal to maximum corner" ); |
222 | 0 |
|
223 | 0 | mExtent = EXTENT_FINITE; |
224 | 0 | mMinimum = min; |
225 | 0 | mMaximum = max; |
226 | 0 | } |
227 | | |
228 | | inline void setExtents( |
229 | | Real mx, Real my, Real mz, |
230 | | Real Mx, Real My, Real Mz ) |
231 | 0 | { |
232 | 0 | assert( (mx <= Mx && my <= My && mz <= Mz) && |
233 | 0 | "The minimum corner of the box must be less than or equal to maximum corner" ); |
234 | 0 |
|
235 | 0 | mExtent = EXTENT_FINITE; |
236 | 0 |
|
237 | 0 | mMinimum.x = mx; |
238 | 0 | mMinimum.y = my; |
239 | 0 | mMinimum.z = mz; |
240 | 0 |
|
241 | 0 | mMaximum.x = Mx; |
242 | 0 | mMaximum.y = My; |
243 | 0 | mMaximum.z = Mz; |
244 | 0 |
|
245 | 0 | } |
246 | | |
247 | | /** Returns a pointer to an array of 8 corner points, useful for |
248 | | collision vs. non-aligned objects. |
249 | | |
250 | | If the order of these corners is important, they are as |
251 | | follows: The 4 points of the minimum Z face (note that |
252 | | because Ogre uses right-handed coordinates, the minimum Z is |
253 | | at the 'back' of the box) starting with the minimum point of |
254 | | all, then anticlockwise around this face (if you are looking |
255 | | onto the face from outside the box). Then the 4 points of the |
256 | | maximum Z face, starting with maximum point of all, then |
257 | | anticlockwise around this face (looking onto the face from |
258 | | outside the box). Like this: |
259 | | <pre> |
260 | | 1-------2 |
261 | | /| /| |
262 | | / | / | |
263 | | 5-------4 | |
264 | | | 0----|--3 |
265 | | | / | / |
266 | | |/ |/ |
267 | | 6-------7 |
268 | | </pre> |
269 | | */ |
270 | | inline Corners getAllCorners(void) const |
271 | 0 | { |
272 | 0 | assert( (mExtent == EXTENT_FINITE) && "Can't get corners of a null or infinite AAB" ); |
273 | 0 |
|
274 | 0 | // The order of these items is, using right-handed coordinates: |
275 | 0 | // Minimum Z face, starting with Min(all), then anticlockwise |
276 | 0 | // around face (looking onto the face) |
277 | 0 | // Maximum Z face, starting with Max(all), then anticlockwise |
278 | 0 | // around face (looking onto the face) |
279 | 0 | // Only for optimization/compatibility. |
280 | 0 | Corners corners; |
281 | 0 |
|
282 | 0 | corners[0] = getCorner(FAR_LEFT_BOTTOM); |
283 | 0 | corners[1] = getCorner(FAR_LEFT_TOP); |
284 | 0 | corners[2] = getCorner(FAR_RIGHT_TOP); |
285 | 0 | corners[3] = getCorner(FAR_RIGHT_BOTTOM); |
286 | 0 |
|
287 | 0 | corners[4] = getCorner(NEAR_RIGHT_TOP); |
288 | 0 | corners[5] = getCorner(NEAR_LEFT_TOP); |
289 | 0 | corners[6] = getCorner(NEAR_LEFT_BOTTOM); |
290 | 0 | corners[7] = getCorner(NEAR_RIGHT_BOTTOM); |
291 | 0 |
|
292 | 0 | return corners; |
293 | 0 | } |
294 | | |
295 | | /** Gets the position of one of the corners |
296 | | */ |
297 | | Vector3 getCorner(CornerEnum cornerToGet) const |
298 | 0 | { |
299 | 0 | switch(cornerToGet) |
300 | 0 | { |
301 | 0 | case FAR_LEFT_BOTTOM: |
302 | 0 | return mMinimum; |
303 | 0 | case FAR_LEFT_TOP: |
304 | 0 | return Vector3(mMinimum.x, mMaximum.y, mMinimum.z); |
305 | 0 | case FAR_RIGHT_TOP: |
306 | 0 | return Vector3(mMaximum.x, mMaximum.y, mMinimum.z); |
307 | 0 | case FAR_RIGHT_BOTTOM: |
308 | 0 | return Vector3(mMaximum.x, mMinimum.y, mMinimum.z); |
309 | 0 | case NEAR_RIGHT_BOTTOM: |
310 | 0 | return Vector3(mMaximum.x, mMinimum.y, mMaximum.z); |
311 | 0 | case NEAR_LEFT_BOTTOM: |
312 | 0 | return Vector3(mMinimum.x, mMinimum.y, mMaximum.z); |
313 | 0 | case NEAR_LEFT_TOP: |
314 | 0 | return Vector3(mMinimum.x, mMaximum.y, mMaximum.z); |
315 | 0 | case NEAR_RIGHT_TOP: |
316 | 0 | return mMaximum; |
317 | 0 | default: |
318 | 0 | return Vector3(); |
319 | 0 | } |
320 | 0 | } |
321 | | |
322 | | /** Merges the passed in box into the current box. The result is the |
323 | | box which encompasses both. |
324 | | */ |
325 | | void merge( const AxisAlignedBox& rhs ) |
326 | 0 | { |
327 | 0 | // Do nothing if rhs null, or this is infinite |
328 | 0 | if ((rhs.mExtent == EXTENT_NULL) || (mExtent == EXTENT_INFINITE)) |
329 | 0 | { |
330 | 0 | return; |
331 | 0 | } |
332 | 0 | // Otherwise if rhs is infinite, make this infinite, too |
333 | 0 | else if (rhs.mExtent == EXTENT_INFINITE) |
334 | 0 | { |
335 | 0 | mExtent = EXTENT_INFINITE; |
336 | 0 | } |
337 | 0 | // Otherwise if current null, just take rhs |
338 | 0 | else if (mExtent == EXTENT_NULL) |
339 | 0 | { |
340 | 0 | setExtents(rhs.mMinimum, rhs.mMaximum); |
341 | 0 | } |
342 | 0 | // Otherwise merge |
343 | 0 | else |
344 | 0 | { |
345 | 0 | Vector3 min = mMinimum; |
346 | 0 | Vector3 max = mMaximum; |
347 | 0 | max.makeCeil(rhs.mMaximum); |
348 | 0 | min.makeFloor(rhs.mMinimum); |
349 | 0 |
|
350 | 0 | setExtents(min, max); |
351 | 0 | } |
352 | 0 |
|
353 | 0 | } |
354 | | |
355 | | /** Extends the box to encompass the specified point (if needed). |
356 | | */ |
357 | | inline void merge( const Vector3& point ) |
358 | 0 | { |
359 | 0 | switch (mExtent) |
360 | 0 | { |
361 | 0 | case EXTENT_NULL: // if null, use this point |
362 | 0 | setExtents(point, point); |
363 | 0 | return; |
364 | 0 |
|
365 | 0 | case EXTENT_FINITE: |
366 | 0 | mMaximum.makeCeil(point); |
367 | 0 | mMinimum.makeFloor(point); |
368 | 0 | return; |
369 | 0 |
|
370 | 0 | case EXTENT_INFINITE: // if infinite, makes no difference |
371 | 0 | return; |
372 | 0 | } |
373 | 0 |
|
374 | 0 | assert( false && "Never reached" ); |
375 | 0 | } |
376 | | |
377 | | /** Transforms the box according to the matrix supplied. |
378 | | |
379 | | By calling this method you get the axis-aligned box which |
380 | | surrounds the transformed version of this box. Therefore each |
381 | | corner of the box is transformed by the matrix, then the |
382 | | extents are mapped back onto the axes to produce another |
383 | | AABB. Useful when you have a local AABB for an object which |
384 | | is then transformed. |
385 | | */ |
386 | | inline void transform( const Matrix4& matrix ) |
387 | 0 | { |
388 | 0 | // Do nothing if current null or infinite |
389 | 0 | if( mExtent != EXTENT_FINITE ) |
390 | 0 | return; |
391 | 0 |
|
392 | 0 | Vector3 oldMin, oldMax, currentCorner; |
393 | 0 |
|
394 | 0 | // Getting the old values so that we can use the existing merge method. |
395 | 0 | oldMin = mMinimum; |
396 | 0 | oldMax = mMaximum; |
397 | 0 |
|
398 | 0 | // reset |
399 | 0 | setNull(); |
400 | 0 |
|
401 | 0 | // We sequentially compute the corners in the following order : |
402 | 0 | // 0, 6, 5, 1, 2, 4 ,7 , 3 |
403 | 0 | // This sequence allows us to only change one member at a time to get at all corners. |
404 | 0 |
|
405 | 0 | // For each one, we transform it using the matrix |
406 | 0 | // Which gives the resulting point and merge the resulting point. |
407 | 0 |
|
408 | 0 | // First corner |
409 | 0 | // min min min |
410 | 0 | currentCorner = oldMin; |
411 | 0 | merge( matrix * currentCorner ); |
412 | 0 |
|
413 | 0 | // min,min,max |
414 | 0 | currentCorner.z = oldMax.z; |
415 | 0 | merge( matrix * currentCorner ); |
416 | 0 |
|
417 | 0 | // min max max |
418 | 0 | currentCorner.y = oldMax.y; |
419 | 0 | merge( matrix * currentCorner ); |
420 | 0 |
|
421 | 0 | // min max min |
422 | 0 | currentCorner.z = oldMin.z; |
423 | 0 | merge( matrix * currentCorner ); |
424 | 0 |
|
425 | 0 | // max max min |
426 | 0 | currentCorner.x = oldMax.x; |
427 | 0 | merge( matrix * currentCorner ); |
428 | 0 |
|
429 | 0 | // max max max |
430 | 0 | currentCorner.z = oldMax.z; |
431 | 0 | merge( matrix * currentCorner ); |
432 | 0 |
|
433 | 0 | // max min max |
434 | 0 | currentCorner.y = oldMin.y; |
435 | 0 | merge( matrix * currentCorner ); |
436 | 0 |
|
437 | 0 | // max min min |
438 | 0 | currentCorner.z = oldMin.z; |
439 | 0 | merge( matrix * currentCorner ); |
440 | 0 | } |
441 | | |
442 | | /** Transforms the box according to the affine matrix supplied. |
443 | | |
444 | | By calling this method you get the axis-aligned box which |
445 | | surrounds the transformed version of this box. Therefore each |
446 | | corner of the box is transformed by the matrix, then the |
447 | | extents are mapped back onto the axes to produce another |
448 | | AABB. Useful when you have a local AABB for an object which |
449 | | is then transformed. |
450 | | */ |
451 | | void transform(const Affine3& m) |
452 | 0 | { |
453 | 0 | // Do nothing if current null or infinite |
454 | 0 | if ( mExtent != EXTENT_FINITE ) |
455 | 0 | return; |
456 | 0 |
|
457 | 0 | Vector3 centre = getCenter(); |
458 | 0 | Vector3 halfSize = getHalfSize(); |
459 | 0 |
|
460 | 0 | Vector3 newCentre = m * centre; |
461 | 0 | Vector3 newHalfSize( |
462 | 0 | Math::Abs(m[0][0]) * halfSize.x + Math::Abs(m[0][1]) * halfSize.y + Math::Abs(m[0][2]) * halfSize.z, |
463 | 0 | Math::Abs(m[1][0]) * halfSize.x + Math::Abs(m[1][1]) * halfSize.y + Math::Abs(m[1][2]) * halfSize.z, |
464 | 0 | Math::Abs(m[2][0]) * halfSize.x + Math::Abs(m[2][1]) * halfSize.y + Math::Abs(m[2][2]) * halfSize.z); |
465 | 0 |
|
466 | 0 | setExtents(newCentre - newHalfSize, newCentre + newHalfSize); |
467 | 0 | } |
468 | | |
469 | | /** Sets the box to a 'null' value i.e. not a box. |
470 | | */ |
471 | | inline void setNull() |
472 | 0 | { |
473 | 0 | mExtent = EXTENT_NULL; |
474 | 0 | } |
475 | | |
476 | | /** Returns true if the box is null i.e. empty. |
477 | | */ |
478 | | inline bool isNull(void) const |
479 | 0 | { |
480 | 0 | return (mExtent == EXTENT_NULL); |
481 | 0 | } |
482 | | |
483 | | /** Returns true if the box is finite. |
484 | | */ |
485 | | bool isFinite(void) const |
486 | 0 | { |
487 | 0 | return (mExtent == EXTENT_FINITE); |
488 | 0 | } |
489 | | |
490 | | /** Sets the box to 'infinite' |
491 | | */ |
492 | | inline void setInfinite() |
493 | 0 | { |
494 | 0 | mExtent = EXTENT_INFINITE; |
495 | 0 | } |
496 | | |
497 | | /** Returns true if the box is infinite. |
498 | | */ |
499 | | bool isInfinite(void) const |
500 | 0 | { |
501 | 0 | return (mExtent == EXTENT_INFINITE); |
502 | 0 | } |
503 | | |
504 | | /** Returns whether or not this box intersects another. */ |
505 | | inline bool intersects(const AxisAlignedBox& b2) const |
506 | 0 | { |
507 | 0 | // Early-fail for nulls |
508 | 0 | if (this->isNull() || b2.isNull()) |
509 | 0 | return false; |
510 | 0 |
|
511 | 0 | // Early-success for infinites |
512 | 0 | if (this->isInfinite() || b2.isInfinite()) |
513 | 0 | return true; |
514 | 0 |
|
515 | 0 | // Use up to 6 separating planes |
516 | 0 | if (mMaximum.x < b2.mMinimum.x) |
517 | 0 | return false; |
518 | 0 | if (mMaximum.y < b2.mMinimum.y) |
519 | 0 | return false; |
520 | 0 | if (mMaximum.z < b2.mMinimum.z) |
521 | 0 | return false; |
522 | 0 |
|
523 | 0 | if (mMinimum.x > b2.mMaximum.x) |
524 | 0 | return false; |
525 | 0 | if (mMinimum.y > b2.mMaximum.y) |
526 | 0 | return false; |
527 | 0 | if (mMinimum.z > b2.mMaximum.z) |
528 | 0 | return false; |
529 | 0 |
|
530 | 0 | // otherwise, must be intersecting |
531 | 0 | return true; |
532 | 0 |
|
533 | 0 | } |
534 | | |
535 | | /// Calculate the area of intersection of this box and another |
536 | | inline AxisAlignedBox intersection(const AxisAlignedBox& b2) const |
537 | 0 | { |
538 | 0 | if (this->isNull() || b2.isNull()) |
539 | 0 | { |
540 | 0 | return AxisAlignedBox(); |
541 | 0 | } |
542 | 0 | else if (this->isInfinite()) |
543 | 0 | { |
544 | 0 | return b2; |
545 | 0 | } |
546 | 0 | else if (b2.isInfinite()) |
547 | 0 | { |
548 | 0 | return *this; |
549 | 0 | } |
550 | 0 |
|
551 | 0 | Vector3 intMin = mMinimum; |
552 | 0 | Vector3 intMax = mMaximum; |
553 | 0 |
|
554 | 0 | intMin.makeCeil(b2.getMinimum()); |
555 | 0 | intMax.makeFloor(b2.getMaximum()); |
556 | 0 |
|
557 | 0 | // Check intersection isn't null |
558 | 0 | if (intMin.x < intMax.x && |
559 | 0 | intMin.y < intMax.y && |
560 | 0 | intMin.z < intMax.z) |
561 | 0 | { |
562 | 0 | return AxisAlignedBox(intMin, intMax); |
563 | 0 | } |
564 | 0 |
|
565 | 0 | return AxisAlignedBox(); |
566 | 0 | } |
567 | | |
568 | | /// Calculate the volume of this box |
569 | | Real volume(void) const |
570 | 0 | { |
571 | 0 | switch (mExtent) |
572 | 0 | { |
573 | 0 | case EXTENT_NULL: |
574 | 0 | return 0.0f; |
575 | 0 |
|
576 | 0 | case EXTENT_FINITE: |
577 | 0 | { |
578 | 0 | Vector3 diff = mMaximum - mMinimum; |
579 | 0 | return diff.x * diff.y * diff.z; |
580 | 0 | } |
581 | 0 |
|
582 | 0 | case EXTENT_INFINITE: |
583 | 0 | return Math::POS_INFINITY; |
584 | 0 |
|
585 | 0 | default: // shut up compiler |
586 | 0 | assert( false && "Never reached" ); |
587 | 0 | return 0.0f; |
588 | 0 | } |
589 | 0 | } |
590 | | |
591 | | /** Scales the AABB by the vector given. */ |
592 | | inline void scale(const Vector3& s) |
593 | 0 | { |
594 | 0 | // Do nothing if current null or infinite |
595 | 0 | if (mExtent != EXTENT_FINITE) |
596 | 0 | return; |
597 | 0 |
|
598 | 0 | // NB assumes centered on origin |
599 | 0 | Vector3 min = mMinimum * s; |
600 | 0 | Vector3 max = mMaximum * s; |
601 | 0 | setExtents(min, max); |
602 | 0 | } |
603 | | |
604 | | /** Tests whether this box intersects a sphere. */ |
605 | | bool intersects(const Sphere& s) const |
606 | 0 | { |
607 | 0 | return Math::intersects(s, *this); |
608 | 0 | } |
609 | | /** Tests whether this box intersects a plane. */ |
610 | | bool intersects(const Plane& p) const |
611 | 0 | { |
612 | 0 | return Math::intersects(p, *this); |
613 | 0 | } |
614 | | /** Tests whether the vector point is within this box. */ |
615 | | bool intersects(const Vector3& v) const |
616 | 0 | { |
617 | 0 | switch (mExtent) |
618 | 0 | { |
619 | 0 | case EXTENT_NULL: |
620 | 0 | return false; |
621 | 0 |
|
622 | 0 | case EXTENT_FINITE: |
623 | 0 | return(v.x >= mMinimum.x && v.x <= mMaximum.x && |
624 | 0 | v.y >= mMinimum.y && v.y <= mMaximum.y && |
625 | 0 | v.z >= mMinimum.z && v.z <= mMaximum.z); |
626 | 0 |
|
627 | 0 | case EXTENT_INFINITE: |
628 | 0 | return true; |
629 | 0 |
|
630 | 0 | default: // shut up compiler |
631 | 0 | assert( false && "Never reached" ); |
632 | 0 | return false; |
633 | 0 | } |
634 | 0 | } |
635 | | /// Gets the centre of the box |
636 | | Vector3 getCenter(void) const |
637 | 0 | { |
638 | 0 | assert( (mExtent == EXTENT_FINITE) && "Can't get center of a null or infinite AAB" ); |
639 | 0 |
|
640 | 0 | return Vector3( |
641 | 0 | (mMaximum.x + mMinimum.x) * 0.5f, |
642 | 0 | (mMaximum.y + mMinimum.y) * 0.5f, |
643 | 0 | (mMaximum.z + mMinimum.z) * 0.5f); |
644 | 0 | } |
645 | | /// Gets the size of the box |
646 | | Vector3 getSize(void) const |
647 | 0 | { |
648 | 0 | switch (mExtent) |
649 | 0 | { |
650 | 0 | case EXTENT_NULL: |
651 | 0 | return Vector3::ZERO; |
652 | 0 |
|
653 | 0 | case EXTENT_FINITE: |
654 | 0 | return mMaximum - mMinimum; |
655 | 0 |
|
656 | 0 | case EXTENT_INFINITE: |
657 | 0 | return Vector3( |
658 | 0 | Math::POS_INFINITY, |
659 | 0 | Math::POS_INFINITY, |
660 | 0 | Math::POS_INFINITY); |
661 | 0 |
|
662 | 0 | default: // shut up compiler |
663 | 0 | assert( false && "Never reached" ); |
664 | 0 | return Vector3::ZERO; |
665 | 0 | } |
666 | 0 | } |
667 | | /// Gets the half-size of the box |
668 | | Vector3 getHalfSize(void) const |
669 | 0 | { |
670 | 0 | switch (mExtent) |
671 | 0 | { |
672 | 0 | case EXTENT_NULL: |
673 | 0 | return Vector3::ZERO; |
674 | 0 |
|
675 | 0 | case EXTENT_FINITE: |
676 | 0 | return (mMaximum - mMinimum) * 0.5; |
677 | 0 |
|
678 | 0 | case EXTENT_INFINITE: |
679 | 0 | return Vector3( |
680 | 0 | Math::POS_INFINITY, |
681 | 0 | Math::POS_INFINITY, |
682 | 0 | Math::POS_INFINITY); |
683 | 0 |
|
684 | 0 | default: // shut up compiler |
685 | 0 | assert( false && "Never reached" ); |
686 | 0 | return Vector3::ZERO; |
687 | 0 | } |
688 | 0 | } |
689 | | |
690 | | /** Tests whether the given point contained by this box. |
691 | | */ |
692 | | bool contains(const Vector3& v) const |
693 | 0 | { |
694 | 0 | if (isNull()) |
695 | 0 | return false; |
696 | 0 | if (isInfinite()) |
697 | 0 | return true; |
698 | 0 |
|
699 | 0 | return mMinimum.x <= v.x && v.x <= mMaximum.x && |
700 | 0 | mMinimum.y <= v.y && v.y <= mMaximum.y && |
701 | 0 | mMinimum.z <= v.z && v.z <= mMaximum.z; |
702 | 0 | } |
703 | | |
704 | | /** Returns the squared minimum distance between a given point and any part of the box. |
705 | | * This is faster than distance since avoiding a squareroot, so use if you can. */ |
706 | | Real squaredDistance(const Vector3& v) const |
707 | 0 | { |
708 | 0 |
|
709 | 0 | if (this->contains(v)) |
710 | 0 | return 0; |
711 | 0 | else |
712 | 0 | { |
713 | 0 | Vector3 maxDist(0,0,0); |
714 | 0 |
|
715 | 0 | if (v.x < mMinimum.x) |
716 | 0 | maxDist.x = mMinimum.x - v.x; |
717 | 0 | else if (v.x > mMaximum.x) |
718 | 0 | maxDist.x = v.x - mMaximum.x; |
719 | 0 |
|
720 | 0 | if (v.y < mMinimum.y) |
721 | 0 | maxDist.y = mMinimum.y - v.y; |
722 | 0 | else if (v.y > mMaximum.y) |
723 | 0 | maxDist.y = v.y - mMaximum.y; |
724 | 0 |
|
725 | 0 | if (v.z < mMinimum.z) |
726 | 0 | maxDist.z = mMinimum.z - v.z; |
727 | 0 | else if (v.z > mMaximum.z) |
728 | 0 | maxDist.z = v.z - mMaximum.z; |
729 | 0 |
|
730 | 0 | return maxDist.squaredLength(); |
731 | 0 | } |
732 | 0 | } |
733 | | |
734 | | /** Returns the minimum distance between a given point and any part of the box. */ |
735 | | Real distance (const Vector3& v) const |
736 | 0 | { |
737 | 0 | return Ogre::Math::Sqrt(squaredDistance(v)); |
738 | 0 | } |
739 | | |
740 | | /** Tests whether another box contained by this box. |
741 | | */ |
742 | | bool contains(const AxisAlignedBox& other) const |
743 | 0 | { |
744 | 0 | if (other.isNull() || this->isInfinite()) |
745 | 0 | return true; |
746 | 0 |
|
747 | 0 | if (this->isNull() || other.isInfinite()) |
748 | 0 | return false; |
749 | 0 |
|
750 | 0 | return this->mMinimum.x <= other.mMinimum.x && |
751 | 0 | this->mMinimum.y <= other.mMinimum.y && |
752 | 0 | this->mMinimum.z <= other.mMinimum.z && |
753 | 0 | other.mMaximum.x <= this->mMaximum.x && |
754 | 0 | other.mMaximum.y <= this->mMaximum.y && |
755 | 0 | other.mMaximum.z <= this->mMaximum.z; |
756 | 0 | } |
757 | | |
758 | | /** Tests 2 boxes for equality. |
759 | | */ |
760 | | bool operator== (const AxisAlignedBox& rhs) const |
761 | 0 | { |
762 | 0 | if (this->mExtent != rhs.mExtent) |
763 | 0 | return false; |
764 | 0 |
|
765 | 0 | if (!this->isFinite()) |
766 | 0 | return true; |
767 | 0 |
|
768 | 0 | return this->mMinimum == rhs.mMinimum && |
769 | 0 | this->mMaximum == rhs.mMaximum; |
770 | 0 | } |
771 | | |
772 | | /** Tests 2 boxes for inequality. |
773 | | */ |
774 | | bool operator!= (const AxisAlignedBox& rhs) const |
775 | 0 | { |
776 | 0 | return !(*this == rhs); |
777 | 0 | } |
778 | | |
779 | | // special values |
780 | | static const AxisAlignedBox BOX_NULL; |
781 | | static const AxisAlignedBox BOX_INFINITE; |
782 | | |
783 | | |
784 | | }; |
785 | | |
786 | | _OgreExport std::ostream& operator<<(std::ostream& o, const AxisAlignedBox& aab); |
787 | | |
788 | | /** @} */ |
789 | | /** @} */ |
790 | | } // namespace Ogre |
791 | | |
792 | | #endif |