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-2012 Torus Knot Software Ltd 00008 00009 Permission is hereby granted, free of charge, to any person obtaining a copy 00010 of this software and associated documentation files (the "Software"), to deal 00011 in the Software without restriction, including without limitation the rights 00012 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00013 copies of the Software, and to permit persons to whom the Software is 00014 furnished to do so, subject to the following conditions: 00015 00016 The above copyright notice and this permission notice shall be included in 00017 all copies or substantial portions of the Software. 00018 00019 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00020 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00021 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00022 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00023 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00024 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00025 THE SOFTWARE. 00026 ----------------------------------------------------------------------------- 00027 */ 00028 #ifndef __AxisAlignedBox_H_ 00029 #define __AxisAlignedBox_H_ 00030 00031 // Precompiler options 00032 #include "OgrePrerequisites.h" 00033 00034 #include "OgreVector3.h" 00035 #include "OgreMatrix4.h" 00036 00037 namespace Ogre { 00054 class _OgreExport AxisAlignedBox 00055 { 00056 public: 00057 enum Extent 00058 { 00059 EXTENT_NULL, 00060 EXTENT_FINITE, 00061 EXTENT_INFINITE 00062 }; 00063 protected: 00064 00065 Vector3 mMinimum; 00066 Vector3 mMaximum; 00067 Extent mExtent; 00068 mutable Vector3* mCorners; 00069 00070 public: 00071 /* 00072 1-----2 00073 /| /| 00074 / | / | 00075 5-----4 | 00076 | 0--|--3 00077 | / | / 00078 |/ |/ 00079 6-----7 00080 */ 00081 typedef enum { 00082 FAR_LEFT_BOTTOM = 0, 00083 FAR_LEFT_TOP = 1, 00084 FAR_RIGHT_TOP = 2, 00085 FAR_RIGHT_BOTTOM = 3, 00086 NEAR_RIGHT_BOTTOM = 7, 00087 NEAR_LEFT_BOTTOM = 6, 00088 NEAR_LEFT_TOP = 5, 00089 NEAR_RIGHT_TOP = 4 00090 } CornerEnum; 00091 inline AxisAlignedBox() : mMinimum(Vector3::ZERO), mMaximum(Vector3::UNIT_SCALE), mCorners(0) 00092 { 00093 // Default to a null box 00094 setMinimum( -0.5, -0.5, -0.5 ); 00095 setMaximum( 0.5, 0.5, 0.5 ); 00096 mExtent = EXTENT_NULL; 00097 } 00098 inline AxisAlignedBox(Extent e) : mMinimum(Vector3::ZERO), mMaximum(Vector3::UNIT_SCALE), mCorners(0) 00099 { 00100 setMinimum( -0.5, -0.5, -0.5 ); 00101 setMaximum( 0.5, 0.5, 0.5 ); 00102 mExtent = e; 00103 } 00104 00105 inline AxisAlignedBox(const AxisAlignedBox & rkBox) : mMinimum(Vector3::ZERO), mMaximum(Vector3::UNIT_SCALE), mCorners(0) 00106 00107 { 00108 if (rkBox.isNull()) 00109 setNull(); 00110 else if (rkBox.isInfinite()) 00111 setInfinite(); 00112 else 00113 setExtents( rkBox.mMinimum, rkBox.mMaximum ); 00114 } 00115 00116 inline AxisAlignedBox( const Vector3& min, const Vector3& max ) : mMinimum(Vector3::ZERO), mMaximum(Vector3::UNIT_SCALE), mCorners(0) 00117 { 00118 setExtents( min, max ); 00119 } 00120 00121 inline AxisAlignedBox( 00122 Real mx, Real my, Real mz, 00123 Real Mx, Real My, Real Mz ) : mMinimum(Vector3::ZERO), mMaximum(Vector3::UNIT_SCALE), mCorners(0) 00124 { 00125 setExtents( mx, my, mz, Mx, My, Mz ); 00126 } 00127 00128 AxisAlignedBox& operator=(const AxisAlignedBox& rhs) 00129 { 00130 // Specifically override to avoid copying mCorners 00131 if (rhs.isNull()) 00132 setNull(); 00133 else if (rhs.isInfinite()) 00134 setInfinite(); 00135 else 00136 setExtents(rhs.mMinimum, rhs.mMaximum); 00137 00138 return *this; 00139 } 00140 00141 ~AxisAlignedBox() 00142 { 00143 if (mCorners) 00144 OGRE_FREE(mCorners, MEMCATEGORY_SCENE_CONTROL); 00145 } 00146 00147 00150 inline const Vector3& getMinimum(void) const 00151 { 00152 return mMinimum; 00153 } 00154 00158 inline Vector3& getMinimum(void) 00159 { 00160 return mMinimum; 00161 } 00162 00165 inline const Vector3& getMaximum(void) const 00166 { 00167 return mMaximum; 00168 } 00169 00173 inline Vector3& getMaximum(void) 00174 { 00175 return mMaximum; 00176 } 00177 00178 00181 inline void setMinimum( const Vector3& vec ) 00182 { 00183 mExtent = EXTENT_FINITE; 00184 mMinimum = vec; 00185 } 00186 00187 inline void setMinimum( Real x, Real y, Real z ) 00188 { 00189 mExtent = EXTENT_FINITE; 00190 mMinimum.x = x; 00191 mMinimum.y = y; 00192 mMinimum.z = z; 00193 } 00194 00198 inline void setMinimumX(Real x) 00199 { 00200 mMinimum.x = x; 00201 } 00202 00203 inline void setMinimumY(Real y) 00204 { 00205 mMinimum.y = y; 00206 } 00207 00208 inline void setMinimumZ(Real z) 00209 { 00210 mMinimum.z = z; 00211 } 00212 00215 inline void setMaximum( const Vector3& vec ) 00216 { 00217 mExtent = EXTENT_FINITE; 00218 mMaximum = vec; 00219 } 00220 00221 inline void setMaximum( Real x, Real y, Real z ) 00222 { 00223 mExtent = EXTENT_FINITE; 00224 mMaximum.x = x; 00225 mMaximum.y = y; 00226 mMaximum.z = z; 00227 } 00228 00232 inline void setMaximumX( Real x ) 00233 { 00234 mMaximum.x = x; 00235 } 00236 00237 inline void setMaximumY( Real y ) 00238 { 00239 mMaximum.y = y; 00240 } 00241 00242 inline void setMaximumZ( Real z ) 00243 { 00244 mMaximum.z = z; 00245 } 00246 00249 inline void setExtents( const Vector3& min, const Vector3& max ) 00250 { 00251 assert( (min.x <= max.x && min.y <= max.y && min.z <= max.z) && 00252 "The minimum corner of the box must be less than or equal to maximum corner" ); 00253 00254 mExtent = EXTENT_FINITE; 00255 mMinimum = min; 00256 mMaximum = max; 00257 } 00258 00259 inline void setExtents( 00260 Real mx, Real my, Real mz, 00261 Real Mx, Real My, Real Mz ) 00262 { 00263 assert( (mx <= Mx && my <= My && mz <= Mz) && 00264 "The minimum corner of the box must be less than or equal to maximum corner" ); 00265 00266 mExtent = EXTENT_FINITE; 00267 00268 mMinimum.x = mx; 00269 mMinimum.y = my; 00270 mMinimum.z = mz; 00271 00272 mMaximum.x = Mx; 00273 mMaximum.y = My; 00274 mMaximum.z = Mz; 00275 00276 } 00277 00302 inline const Vector3* getAllCorners(void) const 00303 { 00304 assert( (mExtent == EXTENT_FINITE) && "Can't get corners of a null or infinite AAB" ); 00305 00306 // The order of these items is, using right-handed co-ordinates: 00307 // Minimum Z face, starting with Min(all), then anticlockwise 00308 // around face (looking onto the face) 00309 // Maximum Z face, starting with Max(all), then anticlockwise 00310 // around face (looking onto the face) 00311 // Only for optimization/compatibility. 00312 if (!mCorners) 00313 mCorners = OGRE_ALLOC_T(Vector3, 8, MEMCATEGORY_SCENE_CONTROL); 00314 00315 mCorners[0] = mMinimum; 00316 mCorners[1].x = mMinimum.x; mCorners[1].y = mMaximum.y; mCorners[1].z = mMinimum.z; 00317 mCorners[2].x = mMaximum.x; mCorners[2].y = mMaximum.y; mCorners[2].z = mMinimum.z; 00318 mCorners[3].x = mMaximum.x; mCorners[3].y = mMinimum.y; mCorners[3].z = mMinimum.z; 00319 00320 mCorners[4] = mMaximum; 00321 mCorners[5].x = mMinimum.x; mCorners[5].y = mMaximum.y; mCorners[5].z = mMaximum.z; 00322 mCorners[6].x = mMinimum.x; mCorners[6].y = mMinimum.y; mCorners[6].z = mMaximum.z; 00323 mCorners[7].x = mMaximum.x; mCorners[7].y = mMinimum.y; mCorners[7].z = mMaximum.z; 00324 00325 return mCorners; 00326 } 00327 00330 Vector3 getCorner(CornerEnum cornerToGet) const 00331 { 00332 switch(cornerToGet) 00333 { 00334 case FAR_LEFT_BOTTOM: 00335 return mMinimum; 00336 case FAR_LEFT_TOP: 00337 return Vector3(mMinimum.x, mMaximum.y, mMinimum.z); 00338 case FAR_RIGHT_TOP: 00339 return Vector3(mMaximum.x, mMaximum.y, mMinimum.z); 00340 case FAR_RIGHT_BOTTOM: 00341 return Vector3(mMaximum.x, mMinimum.y, mMinimum.z); 00342 case NEAR_RIGHT_BOTTOM: 00343 return Vector3(mMaximum.x, mMinimum.y, mMaximum.z); 00344 case NEAR_LEFT_BOTTOM: 00345 return Vector3(mMinimum.x, mMinimum.y, mMaximum.z); 00346 case NEAR_LEFT_TOP: 00347 return Vector3(mMinimum.x, mMaximum.y, mMaximum.z); 00348 case NEAR_RIGHT_TOP: 00349 return mMaximum; 00350 default: 00351 return Vector3(); 00352 } 00353 } 00354 00355 _OgreExport friend std::ostream& operator<<( std::ostream& o, const AxisAlignedBox aab ) 00356 { 00357 switch (aab.mExtent) 00358 { 00359 case EXTENT_NULL: 00360 o << "AxisAlignedBox(null)"; 00361 return o; 00362 00363 case EXTENT_FINITE: 00364 o << "AxisAlignedBox(min=" << aab.mMinimum << ", max=" << aab.mMaximum << ")"; 00365 return o; 00366 00367 case EXTENT_INFINITE: 00368 o << "AxisAlignedBox(infinite)"; 00369 return o; 00370 00371 default: // shut up compiler 00372 assert( false && "Never reached" ); 00373 return o; 00374 } 00375 } 00376 00380 void merge( const AxisAlignedBox& rhs ) 00381 { 00382 // Do nothing if rhs null, or this is infinite 00383 if ((rhs.mExtent == EXTENT_NULL) || (mExtent == EXTENT_INFINITE)) 00384 { 00385 return; 00386 } 00387 // Otherwise if rhs is infinite, make this infinite, too 00388 else if (rhs.mExtent == EXTENT_INFINITE) 00389 { 00390 mExtent = EXTENT_INFINITE; 00391 } 00392 // Otherwise if current null, just take rhs 00393 else if (mExtent == EXTENT_NULL) 00394 { 00395 setExtents(rhs.mMinimum, rhs.mMaximum); 00396 } 00397 // Otherwise merge 00398 else 00399 { 00400 Vector3 min = mMinimum; 00401 Vector3 max = mMaximum; 00402 max.makeCeil(rhs.mMaximum); 00403 min.makeFloor(rhs.mMinimum); 00404 00405 setExtents(min, max); 00406 } 00407 00408 } 00409 00412 inline void merge( const Vector3& point ) 00413 { 00414 switch (mExtent) 00415 { 00416 case EXTENT_NULL: // if null, use this point 00417 setExtents(point, point); 00418 return; 00419 00420 case EXTENT_FINITE: 00421 mMaximum.makeCeil(point); 00422 mMinimum.makeFloor(point); 00423 return; 00424 00425 case EXTENT_INFINITE: // if infinite, makes no difference 00426 return; 00427 } 00428 00429 assert( false && "Never reached" ); 00430 } 00431 00441 inline void transform( const Matrix4& matrix ) 00442 { 00443 // Do nothing if current null or infinite 00444 if( mExtent != EXTENT_FINITE ) 00445 return; 00446 00447 Vector3 oldMin, oldMax, currentCorner; 00448 00449 // Getting the old values so that we can use the existing merge method. 00450 oldMin = mMinimum; 00451 oldMax = mMaximum; 00452 00453 // reset 00454 setNull(); 00455 00456 // We sequentially compute the corners in the following order : 00457 // 0, 6, 5, 1, 2, 4 ,7 , 3 00458 // This sequence allows us to only change one member at a time to get at all corners. 00459 00460 // For each one, we transform it using the matrix 00461 // Which gives the resulting point and merge the resulting point. 00462 00463 // First corner 00464 // min min min 00465 currentCorner = oldMin; 00466 merge( matrix * currentCorner ); 00467 00468 // min,min,max 00469 currentCorner.z = oldMax.z; 00470 merge( matrix * currentCorner ); 00471 00472 // min max max 00473 currentCorner.y = oldMax.y; 00474 merge( matrix * currentCorner ); 00475 00476 // min max min 00477 currentCorner.z = oldMin.z; 00478 merge( matrix * currentCorner ); 00479 00480 // max max min 00481 currentCorner.x = oldMax.x; 00482 merge( matrix * currentCorner ); 00483 00484 // max max max 00485 currentCorner.z = oldMax.z; 00486 merge( matrix * currentCorner ); 00487 00488 // max min max 00489 currentCorner.y = oldMin.y; 00490 merge( matrix * currentCorner ); 00491 00492 // max min min 00493 currentCorner.z = oldMin.z; 00494 merge( matrix * currentCorner ); 00495 } 00496 00508 void transformAffine(const Matrix4& m) 00509 { 00510 assert(m.isAffine()); 00511 00512 // Do nothing if current null or infinite 00513 if ( mExtent != EXTENT_FINITE ) 00514 return; 00515 00516 Vector3 centre = getCenter(); 00517 Vector3 halfSize = getHalfSize(); 00518 00519 Vector3 newCentre = m.transformAffine(centre); 00520 Vector3 newHalfSize( 00521 Math::Abs(m[0][0]) * halfSize.x + Math::Abs(m[0][1]) * halfSize.y + Math::Abs(m[0][2]) * halfSize.z, 00522 Math::Abs(m[1][0]) * halfSize.x + Math::Abs(m[1][1]) * halfSize.y + Math::Abs(m[1][2]) * halfSize.z, 00523 Math::Abs(m[2][0]) * halfSize.x + Math::Abs(m[2][1]) * halfSize.y + Math::Abs(m[2][2]) * halfSize.z); 00524 00525 setExtents(newCentre - newHalfSize, newCentre + newHalfSize); 00526 } 00527 00530 inline void setNull() 00531 { 00532 mExtent = EXTENT_NULL; 00533 } 00534 00537 inline bool isNull(void) const 00538 { 00539 return (mExtent == EXTENT_NULL); 00540 } 00541 00544 bool isFinite(void) const 00545 { 00546 return (mExtent == EXTENT_FINITE); 00547 } 00548 00551 inline void setInfinite() 00552 { 00553 mExtent = EXTENT_INFINITE; 00554 } 00555 00558 bool isInfinite(void) const 00559 { 00560 return (mExtent == EXTENT_INFINITE); 00561 } 00562 00564 inline bool intersects(const AxisAlignedBox& b2) const 00565 { 00566 // Early-fail for nulls 00567 if (this->isNull() || b2.isNull()) 00568 return false; 00569 00570 // Early-success for infinites 00571 if (this->isInfinite() || b2.isInfinite()) 00572 return true; 00573 00574 // Use up to 6 separating planes 00575 if (mMaximum.x < b2.mMinimum.x) 00576 return false; 00577 if (mMaximum.y < b2.mMinimum.y) 00578 return false; 00579 if (mMaximum.z < b2.mMinimum.z) 00580 return false; 00581 00582 if (mMinimum.x > b2.mMaximum.x) 00583 return false; 00584 if (mMinimum.y > b2.mMaximum.y) 00585 return false; 00586 if (mMinimum.z > b2.mMaximum.z) 00587 return false; 00588 00589 // otherwise, must be intersecting 00590 return true; 00591 00592 } 00593 00595 inline AxisAlignedBox intersection(const AxisAlignedBox& b2) const 00596 { 00597 if (this->isNull() || b2.isNull()) 00598 { 00599 return AxisAlignedBox(); 00600 } 00601 else if (this->isInfinite()) 00602 { 00603 return b2; 00604 } 00605 else if (b2.isInfinite()) 00606 { 00607 return *this; 00608 } 00609 00610 Vector3 intMin = mMinimum; 00611 Vector3 intMax = mMaximum; 00612 00613 intMin.makeCeil(b2.getMinimum()); 00614 intMax.makeFloor(b2.getMaximum()); 00615 00616 // Check intersection isn't null 00617 if (intMin.x < intMax.x && 00618 intMin.y < intMax.y && 00619 intMin.z < intMax.z) 00620 { 00621 return AxisAlignedBox(intMin, intMax); 00622 } 00623 00624 return AxisAlignedBox(); 00625 } 00626 00628 Real volume(void) const 00629 { 00630 switch (mExtent) 00631 { 00632 case EXTENT_NULL: 00633 return 0.0f; 00634 00635 case EXTENT_FINITE: 00636 { 00637 Vector3 diff = mMaximum - mMinimum; 00638 return diff.x * diff.y * diff.z; 00639 } 00640 00641 case EXTENT_INFINITE: 00642 return Math::POS_INFINITY; 00643 00644 default: // shut up compiler 00645 assert( false && "Never reached" ); 00646 return 0.0f; 00647 } 00648 } 00649 00651 inline void scale(const Vector3& s) 00652 { 00653 // Do nothing if current null or infinite 00654 if (mExtent != EXTENT_FINITE) 00655 return; 00656 00657 // NB assumes centered on origin 00658 Vector3 min = mMinimum * s; 00659 Vector3 max = mMaximum * s; 00660 setExtents(min, max); 00661 } 00662 00664 bool intersects(const Sphere& s) const 00665 { 00666 return Math::intersects(s, *this); 00667 } 00669 bool intersects(const Plane& p) const 00670 { 00671 return Math::intersects(p, *this); 00672 } 00674 bool intersects(const Vector3& v) const 00675 { 00676 switch (mExtent) 00677 { 00678 case EXTENT_NULL: 00679 return false; 00680 00681 case EXTENT_FINITE: 00682 return(v.x >= mMinimum.x && v.x <= mMaximum.x && 00683 v.y >= mMinimum.y && v.y <= mMaximum.y && 00684 v.z >= mMinimum.z && v.z <= mMaximum.z); 00685 00686 case EXTENT_INFINITE: 00687 return true; 00688 00689 default: // shut up compiler 00690 assert( false && "Never reached" ); 00691 return false; 00692 } 00693 } 00695 Vector3 getCenter(void) const 00696 { 00697 assert( (mExtent == EXTENT_FINITE) && "Can't get center of a null or infinite AAB" ); 00698 00699 return Vector3( 00700 (mMaximum.x + mMinimum.x) * 0.5f, 00701 (mMaximum.y + mMinimum.y) * 0.5f, 00702 (mMaximum.z + mMinimum.z) * 0.5f); 00703 } 00705 Vector3 getSize(void) const 00706 { 00707 switch (mExtent) 00708 { 00709 case EXTENT_NULL: 00710 return Vector3::ZERO; 00711 00712 case EXTENT_FINITE: 00713 return mMaximum - mMinimum; 00714 00715 case EXTENT_INFINITE: 00716 return Vector3( 00717 Math::POS_INFINITY, 00718 Math::POS_INFINITY, 00719 Math::POS_INFINITY); 00720 00721 default: // shut up compiler 00722 assert( false && "Never reached" ); 00723 return Vector3::ZERO; 00724 } 00725 } 00727 Vector3 getHalfSize(void) const 00728 { 00729 switch (mExtent) 00730 { 00731 case EXTENT_NULL: 00732 return Vector3::ZERO; 00733 00734 case EXTENT_FINITE: 00735 return (mMaximum - mMinimum) * 0.5; 00736 00737 case EXTENT_INFINITE: 00738 return Vector3( 00739 Math::POS_INFINITY, 00740 Math::POS_INFINITY, 00741 Math::POS_INFINITY); 00742 00743 default: // shut up compiler 00744 assert( false && "Never reached" ); 00745 return Vector3::ZERO; 00746 } 00747 } 00748 00751 bool contains(const Vector3& v) const 00752 { 00753 if (isNull()) 00754 return false; 00755 if (isInfinite()) 00756 return true; 00757 00758 return mMinimum.x <= v.x && v.x <= mMaximum.x && 00759 mMinimum.y <= v.y && v.y <= mMaximum.y && 00760 mMinimum.z <= v.z && v.z <= mMaximum.z; 00761 } 00762 00764 Real distance(const Vector3& v) const 00765 { 00766 00767 if (this->contains(v)) 00768 return 0; 00769 else 00770 { 00771 Real maxDist = std::numeric_limits<Real>::min(); 00772 00773 if (v.x < mMinimum.x) 00774 maxDist = std::max(maxDist, mMinimum.x - v.x); 00775 if (v.y < mMinimum.y) 00776 maxDist = std::max(maxDist, mMinimum.y - v.y); 00777 if (v.z < mMinimum.z) 00778 maxDist = std::max(maxDist, mMinimum.z - v.z); 00779 00780 if (v.x > mMaximum.x) 00781 maxDist = std::max(maxDist, v.x - mMaximum.x); 00782 if (v.y > mMaximum.y) 00783 maxDist = std::max(maxDist, v.y - mMaximum.y); 00784 if (v.z > mMaximum.z) 00785 maxDist = std::max(maxDist, v.z - mMaximum.z); 00786 00787 return maxDist; 00788 } 00789 } 00790 00793 bool contains(const AxisAlignedBox& other) const 00794 { 00795 if (other.isNull() || this->isInfinite()) 00796 return true; 00797 00798 if (this->isNull() || other.isInfinite()) 00799 return false; 00800 00801 return this->mMinimum.x <= other.mMinimum.x && 00802 this->mMinimum.y <= other.mMinimum.y && 00803 this->mMinimum.z <= other.mMinimum.z && 00804 other.mMaximum.x <= this->mMaximum.x && 00805 other.mMaximum.y <= this->mMaximum.y && 00806 other.mMaximum.z <= this->mMaximum.z; 00807 } 00808 00811 bool operator== (const AxisAlignedBox& rhs) const 00812 { 00813 if (this->mExtent != rhs.mExtent) 00814 return false; 00815 00816 if (!this->isFinite()) 00817 return true; 00818 00819 return this->mMinimum == rhs.mMinimum && 00820 this->mMaximum == rhs.mMaximum; 00821 } 00822 00825 bool operator!= (const AxisAlignedBox& rhs) const 00826 { 00827 return !(*this == rhs); 00828 } 00829 00830 // special values 00831 static const AxisAlignedBox BOX_NULL; 00832 static const AxisAlignedBox BOX_INFINITE; 00833 00834 00835 }; 00836 00839 } // namespace Ogre 00840 00841 #endif
Copyright © 2012 Torus Knot Software Ltd
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
Last modified Fri May 25 23:36:23 2012