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-2013 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 00301 inline const Vector3* getAllCorners(void) const 00302 { 00303 assert( (mExtent == EXTENT_FINITE) && "Can't get corners of a null or infinite AAB" ); 00304 00305 // The order of these items is, using right-handed co-ordinates: 00306 // Minimum Z face, starting with Min(all), then anticlockwise 00307 // around face (looking onto the face) 00308 // Maximum Z face, starting with Max(all), then anticlockwise 00309 // around face (looking onto the face) 00310 // Only for optimization/compatibility. 00311 if (!mCorners) 00312 mCorners = OGRE_ALLOC_T(Vector3, 8, MEMCATEGORY_SCENE_CONTROL); 00313 00314 mCorners[0] = mMinimum; 00315 mCorners[1].x = mMinimum.x; mCorners[1].y = mMaximum.y; mCorners[1].z = mMinimum.z; 00316 mCorners[2].x = mMaximum.x; mCorners[2].y = mMaximum.y; mCorners[2].z = mMinimum.z; 00317 mCorners[3].x = mMaximum.x; mCorners[3].y = mMinimum.y; mCorners[3].z = mMinimum.z; 00318 00319 mCorners[4] = mMaximum; 00320 mCorners[5].x = mMinimum.x; mCorners[5].y = mMaximum.y; mCorners[5].z = mMaximum.z; 00321 mCorners[6].x = mMinimum.x; mCorners[6].y = mMinimum.y; mCorners[6].z = mMaximum.z; 00322 mCorners[7].x = mMaximum.x; mCorners[7].y = mMinimum.y; mCorners[7].z = mMaximum.z; 00323 00324 return mCorners; 00325 } 00326 00329 Vector3 getCorner(CornerEnum cornerToGet) const 00330 { 00331 switch(cornerToGet) 00332 { 00333 case FAR_LEFT_BOTTOM: 00334 return mMinimum; 00335 case FAR_LEFT_TOP: 00336 return Vector3(mMinimum.x, mMaximum.y, mMinimum.z); 00337 case FAR_RIGHT_TOP: 00338 return Vector3(mMaximum.x, mMaximum.y, mMinimum.z); 00339 case FAR_RIGHT_BOTTOM: 00340 return Vector3(mMaximum.x, mMinimum.y, mMinimum.z); 00341 case NEAR_RIGHT_BOTTOM: 00342 return Vector3(mMaximum.x, mMinimum.y, mMaximum.z); 00343 case NEAR_LEFT_BOTTOM: 00344 return Vector3(mMinimum.x, mMinimum.y, mMaximum.z); 00345 case NEAR_LEFT_TOP: 00346 return Vector3(mMinimum.x, mMaximum.y, mMaximum.z); 00347 case NEAR_RIGHT_TOP: 00348 return mMaximum; 00349 default: 00350 return Vector3(); 00351 } 00352 } 00353 00354 _OgreExport friend std::ostream& operator<<( std::ostream& o, const AxisAlignedBox &aab ) 00355 { 00356 switch (aab.mExtent) 00357 { 00358 case EXTENT_NULL: 00359 o << "AxisAlignedBox(null)"; 00360 return o; 00361 00362 case EXTENT_FINITE: 00363 o << "AxisAlignedBox(min=" << aab.mMinimum << ", max=" << aab.mMaximum << ")"; 00364 return o; 00365 00366 case EXTENT_INFINITE: 00367 o << "AxisAlignedBox(infinite)"; 00368 return o; 00369 00370 default: // shut up compiler 00371 assert( false && "Never reached" ); 00372 return o; 00373 } 00374 } 00375 00379 void merge( const AxisAlignedBox& rhs ) 00380 { 00381 // Do nothing if rhs null, or this is infinite 00382 if ((rhs.mExtent == EXTENT_NULL) || (mExtent == EXTENT_INFINITE)) 00383 { 00384 return; 00385 } 00386 // Otherwise if rhs is infinite, make this infinite, too 00387 else if (rhs.mExtent == EXTENT_INFINITE) 00388 { 00389 mExtent = EXTENT_INFINITE; 00390 } 00391 // Otherwise if current null, just take rhs 00392 else if (mExtent == EXTENT_NULL) 00393 { 00394 setExtents(rhs.mMinimum, rhs.mMaximum); 00395 } 00396 // Otherwise merge 00397 else 00398 { 00399 Vector3 min = mMinimum; 00400 Vector3 max = mMaximum; 00401 max.makeCeil(rhs.mMaximum); 00402 min.makeFloor(rhs.mMinimum); 00403 00404 setExtents(min, max); 00405 } 00406 00407 } 00408 00411 inline void merge( const Vector3& point ) 00412 { 00413 switch (mExtent) 00414 { 00415 case EXTENT_NULL: // if null, use this point 00416 setExtents(point, point); 00417 return; 00418 00419 case EXTENT_FINITE: 00420 mMaximum.makeCeil(point); 00421 mMinimum.makeFloor(point); 00422 return; 00423 00424 case EXTENT_INFINITE: // if infinite, makes no difference 00425 return; 00426 } 00427 00428 assert( false && "Never reached" ); 00429 } 00430 00440 inline void transform( const Matrix4& matrix ) 00441 { 00442 // Do nothing if current null or infinite 00443 if( mExtent != EXTENT_FINITE ) 00444 return; 00445 00446 Vector3 oldMin, oldMax, currentCorner; 00447 00448 // Getting the old values so that we can use the existing merge method. 00449 oldMin = mMinimum; 00450 oldMax = mMaximum; 00451 00452 // reset 00453 setNull(); 00454 00455 // We sequentially compute the corners in the following order : 00456 // 0, 6, 5, 1, 2, 4 ,7 , 3 00457 // This sequence allows us to only change one member at a time to get at all corners. 00458 00459 // For each one, we transform it using the matrix 00460 // Which gives the resulting point and merge the resulting point. 00461 00462 // First corner 00463 // min min min 00464 currentCorner = oldMin; 00465 merge( matrix * currentCorner ); 00466 00467 // min,min,max 00468 currentCorner.z = oldMax.z; 00469 merge( matrix * currentCorner ); 00470 00471 // min max max 00472 currentCorner.y = oldMax.y; 00473 merge( matrix * currentCorner ); 00474 00475 // min max min 00476 currentCorner.z = oldMin.z; 00477 merge( matrix * currentCorner ); 00478 00479 // max max min 00480 currentCorner.x = oldMax.x; 00481 merge( matrix * currentCorner ); 00482 00483 // max max max 00484 currentCorner.z = oldMax.z; 00485 merge( matrix * currentCorner ); 00486 00487 // max min max 00488 currentCorner.y = oldMin.y; 00489 merge( matrix * currentCorner ); 00490 00491 // max min min 00492 currentCorner.z = oldMin.z; 00493 merge( matrix * currentCorner ); 00494 } 00495 00507 void transformAffine(const Matrix4& m) 00508 { 00509 assert(m.isAffine()); 00510 00511 // Do nothing if current null or infinite 00512 if ( mExtent != EXTENT_FINITE ) 00513 return; 00514 00515 Vector3 centre = getCenter(); 00516 Vector3 halfSize = getHalfSize(); 00517 00518 Vector3 newCentre = m.transformAffine(centre); 00519 Vector3 newHalfSize( 00520 Math::Abs(m[0][0]) * halfSize.x + Math::Abs(m[0][1]) * halfSize.y + Math::Abs(m[0][2]) * halfSize.z, 00521 Math::Abs(m[1][0]) * halfSize.x + Math::Abs(m[1][1]) * halfSize.y + Math::Abs(m[1][2]) * halfSize.z, 00522 Math::Abs(m[2][0]) * halfSize.x + Math::Abs(m[2][1]) * halfSize.y + Math::Abs(m[2][2]) * halfSize.z); 00523 00524 setExtents(newCentre - newHalfSize, newCentre + newHalfSize); 00525 } 00526 00529 inline void setNull() 00530 { 00531 mExtent = EXTENT_NULL; 00532 } 00533 00536 inline bool isNull(void) const 00537 { 00538 return (mExtent == EXTENT_NULL); 00539 } 00540 00543 bool isFinite(void) const 00544 { 00545 return (mExtent == EXTENT_FINITE); 00546 } 00547 00550 inline void setInfinite() 00551 { 00552 mExtent = EXTENT_INFINITE; 00553 } 00554 00557 bool isInfinite(void) const 00558 { 00559 return (mExtent == EXTENT_INFINITE); 00560 } 00561 00563 inline bool intersects(const AxisAlignedBox& b2) const 00564 { 00565 // Early-fail for nulls 00566 if (this->isNull() || b2.isNull()) 00567 return false; 00568 00569 // Early-success for infinites 00570 if (this->isInfinite() || b2.isInfinite()) 00571 return true; 00572 00573 // Use up to 6 separating planes 00574 if (mMaximum.x < b2.mMinimum.x) 00575 return false; 00576 if (mMaximum.y < b2.mMinimum.y) 00577 return false; 00578 if (mMaximum.z < b2.mMinimum.z) 00579 return false; 00580 00581 if (mMinimum.x > b2.mMaximum.x) 00582 return false; 00583 if (mMinimum.y > b2.mMaximum.y) 00584 return false; 00585 if (mMinimum.z > b2.mMaximum.z) 00586 return false; 00587 00588 // otherwise, must be intersecting 00589 return true; 00590 00591 } 00592 00594 inline AxisAlignedBox intersection(const AxisAlignedBox& b2) const 00595 { 00596 if (this->isNull() || b2.isNull()) 00597 { 00598 return AxisAlignedBox(); 00599 } 00600 else if (this->isInfinite()) 00601 { 00602 return b2; 00603 } 00604 else if (b2.isInfinite()) 00605 { 00606 return *this; 00607 } 00608 00609 Vector3 intMin = mMinimum; 00610 Vector3 intMax = mMaximum; 00611 00612 intMin.makeCeil(b2.getMinimum()); 00613 intMax.makeFloor(b2.getMaximum()); 00614 00615 // Check intersection isn't null 00616 if (intMin.x < intMax.x && 00617 intMin.y < intMax.y && 00618 intMin.z < intMax.z) 00619 { 00620 return AxisAlignedBox(intMin, intMax); 00621 } 00622 00623 return AxisAlignedBox(); 00624 } 00625 00627 Real volume(void) const 00628 { 00629 switch (mExtent) 00630 { 00631 case EXTENT_NULL: 00632 return 0.0f; 00633 00634 case EXTENT_FINITE: 00635 { 00636 Vector3 diff = mMaximum - mMinimum; 00637 return diff.x * diff.y * diff.z; 00638 } 00639 00640 case EXTENT_INFINITE: 00641 return Math::POS_INFINITY; 00642 00643 default: // shut up compiler 00644 assert( false && "Never reached" ); 00645 return 0.0f; 00646 } 00647 } 00648 00650 inline void scale(const Vector3& s) 00651 { 00652 // Do nothing if current null or infinite 00653 if (mExtent != EXTENT_FINITE) 00654 return; 00655 00656 // NB assumes centered on origin 00657 Vector3 min = mMinimum * s; 00658 Vector3 max = mMaximum * s; 00659 setExtents(min, max); 00660 } 00661 00663 bool intersects(const Sphere& s) const 00664 { 00665 return Math::intersects(s, *this); 00666 } 00668 bool intersects(const Plane& p) const 00669 { 00670 return Math::intersects(p, *this); 00671 } 00673 bool intersects(const Vector3& v) const 00674 { 00675 switch (mExtent) 00676 { 00677 case EXTENT_NULL: 00678 return false; 00679 00680 case EXTENT_FINITE: 00681 return(v.x >= mMinimum.x && v.x <= mMaximum.x && 00682 v.y >= mMinimum.y && v.y <= mMaximum.y && 00683 v.z >= mMinimum.z && v.z <= mMaximum.z); 00684 00685 case EXTENT_INFINITE: 00686 return true; 00687 00688 default: // shut up compiler 00689 assert( false && "Never reached" ); 00690 return false; 00691 } 00692 } 00694 Vector3 getCenter(void) const 00695 { 00696 assert( (mExtent == EXTENT_FINITE) && "Can't get center of a null or infinite AAB" ); 00697 00698 return Vector3( 00699 (mMaximum.x + mMinimum.x) * 0.5f, 00700 (mMaximum.y + mMinimum.y) * 0.5f, 00701 (mMaximum.z + mMinimum.z) * 0.5f); 00702 } 00704 Vector3 getSize(void) const 00705 { 00706 switch (mExtent) 00707 { 00708 case EXTENT_NULL: 00709 return Vector3::ZERO; 00710 00711 case EXTENT_FINITE: 00712 return mMaximum - mMinimum; 00713 00714 case EXTENT_INFINITE: 00715 return Vector3( 00716 Math::POS_INFINITY, 00717 Math::POS_INFINITY, 00718 Math::POS_INFINITY); 00719 00720 default: // shut up compiler 00721 assert( false && "Never reached" ); 00722 return Vector3::ZERO; 00723 } 00724 } 00726 Vector3 getHalfSize(void) const 00727 { 00728 switch (mExtent) 00729 { 00730 case EXTENT_NULL: 00731 return Vector3::ZERO; 00732 00733 case EXTENT_FINITE: 00734 return (mMaximum - mMinimum) * 0.5; 00735 00736 case EXTENT_INFINITE: 00737 return Vector3( 00738 Math::POS_INFINITY, 00739 Math::POS_INFINITY, 00740 Math::POS_INFINITY); 00741 00742 default: // shut up compiler 00743 assert( false && "Never reached" ); 00744 return Vector3::ZERO; 00745 } 00746 } 00747 00750 bool contains(const Vector3& v) const 00751 { 00752 if (isNull()) 00753 return false; 00754 if (isInfinite()) 00755 return true; 00756 00757 return mMinimum.x <= v.x && v.x <= mMaximum.x && 00758 mMinimum.y <= v.y && v.y <= mMaximum.y && 00759 mMinimum.z <= v.z && v.z <= mMaximum.z; 00760 } 00761 00764 Real squaredDistance(const Vector3& v) const 00765 { 00766 00767 if (this->contains(v)) 00768 return 0; 00769 else 00770 { 00771 Vector3 maxDist(0,0,0); 00772 00773 if (v.x < mMinimum.x) 00774 maxDist.x = mMinimum.x - v.x; 00775 else if (v.x > mMaximum.x) 00776 maxDist.x = v.x - mMaximum.x; 00777 00778 if (v.y < mMinimum.y) 00779 maxDist.y = mMinimum.y - v.y; 00780 else if (v.y > mMaximum.y) 00781 maxDist.y = v.y - mMaximum.y; 00782 00783 if (v.z < mMinimum.z) 00784 maxDist.z = mMinimum.z - v.z; 00785 else if (v.z > mMaximum.z) 00786 maxDist.z = v.z - mMaximum.z; 00787 00788 return maxDist.squaredLength(); 00789 } 00790 } 00791 00793 Real distance (const Vector3& v) const 00794 { 00795 return Ogre::Math::Sqrt(squaredDistance(v)); 00796 } 00797 00800 bool contains(const AxisAlignedBox& other) const 00801 { 00802 if (other.isNull() || this->isInfinite()) 00803 return true; 00804 00805 if (this->isNull() || other.isInfinite()) 00806 return false; 00807 00808 return this->mMinimum.x <= other.mMinimum.x && 00809 this->mMinimum.y <= other.mMinimum.y && 00810 this->mMinimum.z <= other.mMinimum.z && 00811 other.mMaximum.x <= this->mMaximum.x && 00812 other.mMaximum.y <= this->mMaximum.y && 00813 other.mMaximum.z <= this->mMaximum.z; 00814 } 00815 00818 bool operator== (const AxisAlignedBox& rhs) const 00819 { 00820 if (this->mExtent != rhs.mExtent) 00821 return false; 00822 00823 if (!this->isFinite()) 00824 return true; 00825 00826 return this->mMinimum == rhs.mMinimum && 00827 this->mMaximum == rhs.mMaximum; 00828 } 00829 00832 bool operator!= (const AxisAlignedBox& rhs) const 00833 { 00834 return !(*this == rhs); 00835 } 00836 00837 // special values 00838 static const AxisAlignedBox BOX_NULL; 00839 static const AxisAlignedBox BOX_INFINITE; 00840 00841 00842 }; 00843 00846 } // namespace Ogre 00847 00848 #endif
Copyright © 2012 Torus Knot Software Ltd

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
Last modified Mon Jul 27 2020 13:40:40