/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef SE_INCL_AABBOX_H #define SE_INCL_AABBOX_H #ifdef PRAGMA_ONCE #pragma once #endif #include #include /* * Template for axis-aligned bounding box of arbitrary dimensions */ template class AABBox { // implementation: public: Vector minvect; // vector of min coordinates Vector maxvect; // vector of max coordinates /* Clear to normalized empty bounding box. */ inline void SetToNormalizedEmpty(void); // interface: public: /* Default constructor. */ inline AABBox(void); /* Constructor for one-point bounding box. */ inline AABBox(const Vector &vPoint); /* Constructor for one-point and radius bounding box. */ inline AABBox(const Vector &vPoint, const Type radius); /* Constructor for two diagonal points. */ inline AABBox(const Vector &vPoint1, const Vector &vPoint2); /* Bounding box for union. */ inline AABBox &operator|=(const AABBox &b); /* Bounding box for intersection. */ inline AABBox &operator&=(const AABBox &b); /* Bounding box for intersection. */ inline AABBox operator&(const AABBox &b) const; /* Function for moving bounding box. */ inline AABBox &operator+=(const Vector &vct); inline AABBox &operator-=(const Vector &vct); /* Function for testing equality of bounding boxes. */ inline BOOL operator==(const AABBox &box2) const; /* Function for testing difference between bounding boxes. */ inline BOOL operator!=(const AABBox &box2) const; /* Test if the bounding box contains another bounding box. */ inline BOOL operator>=(const AABBox &b) const; /* Test if the bounding box is contained in another bounding box. */ inline BOOL operator<=(const AABBox &b) const; /* Get diagonal vector (size of box). */ inline const Vector Size(void) const; /* Get center vector (middle of box). */ inline const Vector Center(void) const; /* Get minimal vector (lower left of box). */ inline const Vector &Min(void) const; /* Get maximal vector (upper right of box). */ inline const Vector &Max(void) const; /* Check if empty. */ inline BOOL IsEmpty(void) const; /* Check if intersects or touches another bounding box. */ inline BOOL HasContactWith(const AABBox &b) const; inline BOOL HasContactWith(const AABBox &b, Type tEpsilon) const; /* Check if intersects or touches a sphere. */ inline BOOL TouchesSphere( const Vector &vSphereCenter, Type fSphereRadius) const; // expand the bounding box by given size inline void Expand(Type tEpsilon); // expand the bounding box by given factor of its size along each axis inline void ExpandByFactor(Type tFactor); // stretch the bounding box by a given sizing factor inline void StretchByFactor(Type tSizing); // stretch the bounding box by a given sizing vector inline void StretchByVector(Vector vSizing); friend __forceinline CTStream &operator>>(CTStream &strm, AABBox &b) { strm>>b.minvect; strm>>b.maxvect; return strm; } friend __forceinline CTStream &operator<<(CTStream &strm, const AABBox &b) { strm< inline void AABBox::SetToNormalizedEmpty(void) { for ( int i=1; i<=iDimensions; i++ ) { minvect(i) = UpperLimit(Type(0)); maxvect(i) = LowerLimit(Type(0)); } } /* * Constructor for empty bounding box. */ template inline AABBox::AABBox() { SetToNormalizedEmpty(); } /* * Constructor for one-point bounding box. */ template inline AABBox::AABBox(const Vector &vPoint) { for ( int i=1; i<=iDimensions; i++ ) { minvect(i) = maxvect(i) = vPoint(i); } } /* * Constructor for one-point and radius bounding box. */ template inline AABBox::AABBox(const Vector &vPoint, const Type radius) { for ( int i=1; i<=iDimensions; i++ ) { minvect(i) = vPoint(i)-radius; maxvect(i) = vPoint(i)+radius; } } /* * Constructor for two diagonal points. */ template inline AABBox::AABBox(const Vector &vPoint1, const Vector &vPoint2) { for ( int i=1; i<=iDimensions; i++ ) { minvect(i) = ::Min(vPoint1(i), vPoint2(i)); maxvect(i) = ::Max(vPoint1(i), vPoint2(i)); } } /* * Function for testing equality of bounding boxes. */ template inline BOOL AABBox::operator==(const AABBox &box2) const { return ( (minvect==box2.minvect) && (maxvect==box2.maxvect) ); } /* * Function for testing diferences between bounding boxes. */ template inline BOOL AABBox::operator!=(const AABBox &box2) const { return !(*this == box2); } /* * Test if the bounding box contains another bounding box. */ template inline BOOL AABBox::operator>=(const AABBox &b) const { return b<=*this; } /* * Test if the bounding box is contained in another bounding box. */ template inline BOOL AABBox::operator<=(const AABBox &b) const { // for each dimension for (INDEX i=1; i<=iDimensions; i++ ) { // if that dimension's span is not contained if (minvect(i) < b.minvect(i) || maxvect(i) > b.maxvect(i)) { // the box is not contained return FALSE; } } // otherwise, it is contained return TRUE; } /* * Check if empty. */ template inline BOOL AABBox::IsEmpty(void) const { // if any dimension is empty, it is empty for ( int i=1; i<=iDimensions; i++ ) { if (minvect(i) > maxvect(i)) { return TRUE; } } // otherwise, it is not empty return FALSE; } /* * Get center vector (middle of box). */ template inline const Vector AABBox::Center(void) const { // center is in the middle between min and max return (maxvect + minvect)/(Type)2; } /* * Get diagonal vector (size of box). */ template inline const Vector AABBox::Size(void) const { // size is difference between min and max vectors return maxvect - minvect; } /* * Get minimal vector (lower left of box). */ template inline const Vector &AABBox::Min(void) const { return minvect; } /* * Get maximal vector (upper right of box). */ template inline const Vector &AABBox::Max(void) const { return maxvect; } /* * Bounding box for union. */ template inline AABBox &AABBox::operator|=(const AABBox &b) { for ( int i=1; i<=iDimensions; i++ ) { minvect(i) = ::Min(minvect(i), b.minvect(i)); maxvect(i) = ::Max(maxvect(i), b.maxvect(i)); } return *this; } /* * Bounding box for intersection. */ template inline AABBox &AABBox::operator&=(const AABBox &b) { for ( int i=1; i<=iDimensions; i++ ) { minvect(i) = ::Max(minvect(i), b.minvect(i)); maxvect(i) = ::Min(maxvect(i), b.maxvect(i)); } // if the result is empty bounding box, normalize it if ( IsEmpty() ) SetToNormalizedEmpty(); return *this; } /* * Function for moving bounding box. */ template inline AABBox &AABBox::operator+=(const Vector &vct) { minvect += vct; maxvect += vct; return *this; } template inline AABBox &AABBox::operator-=(const Vector &vct) { minvect -= vct; maxvect -= vct; return *this; } /* Bounding box for intersection. */ template inline AABBox AABBox::operator&(const AABBox &b) const { return AABBox(*this)&=b; } /* Check if intersects or touches another bounding box. */ template inline BOOL AABBox::HasContactWith(const AABBox &b) const { // for all dimensions for ( int i=1; i<=iDimensions; i++ ) { // if spans in that dimension don't have contact if (maxvect(i)b.maxvect(i) ) { // whole bounding boxes don't have contact return FALSE; } } return TRUE; } /* Check if intersects or touches another bounding box. */ template inline BOOL AABBox::HasContactWith(const AABBox &b, Type tEpsilon) const { // for all dimensions for ( int i=1; i<=iDimensions; i++ ) { // if spans in that dimension don't have contact if( (maxvect(i)+tEpsilonb.maxvect(i)) ) { // whole bounding boxes don't have contact return FALSE; } } return TRUE; } /* Check if intersects or touches a sphere. */ template inline BOOL AABBox::TouchesSphere( const Vector &vSphereCenter, Type fSphereRadius) const { // for all dimensions for ( int i=1; i<=iDimensions; i++ ) { // if spans in that dimension don't have contact if( (vSphereCenter(i)+fSphereRadiusmaxvect(i)) ) { // no contact return FALSE; } } return TRUE; } // expand the bounding box by given size template inline void AABBox::Expand(Type tEpsilon) { // for all dimensions for ( int i=1; i<=iDimensions; i++ ) { // expand in that dimension maxvect(i)+=tEpsilon; minvect(i)-=tEpsilon; } } // expand the bounding box by given factor of its size along each axis template inline void AABBox::ExpandByFactor(Type tFactor) { // for all dimensions for ( int i=1; i<=iDimensions; i++ ) { // expand in that dimension Type tEpsilon = (maxvect(i)-minvect(i))*tFactor; maxvect(i)+=tEpsilon; minvect(i)-=tEpsilon; } } // stretch the bounding box by a given sizing factor template inline void AABBox::StretchByFactor(Type tSizing) { tSizing = Abs(tSizing); // for each dimension for ( int i=1; i<=iDimensions; i++ ) { // stretch in that dimension maxvect(i)*=tSizing; minvect(i)*=tSizing; } } // stretch the bounding box by a given sizing vector template inline void AABBox::StretchByVector(Vector vSizing) { // for each dimension for ( int i=1; i<=iDimensions; i++ ) { // stretch in that dimension maxvect(i)*=Abs(vSizing(i)); minvect(i)*=Abs(vSizing(i)); } } // helper functions for converting between FLOAT and DOUBLE aabboxes inline DOUBLEaabbox3D FLOATtoDOUBLE(const FLOATaabbox3D &plf) { return DOUBLEaabbox3D( FLOATtoDOUBLE(plf.Min()), FLOATtoDOUBLE(plf.Max())); } inline FLOATaabbox3D DOUBLEtoFLOAT(const DOUBLEaabbox3D &pld) { return FLOATaabbox3D( DOUBLEtoFLOAT(pld.Min()), DOUBLEtoFLOAT(pld.Max())); } /* Specialized copy for FLOATaabb3D */ /* Check if intersects or touches another bounding box. */ template<> inline BOOL AABBox::HasContactWith(const AABBox &b) const { // if spans in any dimension don't have contact if (maxvect(1)b.maxvect(1) || maxvect(2)b.maxvect(2) || maxvect(3)b.maxvect(3) ) { // whole bounding boxes don't have contact return FALSE; } return TRUE; } /* Check if intersects or touches another bounding box. */ template<> inline BOOL AABBox::HasContactWith(const AABBox &b, FLOAT tEpsilon) const { // if spans in any dimension don't have contact if( (maxvect(1)+tEpsilonb.maxvect(1)) || (maxvect(2)+tEpsilonb.maxvect(2)) || (maxvect(3)+tEpsilonb.maxvect(3)) ) { // whole bounding boxes don't have contact return FALSE; } return TRUE; } /* Check if intersects or touches a sphere. */ template<> inline BOOL AABBox::TouchesSphere( const Vector &vSphereCenter, FLOAT fSphereRadius) const { // if spans in any dimension don't have contact if( (vSphereCenter(1)+fSphereRadiusmaxvect(1)) || (vSphereCenter(2)+fSphereRadiusmaxvect(2)) || (vSphereCenter(3)+fSphereRadiusmaxvect(3)) ) { // no contact return FALSE; } return TRUE; } #endif /* include-once check. */