/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 | | // 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 | |
|
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 | |
|
235 | 0 | mExtent = EXTENT_FINITE; |
236 | |
|
237 | 0 | mMinimum.x = mx; |
238 | 0 | mMinimum.y = my; |
239 | 0 | mMinimum.z = mz; |
240 | |
|
241 | 0 | mMaximum.x = Mx; |
242 | 0 | mMaximum.y = My; |
243 | 0 | mMaximum.z = Mz; |
244 | |
|
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 | | friend std::ostream& operator<<( std::ostream& o, const AxisAlignedBox &aab ) |
323 | 0 | { |
324 | 0 | switch (aab.mExtent) |
325 | 0 | { |
326 | 0 | case EXTENT_NULL: |
327 | 0 | o << "AxisAlignedBox(null)"; |
328 | 0 | return o; |
329 | | |
330 | 0 | case EXTENT_FINITE: |
331 | 0 | o << "AxisAlignedBox(min=" << aab.mMinimum << ", max=" << aab.mMaximum << ")"; |
332 | 0 | return o; |
333 | | |
334 | 0 | case EXTENT_INFINITE: |
335 | 0 | o << "AxisAlignedBox(infinite)"; |
336 | 0 | return o; |
337 | | |
338 | 0 | default: // shut up compiler |
339 | 0 | assert( false && "Never reached" ); |
340 | 0 | return o; |
341 | 0 | } |
342 | 0 | } |
343 | | |
344 | | /** Merges the passed in box into the current box. The result is the |
345 | | box which encompasses both. |
346 | | */ |
347 | | void merge( const AxisAlignedBox& rhs ) |
348 | 0 | { |
349 | | // Do nothing if rhs null, or this is infinite |
350 | 0 | if ((rhs.mExtent == EXTENT_NULL) || (mExtent == EXTENT_INFINITE)) |
351 | 0 | { |
352 | 0 | return; |
353 | 0 | } |
354 | | // Otherwise if rhs is infinite, make this infinite, too |
355 | 0 | else if (rhs.mExtent == EXTENT_INFINITE) |
356 | 0 | { |
357 | 0 | mExtent = EXTENT_INFINITE; |
358 | 0 | } |
359 | | // Otherwise if current null, just take rhs |
360 | 0 | else if (mExtent == EXTENT_NULL) |
361 | 0 | { |
362 | 0 | setExtents(rhs.mMinimum, rhs.mMaximum); |
363 | 0 | } |
364 | | // Otherwise merge |
365 | 0 | else |
366 | 0 | { |
367 | 0 | Vector3 min = mMinimum; |
368 | 0 | Vector3 max = mMaximum; |
369 | 0 | max.makeCeil(rhs.mMaximum); |
370 | 0 | min.makeFloor(rhs.mMinimum); |
371 | |
|
372 | 0 | setExtents(min, max); |
373 | 0 | } |
374 | |
|
375 | 0 | } |
376 | | |
377 | | /** Extends the box to encompass the specified point (if needed). |
378 | | */ |
379 | | inline void merge( const Vector3& point ) |
380 | 0 | { |
381 | 0 | switch (mExtent) |
382 | 0 | { |
383 | 0 | case EXTENT_NULL: // if null, use this point |
384 | 0 | setExtents(point, point); |
385 | 0 | return; |
386 | | |
387 | 0 | case EXTENT_FINITE: |
388 | 0 | mMaximum.makeCeil(point); |
389 | 0 | mMinimum.makeFloor(point); |
390 | 0 | return; |
391 | | |
392 | 0 | case EXTENT_INFINITE: // if infinite, makes no difference |
393 | 0 | return; |
394 | 0 | } |
395 | | |
396 | 0 | assert( false && "Never reached" ); |
397 | 0 | } |
398 | | |
399 | | /** Transforms the box according to the matrix supplied. |
400 | | |
401 | | By calling this method you get the axis-aligned box which |
402 | | surrounds the transformed version of this box. Therefore each |
403 | | corner of the box is transformed by the matrix, then the |
404 | | extents are mapped back onto the axes to produce another |
405 | | AABB. Useful when you have a local AABB for an object which |
406 | | is then transformed. |
407 | | */ |
408 | | inline void transform( const Matrix4& matrix ) |
409 | 0 | { |
410 | 0 | // Do nothing if current null or infinite |
411 | 0 | if( mExtent != EXTENT_FINITE ) |
412 | 0 | return; |
413 | 0 |
|
414 | 0 | Vector3 oldMin, oldMax, currentCorner; |
415 | 0 |
|
416 | 0 | // Getting the old values so that we can use the existing merge method. |
417 | 0 | oldMin = mMinimum; |
418 | 0 | oldMax = mMaximum; |
419 | 0 |
|
420 | 0 | // reset |
421 | 0 | setNull(); |
422 | 0 |
|
423 | 0 | // We sequentially compute the corners in the following order : |
424 | 0 | // 0, 6, 5, 1, 2, 4 ,7 , 3 |
425 | 0 | // This sequence allows us to only change one member at a time to get at all corners. |
426 | 0 |
|
427 | 0 | // For each one, we transform it using the matrix |
428 | 0 | // Which gives the resulting point and merge the resulting point. |
429 | 0 |
|
430 | 0 | // First corner |
431 | 0 | // min min min |
432 | 0 | currentCorner = oldMin; |
433 | 0 | merge( matrix * currentCorner ); |
434 | 0 |
|
435 | 0 | // min,min,max |
436 | 0 | currentCorner.z = oldMax.z; |
437 | 0 | merge( matrix * currentCorner ); |
438 | 0 |
|
439 | 0 | // min max max |
440 | 0 | currentCorner.y = oldMax.y; |
441 | 0 | merge( matrix * currentCorner ); |
442 | 0 |
|
443 | 0 | // min max min |
444 | 0 | currentCorner.z = oldMin.z; |
445 | 0 | merge( matrix * currentCorner ); |
446 | 0 |
|
447 | 0 | // max max min |
448 | 0 | currentCorner.x = oldMax.x; |
449 | 0 | merge( matrix * currentCorner ); |
450 | 0 |
|
451 | 0 | // max max max |
452 | 0 | currentCorner.z = oldMax.z; |
453 | 0 | merge( matrix * currentCorner ); |
454 | 0 |
|
455 | 0 | // max min max |
456 | 0 | currentCorner.y = oldMin.y; |
457 | 0 | merge( matrix * currentCorner ); |
458 | 0 |
|
459 | 0 | // max min min |
460 | 0 | currentCorner.z = oldMin.z; |
461 | 0 | merge( matrix * currentCorner ); |
462 | 0 | } |
463 | | |
464 | | /** Transforms the box according to the affine matrix supplied. |
465 | | |
466 | | By calling this method you get the axis-aligned box which |
467 | | surrounds the transformed version of this box. Therefore each |
468 | | corner of the box is transformed by the matrix, then the |
469 | | extents are mapped back onto the axes to produce another |
470 | | AABB. Useful when you have a local AABB for an object which |
471 | | is then transformed. |
472 | | */ |
473 | | void transform(const Affine3& m) |
474 | 0 | { |
475 | | // Do nothing if current null or infinite |
476 | 0 | if ( mExtent != EXTENT_FINITE ) |
477 | 0 | return; |
478 | | |
479 | 0 | Vector3 centre = getCenter(); |
480 | 0 | Vector3 halfSize = getHalfSize(); |
481 | |
|
482 | 0 | Vector3 newCentre = m * centre; |
483 | 0 | Vector3 newHalfSize( |
484 | 0 | Math::Abs(m[0][0]) * halfSize.x + Math::Abs(m[0][1]) * halfSize.y + Math::Abs(m[0][2]) * halfSize.z, |
485 | 0 | Math::Abs(m[1][0]) * halfSize.x + Math::Abs(m[1][1]) * halfSize.y + Math::Abs(m[1][2]) * halfSize.z, |
486 | 0 | Math::Abs(m[2][0]) * halfSize.x + Math::Abs(m[2][1]) * halfSize.y + Math::Abs(m[2][2]) * halfSize.z); |
487 | |
|
488 | 0 | setExtents(newCentre - newHalfSize, newCentre + newHalfSize); |
489 | 0 | } |
490 | | |
491 | | /** Sets the box to a 'null' value i.e. not a box. |
492 | | */ |
493 | | inline void setNull() |
494 | 0 | { |
495 | 0 | mExtent = EXTENT_NULL; |
496 | 0 | } |
497 | | |
498 | | /** Returns true if the box is null i.e. empty. |
499 | | */ |
500 | | inline bool isNull(void) const |
501 | 0 | { |
502 | 0 | return (mExtent == EXTENT_NULL); |
503 | 0 | } |
504 | | |
505 | | /** Returns true if the box is finite. |
506 | | */ |
507 | | bool isFinite(void) const |
508 | 0 | { |
509 | 0 | return (mExtent == EXTENT_FINITE); |
510 | 0 | } |
511 | | |
512 | | /** Sets the box to 'infinite' |
513 | | */ |
514 | | inline void setInfinite() |
515 | 0 | { |
516 | 0 | mExtent = EXTENT_INFINITE; |
517 | 0 | } |
518 | | |
519 | | /** Returns true if the box is infinite. |
520 | | */ |
521 | | bool isInfinite(void) const |
522 | 0 | { |
523 | 0 | return (mExtent == EXTENT_INFINITE); |
524 | 0 | } |
525 | | |
526 | | /** Returns whether or not this box intersects another. */ |
527 | | inline bool intersects(const AxisAlignedBox& b2) const |
528 | 0 | { |
529 | | // Early-fail for nulls |
530 | 0 | if (this->isNull() || b2.isNull()) |
531 | 0 | return false; |
532 | | |
533 | | // Early-success for infinites |
534 | 0 | if (this->isInfinite() || b2.isInfinite()) |
535 | 0 | return true; |
536 | | |
537 | | // Use up to 6 separating planes |
538 | 0 | if (mMaximum.x < b2.mMinimum.x) |
539 | 0 | return false; |
540 | 0 | if (mMaximum.y < b2.mMinimum.y) |
541 | 0 | return false; |
542 | 0 | if (mMaximum.z < b2.mMinimum.z) |
543 | 0 | return false; |
544 | | |
545 | 0 | if (mMinimum.x > b2.mMaximum.x) |
546 | 0 | return false; |
547 | 0 | if (mMinimum.y > b2.mMaximum.y) |
548 | 0 | return false; |
549 | 0 | if (mMinimum.z > b2.mMaximum.z) |
550 | 0 | return false; |
551 | | |
552 | | // otherwise, must be intersecting |
553 | 0 | return true; |
554 | |
|
555 | 0 | } |
556 | | |
557 | | /// Calculate the area of intersection of this box and another |
558 | | inline AxisAlignedBox intersection(const AxisAlignedBox& b2) const |
559 | 0 | { |
560 | 0 | if (this->isNull() || b2.isNull()) |
561 | 0 | { |
562 | 0 | return AxisAlignedBox(); |
563 | 0 | } |
564 | 0 | else if (this->isInfinite()) |
565 | 0 | { |
566 | 0 | return b2; |
567 | 0 | } |
568 | 0 | else if (b2.isInfinite()) |
569 | 0 | { |
570 | 0 | return *this; |
571 | 0 | } |
572 | 0 |
|
573 | 0 | Vector3 intMin = mMinimum; |
574 | 0 | Vector3 intMax = mMaximum; |
575 | 0 |
|
576 | 0 | intMin.makeCeil(b2.getMinimum()); |
577 | 0 | intMax.makeFloor(b2.getMaximum()); |
578 | 0 |
|
579 | 0 | // Check intersection isn't null |
580 | 0 | if (intMin.x < intMax.x && |
581 | 0 | intMin.y < intMax.y && |
582 | 0 | intMin.z < intMax.z) |
583 | 0 | { |
584 | 0 | return AxisAlignedBox(intMin, intMax); |
585 | 0 | } |
586 | 0 |
|
587 | 0 | return AxisAlignedBox(); |
588 | 0 | } |
589 | | |
590 | | /// Calculate the volume of this box |
591 | | Real volume(void) const |
592 | 0 | { |
593 | 0 | switch (mExtent) |
594 | 0 | { |
595 | 0 | case EXTENT_NULL: |
596 | 0 | return 0.0f; |
597 | 0 |
|
598 | 0 | case EXTENT_FINITE: |
599 | 0 | { |
600 | 0 | Vector3 diff = mMaximum - mMinimum; |
601 | 0 | return diff.x * diff.y * diff.z; |
602 | 0 | } |
603 | 0 |
|
604 | 0 | case EXTENT_INFINITE: |
605 | 0 | return Math::POS_INFINITY; |
606 | 0 |
|
607 | 0 | default: // shut up compiler |
608 | 0 | assert( false && "Never reached" ); |
609 | 0 | return 0.0f; |
610 | 0 | } |
611 | 0 | } |
612 | | |
613 | | /** Scales the AABB by the vector given. */ |
614 | | inline void scale(const Vector3& s) |
615 | 0 | { |
616 | 0 | // Do nothing if current null or infinite |
617 | 0 | if (mExtent != EXTENT_FINITE) |
618 | 0 | return; |
619 | 0 |
|
620 | 0 | // NB assumes centered on origin |
621 | 0 | Vector3 min = mMinimum * s; |
622 | 0 | Vector3 max = mMaximum * s; |
623 | 0 | setExtents(min, max); |
624 | 0 | } |
625 | | |
626 | | /** Tests whether this box intersects a sphere. */ |
627 | | bool intersects(const Sphere& s) const |
628 | 0 | { |
629 | 0 | return Math::intersects(s, *this); |
630 | 0 | } |
631 | | /** Tests whether this box intersects a plane. */ |
632 | | bool intersects(const Plane& p) const |
633 | 0 | { |
634 | 0 | return Math::intersects(p, *this); |
635 | 0 | } |
636 | | /** Tests whether the vector point is within this box. */ |
637 | | bool intersects(const Vector3& v) const |
638 | 0 | { |
639 | 0 | switch (mExtent) |
640 | 0 | { |
641 | 0 | case EXTENT_NULL: |
642 | 0 | return false; |
643 | 0 |
|
644 | 0 | case EXTENT_FINITE: |
645 | 0 | return(v.x >= mMinimum.x && v.x <= mMaximum.x && |
646 | 0 | v.y >= mMinimum.y && v.y <= mMaximum.y && |
647 | 0 | v.z >= mMinimum.z && v.z <= mMaximum.z); |
648 | 0 |
|
649 | 0 | case EXTENT_INFINITE: |
650 | 0 | return true; |
651 | 0 |
|
652 | 0 | default: // shut up compiler |
653 | 0 | assert( false && "Never reached" ); |
654 | 0 | return false; |
655 | 0 | } |
656 | 0 | } |
657 | | /// Gets the centre of the box |
658 | | Vector3 getCenter(void) const |
659 | 0 | { |
660 | 0 | assert( (mExtent == EXTENT_FINITE) && "Can't get center of a null or infinite AAB" ); |
661 | |
|
662 | 0 | return Vector3( |
663 | 0 | (mMaximum.x + mMinimum.x) * 0.5f, |
664 | 0 | (mMaximum.y + mMinimum.y) * 0.5f, |
665 | 0 | (mMaximum.z + mMinimum.z) * 0.5f); |
666 | 0 | } |
667 | | /// Gets the size of the box |
668 | | Vector3 getSize(void) const |
669 | 0 | { |
670 | 0 | switch (mExtent) |
671 | 0 | { |
672 | 0 | case EXTENT_NULL: |
673 | 0 | return Vector3::ZERO; |
674 | | |
675 | 0 | case EXTENT_FINITE: |
676 | 0 | return mMaximum - mMinimum; |
677 | | |
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 | | |
684 | 0 | default: // shut up compiler |
685 | 0 | assert( false && "Never reached" ); |
686 | 0 | return Vector3::ZERO; |
687 | 0 | } |
688 | 0 | } |
689 | | /// Gets the half-size of the box |
690 | | Vector3 getHalfSize(void) const |
691 | 0 | { |
692 | 0 | switch (mExtent) |
693 | 0 | { |
694 | 0 | case EXTENT_NULL: |
695 | 0 | return Vector3::ZERO; |
696 | | |
697 | 0 | case EXTENT_FINITE: |
698 | 0 | return (mMaximum - mMinimum) * 0.5; |
699 | | |
700 | 0 | case EXTENT_INFINITE: |
701 | 0 | return Vector3( |
702 | 0 | Math::POS_INFINITY, |
703 | 0 | Math::POS_INFINITY, |
704 | 0 | Math::POS_INFINITY); |
705 | | |
706 | 0 | default: // shut up compiler |
707 | 0 | assert( false && "Never reached" ); |
708 | 0 | return Vector3::ZERO; |
709 | 0 | } |
710 | 0 | } |
711 | | |
712 | | /** Tests whether the given point contained by this box. |
713 | | */ |
714 | | bool contains(const Vector3& v) const |
715 | 0 | { |
716 | 0 | if (isNull()) |
717 | 0 | return false; |
718 | 0 | if (isInfinite()) |
719 | 0 | return true; |
720 | 0 |
|
721 | 0 | return mMinimum.x <= v.x && v.x <= mMaximum.x && |
722 | 0 | mMinimum.y <= v.y && v.y <= mMaximum.y && |
723 | 0 | mMinimum.z <= v.z && v.z <= mMaximum.z; |
724 | 0 | } |
725 | | |
726 | | /** Returns the squared minimum distance between a given point and any part of the box. |
727 | | * This is faster than distance since avoiding a squareroot, so use if you can. */ |
728 | | Real squaredDistance(const Vector3& v) const |
729 | 0 | { |
730 | 0 |
|
731 | 0 | if (this->contains(v)) |
732 | 0 | return 0; |
733 | 0 | else |
734 | 0 | { |
735 | 0 | Vector3 maxDist(0,0,0); |
736 | 0 |
|
737 | 0 | if (v.x < mMinimum.x) |
738 | 0 | maxDist.x = mMinimum.x - v.x; |
739 | 0 | else if (v.x > mMaximum.x) |
740 | 0 | maxDist.x = v.x - mMaximum.x; |
741 | 0 |
|
742 | 0 | if (v.y < mMinimum.y) |
743 | 0 | maxDist.y = mMinimum.y - v.y; |
744 | 0 | else if (v.y > mMaximum.y) |
745 | 0 | maxDist.y = v.y - mMaximum.y; |
746 | 0 |
|
747 | 0 | if (v.z < mMinimum.z) |
748 | 0 | maxDist.z = mMinimum.z - v.z; |
749 | 0 | else if (v.z > mMaximum.z) |
750 | 0 | maxDist.z = v.z - mMaximum.z; |
751 | 0 |
|
752 | 0 | return maxDist.squaredLength(); |
753 | 0 | } |
754 | 0 | } |
755 | | |
756 | | /** Returns the minimum distance between a given point and any part of the box. */ |
757 | | Real distance (const Vector3& v) const |
758 | 0 | { |
759 | 0 | return Ogre::Math::Sqrt(squaredDistance(v)); |
760 | 0 | } |
761 | | |
762 | | /** Tests whether another box contained by this box. |
763 | | */ |
764 | | bool contains(const AxisAlignedBox& other) const |
765 | 0 | { |
766 | 0 | if (other.isNull() || this->isInfinite()) |
767 | 0 | return true; |
768 | 0 |
|
769 | 0 | if (this->isNull() || other.isInfinite()) |
770 | 0 | return false; |
771 | 0 |
|
772 | 0 | return this->mMinimum.x <= other.mMinimum.x && |
773 | 0 | this->mMinimum.y <= other.mMinimum.y && |
774 | 0 | this->mMinimum.z <= other.mMinimum.z && |
775 | 0 | other.mMaximum.x <= this->mMaximum.x && |
776 | 0 | other.mMaximum.y <= this->mMaximum.y && |
777 | 0 | other.mMaximum.z <= this->mMaximum.z; |
778 | 0 | } |
779 | | |
780 | | /** Tests 2 boxes for equality. |
781 | | */ |
782 | | bool operator== (const AxisAlignedBox& rhs) const |
783 | 0 | { |
784 | 0 | if (this->mExtent != rhs.mExtent) |
785 | 0 | return false; |
786 | 0 |
|
787 | 0 | if (!this->isFinite()) |
788 | 0 | return true; |
789 | 0 |
|
790 | 0 | return this->mMinimum == rhs.mMinimum && |
791 | 0 | this->mMaximum == rhs.mMaximum; |
792 | 0 | } |
793 | | |
794 | | /** Tests 2 boxes for inequality. |
795 | | */ |
796 | | bool operator!= (const AxisAlignedBox& rhs) const |
797 | 0 | { |
798 | 0 | return !(*this == rhs); |
799 | 0 | } |
800 | | |
801 | | // special values |
802 | | static const AxisAlignedBox BOX_NULL; |
803 | | static const AxisAlignedBox BOX_INFINITE; |
804 | | |
805 | | |
806 | | }; |
807 | | |
808 | | /** @} */ |
809 | | /** @} */ |
810 | | } // namespace Ogre |
811 | | |
812 | | #endif |