00001 /* 00002 ----------------------------------------------------------------------------- 00003 This source file is part of OGRE 00004 (Object-oriented Graphics Rendering Engine) 00005 For the latest info, see http://www.ogre3d.org/ 00006 00007 Copyright (c) 2000-2006 Torus Knot Software Ltd 00008 Also see acknowledgements in Readme.html 00009 00010 This program is free software; you can redistribute it and/or modify it under 00011 the terms of the GNU Lesser General Public License as published by the Free Software 00012 Foundation; either version 2 of the License, or (at your option) any later 00013 version. 00014 00015 This program is distributed in the hope that it will be useful, but WITHOUT 00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 00018 00019 You should have received a copy of the GNU Lesser General Public License along with 00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple 00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to 00022 http://www.gnu.org/copyleft/lesser.txt. 00023 00024 You may alternatively use this source under the terms of a specific version of 00025 the OGRE Unrestricted License provided you have obtained such a license from 00026 Torus Knot Software Ltd. 00027 ----------------------------------------------------------------------------- 00028 */ 00029 #ifndef __AxisAlignedBox_H_ 00030 #define __AxisAlignedBox_H_ 00031 00032 // Precompiler options 00033 #include "OgrePrerequisites.h" 00034 00035 #include "OgreVector3.h" 00036 #include "OgreMatrix4.h" 00037 00038 namespace Ogre { 00039 00049 class _OgreExport AxisAlignedBox 00050 { 00051 public: 00052 enum Extent 00053 { 00054 EXTENT_NULL, 00055 EXTENT_FINITE, 00056 EXTENT_INFINITE 00057 }; 00058 protected: 00059 00060 Vector3 mMinimum; 00061 Vector3 mMaximum; 00062 Extent mExtent; 00063 mutable Vector3* mpCorners; 00064 00065 public: 00066 /* 00067 1-----2 00068 /| /| 00069 / | / | 00070 5-----4 | 00071 | 0--|--3 00072 | / | / 00073 |/ |/ 00074 6-----7 00075 */ 00076 typedef enum { 00077 FAR_LEFT_BOTTOM = 0, 00078 FAR_LEFT_TOP = 1, 00079 FAR_RIGHT_TOP = 2, 00080 FAR_RIGHT_BOTTOM = 3, 00081 NEAR_RIGHT_BOTTOM = 7, 00082 NEAR_LEFT_BOTTOM = 6, 00083 NEAR_LEFT_TOP = 5, 00084 NEAR_RIGHT_TOP = 4 00085 } CornerEnum; 00086 inline AxisAlignedBox() : mpCorners(0) 00087 { 00088 // Default to a null box 00089 setMinimum( -0.5, -0.5, -0.5 ); 00090 setMaximum( 0.5, 0.5, 0.5 ); 00091 mExtent = EXTENT_NULL; 00092 } 00093 inline AxisAlignedBox(Extent e) : mpCorners(0) 00094 { 00095 setMinimum( -0.5, -0.5, -0.5 ); 00096 setMaximum( 0.5, 0.5, 0.5 ); 00097 mExtent = e; 00098 } 00099 00100 inline AxisAlignedBox(const AxisAlignedBox & rkBox) : mpCorners(0) 00101 { 00102 if (rkBox.isNull()) 00103 setNull(); 00104 else if (rkBox.isInfinite()) 00105 setInfinite(); 00106 else 00107 setExtents( rkBox.mMinimum, rkBox.mMaximum ); 00108 } 00109 00110 inline AxisAlignedBox( const Vector3& min, const Vector3& max ) : mpCorners(0) 00111 { 00112 setExtents( min, max ); 00113 } 00114 00115 inline AxisAlignedBox( 00116 Real mx, Real my, Real mz, 00117 Real Mx, Real My, Real Mz ) : mpCorners(0) 00118 { 00119 setExtents( mx, my, mz, Mx, My, Mz ); 00120 } 00121 00122 AxisAlignedBox& operator=(const AxisAlignedBox& rhs) 00123 { 00124 // Specifically override to avoid copying mpCorners 00125 if (rhs.isNull()) 00126 setNull(); 00127 else if (rhs.isInfinite()) 00128 setInfinite(); 00129 else 00130 setExtents(rhs.mMinimum, rhs.mMaximum); 00131 00132 return *this; 00133 } 00134 00135 ~AxisAlignedBox() 00136 { 00137 if (mpCorners) 00138 OGRE_FREE(mpCorners, MEMCATEGORY_SCENE_CONTROL); 00139 } 00140 00141 00144 inline const Vector3& getMinimum(void) const 00145 { 00146 return mMinimum; 00147 } 00148 00152 inline Vector3& getMinimum(void) 00153 { 00154 return mMinimum; 00155 } 00156 00159 inline const Vector3& getMaximum(void) const 00160 { 00161 return mMaximum; 00162 } 00163 00167 inline Vector3& getMaximum(void) 00168 { 00169 return mMaximum; 00170 } 00171 00172 00175 inline void setMinimum( const Vector3& vec ) 00176 { 00177 mExtent = EXTENT_FINITE; 00178 mMinimum = vec; 00179 } 00180 00181 inline void setMinimum( Real x, Real y, Real z ) 00182 { 00183 mExtent = EXTENT_FINITE; 00184 mMinimum.x = x; 00185 mMinimum.y = y; 00186 mMinimum.z = z; 00187 } 00188 00192 inline void setMinimumX(Real x) 00193 { 00194 mMinimum.x = x; 00195 } 00196 00197 inline void setMinimumY(Real y) 00198 { 00199 mMinimum.y = y; 00200 } 00201 00202 inline void setMinimumZ(Real z) 00203 { 00204 mMinimum.z = z; 00205 } 00206 00209 inline void setMaximum( const Vector3& vec ) 00210 { 00211 mExtent = EXTENT_FINITE; 00212 mMaximum = vec; 00213 } 00214 00215 inline void setMaximum( Real x, Real y, Real z ) 00216 { 00217 mExtent = EXTENT_FINITE; 00218 mMaximum.x = x; 00219 mMaximum.y = y; 00220 mMaximum.z = z; 00221 } 00222 00226 inline void setMaximumX( Real x ) 00227 { 00228 mMaximum.x = x; 00229 } 00230 00231 inline void setMaximumY( Real y ) 00232 { 00233 mMaximum.y = y; 00234 } 00235 00236 inline void setMaximumZ( Real z ) 00237 { 00238 mMaximum.z = z; 00239 } 00240 00243 inline void setExtents( const Vector3& min, const Vector3& max ) 00244 { 00245 assert( (min.x <= max.x && min.y <= max.y && min.z <= max.z) && 00246 "The minimum corner of the box must be less than or equal to maximum corner" ); 00247 00248 mExtent = EXTENT_FINITE; 00249 mMinimum = min; 00250 mMaximum = max; 00251 } 00252 00253 inline void setExtents( 00254 Real mx, Real my, Real mz, 00255 Real Mx, Real My, Real Mz ) 00256 { 00257 assert( (mx <= Mx && my <= My && mz <= Mz) && 00258 "The minimum corner of the box must be less than or equal to maximum corner" ); 00259 00260 mExtent = EXTENT_FINITE; 00261 00262 mMinimum.x = mx; 00263 mMinimum.y = my; 00264 mMinimum.z = mz; 00265 00266 mMaximum.x = Mx; 00267 mMaximum.y = My; 00268 mMaximum.z = Mz; 00269 00270 } 00271 00296 inline const Vector3* getAllCorners(void) const 00297 { 00298 assert( (mExtent == EXTENT_FINITE) && "Can't get corners of a null or infinite AAB" ); 00299 00300 // The order of these items is, using right-handed co-ordinates: 00301 // Minimum Z face, starting with Min(all), then anticlockwise 00302 // around face (looking onto the face) 00303 // Maximum Z face, starting with Max(all), then anticlockwise 00304 // around face (looking onto the face) 00305 // Only for optimization/compatibility. 00306 if (!mpCorners) 00307 mpCorners = OGRE_ALLOC_T(Vector3, 8, MEMCATEGORY_SCENE_CONTROL); 00308 00309 mpCorners[0] = mMinimum; 00310 mpCorners[1].x = mMinimum.x; mpCorners[1].y = mMaximum.y; mpCorners[1].z = mMinimum.z; 00311 mpCorners[2].x = mMaximum.x; mpCorners[2].y = mMaximum.y; mpCorners[2].z = mMinimum.z; 00312 mpCorners[3].x = mMaximum.x; mpCorners[3].y = mMinimum.y; mpCorners[3].z = mMinimum.z; 00313 00314 mpCorners[4] = mMaximum; 00315 mpCorners[5].x = mMinimum.x; mpCorners[5].y = mMaximum.y; mpCorners[5].z = mMaximum.z; 00316 mpCorners[6].x = mMinimum.x; mpCorners[6].y = mMinimum.y; mpCorners[6].z = mMaximum.z; 00317 mpCorners[7].x = mMaximum.x; mpCorners[7].y = mMinimum.y; mpCorners[7].z = mMaximum.z; 00318 00319 return mpCorners; 00320 } 00321 00324 Vector3 getCorner(CornerEnum cornerToGet) const 00325 { 00326 switch(cornerToGet) 00327 { 00328 case FAR_LEFT_BOTTOM: 00329 return mMinimum; 00330 case FAR_LEFT_TOP: 00331 return Vector3(mMinimum.x, mMaximum.y, mMinimum.z); 00332 case FAR_RIGHT_TOP: 00333 return Vector3(mMaximum.x, mMaximum.y, mMinimum.z); 00334 case FAR_RIGHT_BOTTOM: 00335 return Vector3(mMaximum.x, mMinimum.y, mMinimum.z); 00336 case NEAR_RIGHT_BOTTOM: 00337 return Vector3(mMaximum.x, mMinimum.y, mMaximum.z); 00338 case NEAR_LEFT_BOTTOM: 00339 return Vector3(mMinimum.x, mMinimum.y, mMaximum.z); 00340 case NEAR_LEFT_TOP: 00341 return Vector3(mMinimum.x, mMaximum.y, mMaximum.z); 00342 case NEAR_RIGHT_TOP: 00343 return mMaximum; 00344 default: 00345 return Vector3(); 00346 } 00347 } 00348 00349 _OgreExport friend std::ostream& operator<<( std::ostream& o, const AxisAlignedBox aab ) 00350 { 00351 switch (aab.mExtent) 00352 { 00353 case EXTENT_NULL: 00354 o << "AxisAlignedBox(null)"; 00355 return o; 00356 00357 case EXTENT_FINITE: 00358 o << "AxisAlignedBox(min=" << aab.mMinimum << ", max=" << aab.mMaximum << ")"; 00359 return o; 00360 00361 case EXTENT_INFINITE: 00362 o << "AxisAlignedBox(infinite)"; 00363 return o; 00364 00365 default: // shut up compiler 00366 assert( false && "Never reached" ); 00367 return o; 00368 } 00369 } 00370 00374 void merge( const AxisAlignedBox& rhs ) 00375 { 00376 // Do nothing if rhs null, or this is infinite 00377 if ((rhs.mExtent == EXTENT_NULL) || (mExtent == EXTENT_INFINITE)) 00378 { 00379 return; 00380 } 00381 // Otherwise if rhs is infinite, make this infinite, too 00382 else if (rhs.mExtent == EXTENT_INFINITE) 00383 { 00384 mExtent = EXTENT_INFINITE; 00385 } 00386 // Otherwise if current null, just take rhs 00387 else if (mExtent == EXTENT_NULL) 00388 { 00389 setExtents(rhs.mMinimum, rhs.mMaximum); 00390 } 00391 // Otherwise merge 00392 else 00393 { 00394 Vector3 min = mMinimum; 00395 Vector3 max = mMaximum; 00396 max.makeCeil(rhs.mMaximum); 00397 min.makeFloor(rhs.mMinimum); 00398 00399 setExtents(min, max); 00400 } 00401 00402 } 00403 00406 inline void merge( const Vector3& point ) 00407 { 00408 switch (mExtent) 00409 { 00410 case EXTENT_NULL: // if null, use this point 00411 setExtents(point, point); 00412 return; 00413 00414 case EXTENT_FINITE: 00415 mMaximum.makeCeil(point); 00416 mMinimum.makeFloor(point); 00417 return; 00418 00419 case EXTENT_INFINITE: // if infinite, makes no difference 00420 return; 00421 } 00422 00423 assert( false && "Never reached" ); 00424 } 00425 00435 inline void transform( const Matrix4& matrix ) 00436 { 00437 // Do nothing if current null or infinite 00438 if( mExtent != EXTENT_FINITE ) 00439 return; 00440 00441 Vector3 oldMin, oldMax, currentCorner; 00442 00443 // Getting the old values so that we can use the existing merge method. 00444 oldMin = mMinimum; 00445 oldMax = mMaximum; 00446 00447 // reset 00448 setNull(); 00449 00450 // We sequentially compute the corners in the following order : 00451 // 0, 6, 5, 1, 2, 4 ,7 , 3 00452 // This sequence allows us to only change one member at a time to get at all corners. 00453 00454 // For each one, we transform it using the matrix 00455 // Which gives the resulting point and merge the resulting point. 00456 00457 // First corner 00458 // min min min 00459 currentCorner = oldMin; 00460 merge( matrix * currentCorner ); 00461 00462 // min,min,max 00463 currentCorner.z = oldMax.z; 00464 merge( matrix * currentCorner ); 00465 00466 // min max max 00467 currentCorner.y = oldMax.y; 00468 merge( matrix * currentCorner ); 00469 00470 // min max min 00471 currentCorner.z = oldMin.z; 00472 merge( matrix * currentCorner ); 00473 00474 // max max min 00475 currentCorner.x = oldMax.x; 00476 merge( matrix * currentCorner ); 00477 00478 // max max max 00479 currentCorner.z = oldMax.z; 00480 merge( matrix * currentCorner ); 00481 00482 // max min max 00483 currentCorner.y = oldMin.y; 00484 merge( matrix * currentCorner ); 00485 00486 // max min min 00487 currentCorner.z = oldMin.z; 00488 merge( matrix * currentCorner ); 00489 } 00490 00502 void transformAffine(const Matrix4& m) 00503 { 00504 assert(m.isAffine()); 00505 00506 // Do nothing if current null or infinite 00507 if ( mExtent != EXTENT_FINITE ) 00508 return; 00509 00510 Vector3 centre = getCenter(); 00511 Vector3 halfSize = getHalfSize(); 00512 00513 Vector3 newCentre = m.transformAffine(centre); 00514 Vector3 newHalfSize( 00515 Math::Abs(m[0][0]) * halfSize.x + Math::Abs(m[0][1]) * halfSize.y + Math::Abs(m[0][2]) * halfSize.z, 00516 Math::Abs(m[1][0]) * halfSize.x + Math::Abs(m[1][1]) * halfSize.y + Math::Abs(m[1][2]) * halfSize.z, 00517 Math::Abs(m[2][0]) * halfSize.x + Math::Abs(m[2][1]) * halfSize.y + Math::Abs(m[2][2]) * halfSize.z); 00518 00519 setExtents(newCentre - newHalfSize, newCentre + newHalfSize); 00520 } 00521 00524 inline void setNull() 00525 { 00526 mExtent = EXTENT_NULL; 00527 } 00528 00531 inline bool isNull(void) const 00532 { 00533 return (mExtent == EXTENT_NULL); 00534 } 00535 00538 bool isFinite(void) const 00539 { 00540 return (mExtent == EXTENT_FINITE); 00541 } 00542 00545 inline void setInfinite() 00546 { 00547 mExtent = EXTENT_INFINITE; 00548 } 00549 00552 bool isInfinite(void) const 00553 { 00554 return (mExtent == EXTENT_INFINITE); 00555 } 00556 00558 inline bool intersects(const AxisAlignedBox& b2) const 00559 { 00560 // Early-fail for nulls 00561 if (this->isNull() || b2.isNull()) 00562 return false; 00563 00564 // Early-success for infinites 00565 if (this->isInfinite() || b2.isInfinite()) 00566 return true; 00567 00568 // Use up to 6 separating planes 00569 if (mMaximum.x < b2.mMinimum.x) 00570 return false; 00571 if (mMaximum.y < b2.mMinimum.y) 00572 return false; 00573 if (mMaximum.z < b2.mMinimum.z) 00574 return false; 00575 00576 if (mMinimum.x > b2.mMaximum.x) 00577 return false; 00578 if (mMinimum.y > b2.mMaximum.y) 00579 return false; 00580 if (mMinimum.z > b2.mMaximum.z) 00581 return false; 00582 00583 // otherwise, must be intersecting 00584 return true; 00585 00586 } 00587 00589 inline AxisAlignedBox intersection(const AxisAlignedBox& b2) const 00590 { 00591 if (this->isNull() || b2.isNull()) 00592 { 00593 return AxisAlignedBox(); 00594 } 00595 else if (this->isInfinite()) 00596 { 00597 return b2; 00598 } 00599 else if (b2.isInfinite()) 00600 { 00601 return *this; 00602 } 00603 00604 Vector3 intMin = mMinimum; 00605 Vector3 intMax = mMaximum; 00606 00607 intMin.makeCeil(b2.getMinimum()); 00608 intMax.makeFloor(b2.getMaximum()); 00609 00610 // Check intersection isn't null 00611 if (intMin.x < intMax.x && 00612 intMin.y < intMax.y && 00613 intMin.z < intMax.z) 00614 { 00615 return AxisAlignedBox(intMin, intMax); 00616 } 00617 00618 return AxisAlignedBox(); 00619 } 00620 00622 Real volume(void) const 00623 { 00624 switch (mExtent) 00625 { 00626 case EXTENT_NULL: 00627 return 0.0f; 00628 00629 case EXTENT_FINITE: 00630 { 00631 Vector3 diff = mMaximum - mMinimum; 00632 return diff.x * diff.y * diff.z; 00633 } 00634 00635 case EXTENT_INFINITE: 00636 return Math::POS_INFINITY; 00637 00638 default: // shut up compiler 00639 assert( false && "Never reached" ); 00640 return 0.0f; 00641 } 00642 } 00643 00645 inline void scale(const Vector3& s) 00646 { 00647 // Do nothing if current null or infinite 00648 if (mExtent != EXTENT_FINITE) 00649 return; 00650 00651 // NB assumes centered on origin 00652 Vector3 min = mMinimum * s; 00653 Vector3 max = mMaximum * s; 00654 setExtents(min, max); 00655 } 00656 00658 bool intersects(const Sphere& s) const 00659 { 00660 return Math::intersects(s, *this); 00661 } 00663 bool intersects(const Plane& p) const 00664 { 00665 return Math::intersects(p, *this); 00666 } 00668 bool intersects(const Vector3& v) const 00669 { 00670 switch (mExtent) 00671 { 00672 case EXTENT_NULL: 00673 return false; 00674 00675 case EXTENT_FINITE: 00676 return(v.x >= mMinimum.x && v.x <= mMaximum.x && 00677 v.y >= mMinimum.y && v.y <= mMaximum.y && 00678 v.z >= mMinimum.z && v.z <= mMaximum.z); 00679 00680 case EXTENT_INFINITE: 00681 return true; 00682 00683 default: // shut up compiler 00684 assert( false && "Never reached" ); 00685 return false; 00686 } 00687 } 00689 Vector3 getCenter(void) const 00690 { 00691 assert( (mExtent == EXTENT_FINITE) && "Can't get center of a null or infinite AAB" ); 00692 00693 return Vector3( 00694 (mMaximum.x + mMinimum.x) * 0.5, 00695 (mMaximum.y + mMinimum.y) * 0.5, 00696 (mMaximum.z + mMinimum.z) * 0.5); 00697 } 00699 Vector3 getSize(void) const 00700 { 00701 switch (mExtent) 00702 { 00703 case EXTENT_NULL: 00704 return Vector3::ZERO; 00705 00706 case EXTENT_FINITE: 00707 return mMaximum - mMinimum; 00708 00709 case EXTENT_INFINITE: 00710 return Vector3( 00711 Math::POS_INFINITY, 00712 Math::POS_INFINITY, 00713 Math::POS_INFINITY); 00714 00715 default: // shut up compiler 00716 assert( false && "Never reached" ); 00717 return Vector3::ZERO; 00718 } 00719 } 00721 Vector3 getHalfSize(void) const 00722 { 00723 switch (mExtent) 00724 { 00725 case EXTENT_NULL: 00726 return Vector3::ZERO; 00727 00728 case EXTENT_FINITE: 00729 return (mMaximum - mMinimum) * 0.5; 00730 00731 case EXTENT_INFINITE: 00732 return Vector3( 00733 Math::POS_INFINITY, 00734 Math::POS_INFINITY, 00735 Math::POS_INFINITY); 00736 00737 default: // shut up compiler 00738 assert( false && "Never reached" ); 00739 return Vector3::ZERO; 00740 } 00741 } 00742 00745 bool contains(const Vector3& v) const 00746 { 00747 if (isNull()) 00748 return false; 00749 if (isInfinite()) 00750 return true; 00751 00752 return mMinimum.x <= v.x && v.x <= mMaximum.x && 00753 mMinimum.y <= v.y && v.y <= mMaximum.y && 00754 mMinimum.z <= v.z && v.z <= mMaximum.z; 00755 } 00756 00759 bool contains(const AxisAlignedBox& other) const 00760 { 00761 if (other.isNull() || this->isInfinite()) 00762 return true; 00763 00764 if (this->isNull() || other.isInfinite()) 00765 return false; 00766 00767 return this->mMinimum.x <= other.mMinimum.x && 00768 this->mMinimum.y <= other.mMinimum.y && 00769 this->mMinimum.z <= other.mMinimum.z && 00770 other.mMaximum.x <= this->mMaximum.x && 00771 other.mMaximum.y <= this->mMaximum.y && 00772 other.mMaximum.z <= this->mMaximum.z; 00773 } 00774 00777 bool operator== (const AxisAlignedBox& rhs) const 00778 { 00779 if (this->mExtent != rhs.mExtent) 00780 return false; 00781 00782 if (!this->isFinite()) 00783 return true; 00784 00785 return this->mMinimum == rhs.mMinimum && 00786 this->mMaximum == rhs.mMaximum; 00787 } 00788 00791 bool operator!= (const AxisAlignedBox& rhs) const 00792 { 00793 return !(*this == rhs); 00794 } 00795 00796 // special values 00797 static const AxisAlignedBox BOX_NULL; 00798 static const AxisAlignedBox BOX_INFINITE; 00799 00800 00801 }; 00802 00803 } // namespace Ogre 00804 00805 #endif
Copyright © 2008 Torus Knot Software Ltd
This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 License.
Last modified Sun Sep 27 22:02:22 2009