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 // We sequentially compute the corners in the following order : 00441 // 0, 6, 5, 1, 2, 4 ,7 , 3 00442 // This sequence allows us to only change one member at a time to get at all corners. 00443 00444 // For each one, we transform it using the matrix 00445 // Which gives the resulting point and merge the resulting point. 00446 00447 // First corner 00448 // min min min 00449 currentCorner = oldMin; 00450 merge( matrix * currentCorner ); 00451 00452 // min,min,max 00453 currentCorner.z = oldMax.z; 00454 merge( matrix * currentCorner ); 00455 00456 // min max max 00457 currentCorner.y = oldMax.y; 00458 merge( matrix * currentCorner ); 00459 00460 // min max min 00461 currentCorner.z = oldMin.z; 00462 merge( matrix * currentCorner ); 00463 00464 // max max min 00465 currentCorner.x = oldMax.x; 00466 merge( matrix * currentCorner ); 00467 00468 // max max max 00469 currentCorner.z = oldMax.z; 00470 merge( matrix * currentCorner ); 00471 00472 // max min max 00473 currentCorner.y = oldMin.y; 00474 merge( matrix * currentCorner ); 00475 00476 // max min min 00477 currentCorner.z = oldMin.z; 00478 merge( matrix * currentCorner ); 00479 } 00480 00492 void transformAffine(const Matrix4& m) 00493 { 00494 assert(m.isAffine()); 00495 00496 // Do nothing if current null or infinite 00497 if ( mExtent != EXTENT_FINITE ) 00498 return; 00499 00500 Vector3 centre = getCenter(); 00501 Vector3 halfSize = getHalfSize(); 00502 00503 Vector3 newCentre = m.transformAffine(centre); 00504 Vector3 newHalfSize( 00505 Math::Abs(m[0][0]) * halfSize.x + Math::Abs(m[0][1]) * halfSize.y + Math::Abs(m[0][2]) * halfSize.z, 00506 Math::Abs(m[1][0]) * halfSize.x + Math::Abs(m[1][1]) * halfSize.y + Math::Abs(m[1][2]) * halfSize.z, 00507 Math::Abs(m[2][0]) * halfSize.x + Math::Abs(m[2][1]) * halfSize.y + Math::Abs(m[2][2]) * halfSize.z); 00508 00509 setExtents(newCentre - newHalfSize, newCentre + newHalfSize); 00510 } 00511 00514 inline void setNull() 00515 { 00516 mExtent = EXTENT_NULL; 00517 } 00518 00521 inline bool isNull(void) const 00522 { 00523 return (mExtent == EXTENT_NULL); 00524 } 00525 00528 bool isFinite(void) const 00529 { 00530 return (mExtent == EXTENT_FINITE); 00531 } 00532 00535 inline void setInfinite() 00536 { 00537 mExtent = EXTENT_INFINITE; 00538 } 00539 00542 bool isInfinite(void) const 00543 { 00544 return (mExtent == EXTENT_INFINITE); 00545 } 00546 00548 inline bool intersects(const AxisAlignedBox& b2) const 00549 { 00550 // Early-fail for nulls 00551 if (this->isNull() || b2.isNull()) 00552 return false; 00553 00554 // Early-success for infinites 00555 if (this->isInfinite() || b2.isInfinite()) 00556 return true; 00557 00558 // Use up to 6 separating planes 00559 if (mMaximum.x < b2.mMinimum.x) 00560 return false; 00561 if (mMaximum.y < b2.mMinimum.y) 00562 return false; 00563 if (mMaximum.z < b2.mMinimum.z) 00564 return false; 00565 00566 if (mMinimum.x > b2.mMaximum.x) 00567 return false; 00568 if (mMinimum.y > b2.mMaximum.y) 00569 return false; 00570 if (mMinimum.z > b2.mMaximum.z) 00571 return false; 00572 00573 // otherwise, must be intersecting 00574 return true; 00575 00576 } 00577 00579 inline AxisAlignedBox intersection(const AxisAlignedBox& b2) const 00580 { 00581 if (this->isNull() || b2.isNull()) 00582 { 00583 return AxisAlignedBox(); 00584 } 00585 else if (this->isInfinite()) 00586 { 00587 return b2; 00588 } 00589 else if (b2.isInfinite()) 00590 { 00591 return *this; 00592 } 00593 00594 Vector3 intMin = mMinimum; 00595 Vector3 intMax = mMaximum; 00596 00597 intMin.makeCeil(b2.getMinimum()); 00598 intMax.makeFloor(b2.getMaximum()); 00599 00600 // Check intersection isn't null 00601 if (intMin.x < intMax.x && 00602 intMin.y < intMax.y && 00603 intMin.z < intMax.z) 00604 { 00605 return AxisAlignedBox(intMin, intMax); 00606 } 00607 00608 return AxisAlignedBox(); 00609 } 00610 00612 Real volume(void) const 00613 { 00614 switch (mExtent) 00615 { 00616 case EXTENT_NULL: 00617 return 0.0f; 00618 00619 case EXTENT_FINITE: 00620 { 00621 Vector3 diff = mMaximum - mMinimum; 00622 return diff.x * diff.y * diff.z; 00623 } 00624 00625 case EXTENT_INFINITE: 00626 return Math::POS_INFINITY; 00627 00628 default: // shut up compiler 00629 assert( false && "Never reached" ); 00630 return 0.0f; 00631 } 00632 } 00633 00635 inline void scale(const Vector3& s) 00636 { 00637 // Do nothing if current null or infinite 00638 if (mExtent != EXTENT_FINITE) 00639 return; 00640 00641 // NB assumes centered on origin 00642 Vector3 min = mMinimum * s; 00643 Vector3 max = mMaximum * s; 00644 setExtents(min, max); 00645 } 00646 00648 bool intersects(const Sphere& s) const 00649 { 00650 return Math::intersects(s, *this); 00651 } 00653 bool intersects(const Plane& p) const 00654 { 00655 return Math::intersects(p, *this); 00656 } 00658 bool intersects(const Vector3& v) const 00659 { 00660 switch (mExtent) 00661 { 00662 case EXTENT_NULL: 00663 return false; 00664 00665 case EXTENT_FINITE: 00666 return(v.x >= mMinimum.x && v.x <= mMaximum.x && 00667 v.y >= mMinimum.y && v.y <= mMaximum.y && 00668 v.z >= mMinimum.z && v.z <= mMaximum.z); 00669 00670 case EXTENT_INFINITE: 00671 return true; 00672 00673 default: // shut up compiler 00674 assert( false && "Never reached" ); 00675 return false; 00676 } 00677 } 00679 Vector3 getCenter(void) const 00680 { 00681 assert( (mExtent == EXTENT_FINITE) && "Can't get center of a null or infinite AAB" ); 00682 00683 return Vector3( 00684 (mMaximum.x + mMinimum.x) * 0.5, 00685 (mMaximum.y + mMinimum.y) * 0.5, 00686 (mMaximum.z + mMinimum.z) * 0.5); 00687 } 00689 Vector3 getSize(void) const 00690 { 00691 switch (mExtent) 00692 { 00693 case EXTENT_NULL: 00694 return Vector3::ZERO; 00695 00696 case EXTENT_FINITE: 00697 return mMaximum - mMinimum; 00698 00699 case EXTENT_INFINITE: 00700 return Vector3( 00701 Math::POS_INFINITY, 00702 Math::POS_INFINITY, 00703 Math::POS_INFINITY); 00704 00705 default: // shut up compiler 00706 assert( false && "Never reached" ); 00707 return Vector3::ZERO; 00708 } 00709 } 00711 Vector3 getHalfSize(void) const 00712 { 00713 switch (mExtent) 00714 { 00715 case EXTENT_NULL: 00716 return Vector3::ZERO; 00717 00718 case EXTENT_FINITE: 00719 return (mMaximum - mMinimum) * 0.5; 00720 00721 case EXTENT_INFINITE: 00722 return Vector3( 00723 Math::POS_INFINITY, 00724 Math::POS_INFINITY, 00725 Math::POS_INFINITY); 00726 00727 default: // shut up compiler 00728 assert( false && "Never reached" ); 00729 return Vector3::ZERO; 00730 } 00731 } 00732 00735 bool contains(const Vector3& v) const 00736 { 00737 if (isNull()) 00738 return false; 00739 if (isInfinite()) 00740 return true; 00741 00742 return mMinimum.x <= v.x && v.x <= mMaximum.x && 00743 mMinimum.y <= v.y && v.y <= mMaximum.y && 00744 mMinimum.z <= v.z && v.z <= mMaximum.z; 00745 } 00746 00749 bool contains(const AxisAlignedBox& other) const 00750 { 00751 if (other.isNull() || this->isInfinite()) 00752 return true; 00753 00754 if (this->isNull() || other.isInfinite()) 00755 return false; 00756 00757 return this->mMinimum.x <= other.mMinimum.x && 00758 this->mMinimum.y <= other.mMinimum.y && 00759 this->mMinimum.z <= other.mMinimum.z && 00760 other.mMaximum.x <= this->mMaximum.x && 00761 other.mMaximum.y <= this->mMaximum.y && 00762 other.mMaximum.z <= this->mMaximum.z; 00763 } 00764 00767 bool operator== (const AxisAlignedBox& rhs) const 00768 { 00769 if (this->mExtent != rhs.mExtent) 00770 return false; 00771 00772 if (!this->isFinite()) 00773 return true; 00774 00775 return this->mMinimum == rhs.mMinimum && 00776 this->mMaximum == rhs.mMaximum; 00777 } 00778 00781 bool operator!= (const AxisAlignedBox& rhs) const 00782 { 00783 return !(*this == rhs); 00784 } 00785 00786 }; 00787 00788 } // namespace Ogre 00789 00790 #endif
Copyright © 2000-2005 by The OGRE Team
This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 License.
Last modified Sun May 6 10:54:20 2007