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 protected: 00052 enum Extent 00053 { 00054 EXTENT_NULL, 00055 EXTENT_FINITE, 00056 EXTENT_INFINITE 00057 }; 00058 00059 Vector3 mMinimum; 00060 Vector3 mMaximum; 00061 Extent mExtent; 00062 mutable Vector3* mpCorners; 00063 00064 public: 00065 /* 00066 1-----2 00067 /| /| 00068 / | / | 00069 5-----4 | 00070 | 0--|--3 00071 | / | / 00072 |/ |/ 00073 6-----7 00074 */ 00075 typedef enum { 00076 FAR_LEFT_BOTTOM = 0, 00077 FAR_LEFT_TOP = 1, 00078 FAR_RIGHT_TOP = 2, 00079 FAR_RIGHT_BOTTOM = 3, 00080 NEAR_RIGHT_BOTTOM = 7, 00081 NEAR_LEFT_BOTTOM = 6, 00082 NEAR_LEFT_TOP = 5, 00083 NEAR_RIGHT_TOP = 4 00084 } CornerEnum; 00085 inline AxisAlignedBox() : mpCorners(0) 00086 { 00087 // Default to a null box 00088 setMinimum( -0.5, -0.5, -0.5 ); 00089 setMaximum( 0.5, 0.5, 0.5 ); 00090 mExtent = EXTENT_NULL; 00091 } 00092 00093 inline AxisAlignedBox(const AxisAlignedBox & rkBox) : mpCorners(0) 00094 { 00095 if (rkBox.isNull()) 00096 setNull(); 00097 else if (rkBox.isInfinite()) 00098 setInfinite(); 00099 else 00100 setExtents( rkBox.mMinimum, rkBox.mMaximum ); 00101 } 00102 00103 inline AxisAlignedBox( const Vector3& min, const Vector3& max ) : mpCorners(0) 00104 { 00105 setExtents( min, max ); 00106 } 00107 00108 inline AxisAlignedBox( 00109 Real mx, Real my, Real mz, 00110 Real Mx, Real My, Real Mz ) : mpCorners(0) 00111 { 00112 setExtents( mx, my, mz, Mx, My, Mz ); 00113 } 00114 00115 AxisAlignedBox& operator=(const AxisAlignedBox& rhs) 00116 { 00117 // Specifically override to avoid copying mpCorners 00118 if (rhs.isNull()) 00119 setNull(); 00120 else if (rhs.isInfinite()) 00121 setInfinite(); 00122 else 00123 setExtents(rhs.mMinimum, rhs.mMaximum); 00124 00125 return *this; 00126 } 00127 00128 ~AxisAlignedBox() 00129 { 00130 if (mpCorners) 00131 delete [] mpCorners; 00132 } 00133 00134 00137 inline const Vector3& getMinimum(void) const 00138 { 00139 return mMinimum; 00140 } 00141 00145 inline Vector3& getMinimum(void) 00146 { 00147 return mMinimum; 00148 } 00149 00152 inline const Vector3& getMaximum(void) const 00153 { 00154 return mMaximum; 00155 } 00156 00160 inline Vector3& getMaximum(void) 00161 { 00162 return mMaximum; 00163 } 00164 00165 00168 inline void setMinimum( const Vector3& vec ) 00169 { 00170 mExtent = EXTENT_FINITE; 00171 mMinimum = vec; 00172 } 00173 00174 inline void setMinimum( Real x, Real y, Real z ) 00175 { 00176 mExtent = EXTENT_FINITE; 00177 mMinimum.x = x; 00178 mMinimum.y = y; 00179 mMinimum.z = z; 00180 } 00181 00185 inline void setMinimumX(Real x) 00186 { 00187 mMinimum.x = x; 00188 } 00189 00190 inline void setMinimumY(Real y) 00191 { 00192 mMinimum.y = y; 00193 } 00194 00195 inline void setMinimumZ(Real z) 00196 { 00197 mMinimum.z = z; 00198 } 00199 00202 inline void setMaximum( const Vector3& vec ) 00203 { 00204 mExtent = EXTENT_FINITE; 00205 mMaximum = vec; 00206 } 00207 00208 inline void setMaximum( Real x, Real y, Real z ) 00209 { 00210 mExtent = EXTENT_FINITE; 00211 mMaximum.x = x; 00212 mMaximum.y = y; 00213 mMaximum.z = z; 00214 } 00215 00219 inline void setMaximumX( Real x ) 00220 { 00221 mMaximum.x = x; 00222 } 00223 00224 inline void setMaximumY( Real y ) 00225 { 00226 mMaximum.y = y; 00227 } 00228 00229 inline void setMaximumZ( Real z ) 00230 { 00231 mMaximum.z = z; 00232 } 00233 00236 inline void setExtents( const Vector3& min, const Vector3& max ) 00237 { 00238 assert( (min.x <= max.x && min.y <= max.y && min.z <= max.z) && 00239 "The minimum corner of the box must be less than or equal to maximum corner" ); 00240 00241 mExtent = EXTENT_FINITE; 00242 mMinimum = min; 00243 mMaximum = max; 00244 } 00245 00246 inline void setExtents( 00247 Real mx, Real my, Real mz, 00248 Real Mx, Real My, Real Mz ) 00249 { 00250 assert( (mx <= Mx && my <= My && mz <= Mz) && 00251 "The minimum corner of the box must be less than or equal to maximum corner" ); 00252 00253 mExtent = EXTENT_FINITE; 00254 00255 mMinimum.x = mx; 00256 mMinimum.y = my; 00257 mMinimum.z = mz; 00258 00259 mMaximum.x = Mx; 00260 mMaximum.y = My; 00261 mMaximum.z = Mz; 00262 00263 } 00264 00289 inline const Vector3* getAllCorners(void) const 00290 { 00291 assert( (mExtent == EXTENT_FINITE) && "Can't get corners of a null or infinite AAB" ); 00292 00293 // The order of these items is, using right-handed co-ordinates: 00294 // Minimum Z face, starting with Min(all), then anticlockwise 00295 // around face (looking onto the face) 00296 // Maximum Z face, starting with Max(all), then anticlockwise 00297 // around face (looking onto the face) 00298 // Only for optimization/compatibility. 00299 if (!mpCorners) 00300 mpCorners = new Vector3[8]; 00301 00302 mpCorners[0] = mMinimum; 00303 mpCorners[1].x = mMinimum.x; mpCorners[1].y = mMaximum.y; mpCorners[1].z = mMinimum.z; 00304 mpCorners[2].x = mMaximum.x; mpCorners[2].y = mMaximum.y; mpCorners[2].z = mMinimum.z; 00305 mpCorners[3].x = mMaximum.x; mpCorners[3].y = mMinimum.y; mpCorners[3].z = mMinimum.z; 00306 00307 mpCorners[4] = mMaximum; 00308 mpCorners[5].x = mMinimum.x; mpCorners[5].y = mMaximum.y; mpCorners[5].z = mMaximum.z; 00309 mpCorners[6].x = mMinimum.x; mpCorners[6].y = mMinimum.y; mpCorners[6].z = mMaximum.z; 00310 mpCorners[7].x = mMaximum.x; mpCorners[7].y = mMinimum.y; mpCorners[7].z = mMaximum.z; 00311 00312 return mpCorners; 00313 } 00314 00317 Vector3 getCorner(CornerEnum cornerToGet) const 00318 { 00319 switch(cornerToGet) 00320 { 00321 case FAR_LEFT_BOTTOM: 00322 return mMinimum; 00323 case FAR_LEFT_TOP: 00324 return Vector3(mMinimum.x, mMaximum.y, mMinimum.z); 00325 case FAR_RIGHT_TOP: 00326 return Vector3(mMaximum.x, mMaximum.y, mMinimum.z); 00327 case FAR_RIGHT_BOTTOM: 00328 return Vector3(mMaximum.x, mMinimum.y, mMinimum.z); 00329 case NEAR_RIGHT_BOTTOM: 00330 return Vector3(mMaximum.x, mMinimum.y, mMaximum.z); 00331 case NEAR_LEFT_BOTTOM: 00332 return Vector3(mMinimum.x, mMinimum.y, mMaximum.z); 00333 case NEAR_LEFT_TOP: 00334 return Vector3(mMinimum.x, mMaximum.y, mMaximum.z); 00335 case NEAR_RIGHT_TOP: 00336 return mMaximum; 00337 default: 00338 return Vector3(); 00339 } 00340 } 00341 00342 _OgreExport friend std::ostream& operator<<( std::ostream& o, const AxisAlignedBox aab ) 00343 { 00344 switch (aab.mExtent) 00345 { 00346 case EXTENT_NULL: 00347 o << "AxisAlignedBox(null)"; 00348 return o; 00349 00350 case EXTENT_FINITE: 00351 o << "AxisAlignedBox(min=" << aab.mMinimum << ", max=" << aab.mMaximum << ")"; 00352 return o; 00353 00354 case EXTENT_INFINITE: 00355 o << "AxisAlignedBox(infinite)"; 00356 return o; 00357 00358 default: // shut up compiler 00359 assert( false && "Never reached" ); 00360 return o; 00361 } 00362 } 00363 00367 void merge( const AxisAlignedBox& rhs ) 00368 { 00369 // Do nothing if rhs null, or this is infinite 00370 if ((rhs.mExtent == EXTENT_NULL) || (mExtent == EXTENT_INFINITE)) 00371 { 00372 return; 00373 } 00374 // Otherwise if rhs is infinite, make this infinite, too 00375 else if (rhs.mExtent == EXTENT_INFINITE) 00376 { 00377 mExtent = EXTENT_INFINITE; 00378 } 00379 // Otherwise if current null, just take rhs 00380 else if (mExtent == EXTENT_NULL) 00381 { 00382 setExtents(rhs.mMinimum, rhs.mMaximum); 00383 } 00384 // Otherwise merge 00385 else 00386 { 00387 Vector3 min = mMinimum; 00388 Vector3 max = mMaximum; 00389 max.makeCeil(rhs.mMaximum); 00390 min.makeFloor(rhs.mMinimum); 00391 00392 setExtents(min, max); 00393 } 00394 00395 } 00396 00399 inline void merge( const Vector3& point ) 00400 { 00401 switch (mExtent) 00402 { 00403 case EXTENT_NULL: // if null, use this point 00404 setExtents(point, point); 00405 return; 00406 00407 case EXTENT_FINITE: 00408 mMaximum.makeCeil(point); 00409 mMinimum.makeFloor(point); 00410 return; 00411 00412 case EXTENT_INFINITE: // if infinite, makes no difference 00413 return; 00414 } 00415 00416 assert( false && "Never reached" ); 00417 } 00418 00428 inline void transform( const Matrix4& matrix ) 00429 { 00430 // Do nothing if current null or infinite 00431 if( mExtent != EXTENT_FINITE ) 00432 return; 00433 00434 Vector3 oldMin, oldMax, currentCorner; 00435 00436 // Getting the old values so that we can use the existing merge method. 00437 oldMin = mMinimum; 00438 oldMax = mMaximum; 00439 00440 // reset 00441 setNull(); 00442 00443 // We sequentially compute the corners in the following order : 00444 // 0, 6, 5, 1, 2, 4 ,7 , 3 00445 // This sequence allows us to only change one member at a time to get at all corners. 00446 00447 // For each one, we transform it using the matrix 00448 // Which gives the resulting point and merge the resulting point. 00449 00450 // First corner 00451 // min min min 00452 currentCorner = oldMin; 00453 merge( matrix * currentCorner ); 00454 00455 // min,min,max 00456 currentCorner.z = oldMax.z; 00457 merge( matrix * currentCorner ); 00458 00459 // min max max 00460 currentCorner.y = oldMax.y; 00461 merge( matrix * currentCorner ); 00462 00463 // min max min 00464 currentCorner.z = oldMin.z; 00465 merge( matrix * currentCorner ); 00466 00467 // max max min 00468 currentCorner.x = oldMax.x; 00469 merge( matrix * currentCorner ); 00470 00471 // max max max 00472 currentCorner.z = oldMax.z; 00473 merge( matrix * currentCorner ); 00474 00475 // max min max 00476 currentCorner.y = oldMin.y; 00477 merge( matrix * currentCorner ); 00478 00479 // max min min 00480 currentCorner.z = oldMin.z; 00481 merge( matrix * currentCorner ); 00482 } 00483 00495 void transformAffine(const Matrix4& m) 00496 { 00497 assert(m.isAffine()); 00498 00499 // Do nothing if current null or infinite 00500 if ( mExtent != EXTENT_FINITE ) 00501 return; 00502 00503 Vector3 centre = getCenter(); 00504 Vector3 halfSize = getHalfSize(); 00505 00506 Vector3 newCentre = m.transformAffine(centre); 00507 Vector3 newHalfSize( 00508 Math::Abs(m[0][0]) * halfSize.x + Math::Abs(m[0][1]) * halfSize.y + Math::Abs(m[0][2]) * halfSize.z, 00509 Math::Abs(m[1][0]) * halfSize.x + Math::Abs(m[1][1]) * halfSize.y + Math::Abs(m[1][2]) * halfSize.z, 00510 Math::Abs(m[2][0]) * halfSize.x + Math::Abs(m[2][1]) * halfSize.y + Math::Abs(m[2][2]) * halfSize.z); 00511 00512 setExtents(newCentre - newHalfSize, newCentre + newHalfSize); 00513 } 00514 00517 inline void setNull() 00518 { 00519 mExtent = EXTENT_NULL; 00520 } 00521 00524 inline bool isNull(void) const 00525 { 00526 return (mExtent == EXTENT_NULL); 00527 } 00528 00531 bool isFinite(void) const 00532 { 00533 return (mExtent == EXTENT_FINITE); 00534 } 00535 00538 inline void setInfinite() 00539 { 00540 mExtent = EXTENT_INFINITE; 00541 } 00542 00545 bool isInfinite(void) const 00546 { 00547 return (mExtent == EXTENT_INFINITE); 00548 } 00549 00551 inline bool intersects(const AxisAlignedBox& b2) const 00552 { 00553 // Early-fail for nulls 00554 if (this->isNull() || b2.isNull()) 00555 return false; 00556 00557 // Early-success for infinites 00558 if (this->isInfinite() || b2.isInfinite()) 00559 return true; 00560 00561 // Use up to 6 separating planes 00562 if (mMaximum.x < b2.mMinimum.x) 00563 return false; 00564 if (mMaximum.y < b2.mMinimum.y) 00565 return false; 00566 if (mMaximum.z < b2.mMinimum.z) 00567 return false; 00568 00569 if (mMinimum.x > b2.mMaximum.x) 00570 return false; 00571 if (mMinimum.y > b2.mMaximum.y) 00572 return false; 00573 if (mMinimum.z > b2.mMaximum.z) 00574 return false; 00575 00576 // otherwise, must be intersecting 00577 return true; 00578 00579 } 00580 00582 inline AxisAlignedBox intersection(const AxisAlignedBox& b2) const 00583 { 00584 if (this->isNull() || b2.isNull()) 00585 { 00586 return AxisAlignedBox(); 00587 } 00588 else if (this->isInfinite()) 00589 { 00590 return b2; 00591 } 00592 else if (b2.isInfinite()) 00593 { 00594 return *this; 00595 } 00596 00597 Vector3 intMin = mMinimum; 00598 Vector3 intMax = mMaximum; 00599 00600 intMin.makeCeil(b2.getMinimum()); 00601 intMax.makeFloor(b2.getMaximum()); 00602 00603 // Check intersection isn't null 00604 if (intMin.x < intMax.x && 00605 intMin.y < intMax.y && 00606 intMin.z < intMax.z) 00607 { 00608 return AxisAlignedBox(intMin, intMax); 00609 } 00610 00611 return AxisAlignedBox(); 00612 } 00613 00615 Real volume(void) const 00616 { 00617 switch (mExtent) 00618 { 00619 case EXTENT_NULL: 00620 return 0.0f; 00621 00622 case EXTENT_FINITE: 00623 { 00624 Vector3 diff = mMaximum - mMinimum; 00625 return diff.x * diff.y * diff.z; 00626 } 00627 00628 case EXTENT_INFINITE: 00629 return Math::POS_INFINITY; 00630 00631 default: // shut up compiler 00632 assert( false && "Never reached" ); 00633 return 0.0f; 00634 } 00635 } 00636 00638 inline void scale(const Vector3& s) 00639 { 00640 // Do nothing if current null or infinite 00641 if (mExtent != EXTENT_FINITE) 00642 return; 00643 00644 // NB assumes centered on origin 00645 Vector3 min = mMinimum * s; 00646 Vector3 max = mMaximum * s; 00647 setExtents(min, max); 00648 } 00649 00651 bool intersects(const Sphere& s) const 00652 { 00653 return Math::intersects(s, *this); 00654 } 00656 bool intersects(const Plane& p) const 00657 { 00658 return Math::intersects(p, *this); 00659 } 00661 bool intersects(const Vector3& v) const 00662 { 00663 switch (mExtent) 00664 { 00665 case EXTENT_NULL: 00666 return false; 00667 00668 case EXTENT_FINITE: 00669 return(v.x >= mMinimum.x && v.x <= mMaximum.x && 00670 v.y >= mMinimum.y && v.y <= mMaximum.y && 00671 v.z >= mMinimum.z && v.z <= mMaximum.z); 00672 00673 case EXTENT_INFINITE: 00674 return true; 00675 00676 default: // shut up compiler 00677 assert( false && "Never reached" ); 00678 return false; 00679 } 00680 } 00682 Vector3 getCenter(void) const 00683 { 00684 assert( (mExtent == EXTENT_FINITE) && "Can't get center of a null or infinite AAB" ); 00685 00686 return Vector3( 00687 (mMaximum.x + mMinimum.x) * 0.5, 00688 (mMaximum.y + mMinimum.y) * 0.5, 00689 (mMaximum.z + mMinimum.z) * 0.5); 00690 } 00692 Vector3 getSize(void) const 00693 { 00694 switch (mExtent) 00695 { 00696 case EXTENT_NULL: 00697 return Vector3::ZERO; 00698 00699 case EXTENT_FINITE: 00700 return mMaximum - mMinimum; 00701 00702 case EXTENT_INFINITE: 00703 return Vector3( 00704 Math::POS_INFINITY, 00705 Math::POS_INFINITY, 00706 Math::POS_INFINITY); 00707 00708 default: // shut up compiler 00709 assert( false && "Never reached" ); 00710 return Vector3::ZERO; 00711 } 00712 } 00714 Vector3 getHalfSize(void) const 00715 { 00716 switch (mExtent) 00717 { 00718 case EXTENT_NULL: 00719 return Vector3::ZERO; 00720 00721 case EXTENT_FINITE: 00722 return (mMaximum - mMinimum) * 0.5; 00723 00724 case EXTENT_INFINITE: 00725 return Vector3( 00726 Math::POS_INFINITY, 00727 Math::POS_INFINITY, 00728 Math::POS_INFINITY); 00729 00730 default: // shut up compiler 00731 assert( false && "Never reached" ); 00732 return Vector3::ZERO; 00733 } 00734 } 00735 00738 bool contains(const Vector3& v) const 00739 { 00740 if (isNull()) 00741 return false; 00742 if (isInfinite()) 00743 return true; 00744 00745 return mMinimum.x <= v.x && v.x <= mMaximum.x && 00746 mMinimum.y <= v.y && v.y <= mMaximum.y && 00747 mMinimum.z <= v.z && v.z <= mMaximum.z; 00748 } 00749 00752 bool contains(const AxisAlignedBox& other) const 00753 { 00754 if (other.isNull() || this->isInfinite()) 00755 return true; 00756 00757 if (this->isNull() || other.isInfinite()) 00758 return false; 00759 00760 return this->mMinimum.x <= other.mMinimum.x && 00761 this->mMinimum.y <= other.mMinimum.y && 00762 this->mMinimum.z <= other.mMinimum.z && 00763 other.mMaximum.x <= this->mMaximum.x && 00764 other.mMaximum.y <= this->mMaximum.y && 00765 other.mMaximum.z <= this->mMaximum.z; 00766 } 00767 00770 bool operator== (const AxisAlignedBox& rhs) const 00771 { 00772 if (this->mExtent != rhs.mExtent) 00773 return false; 00774 00775 if (!this->isFinite()) 00776 return true; 00777 00778 return this->mMinimum == rhs.mMinimum && 00779 this->mMaximum == rhs.mMaximum; 00780 } 00781 00784 bool operator!= (const AxisAlignedBox& rhs) const 00785 { 00786 return !(*this == rhs); 00787 } 00788 00789 }; 00790 00791 } // namespace Ogre 00792 00793 #endif
Copyright © 2000-2005 by The OGRE Team
This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 License.
Last modified Mon Jun 16 12:48:49 2008