Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

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             // 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
Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 2.5 License.
Last modified Sun Jun 10 10:35:47 2007