# 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
This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 License.
Last modified Sat May 10 16:24:56 2008