OgreAxisAlignedBox.h

Go to the documentation of this file.
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
Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 License.
Last modified Sun Sep 27 22:02:22 2009