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     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
Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 License.
Last modified Mon Jun 16 12:48:49 2008