source: GTP/trunk/App/Demos/Geom/OgreStuff/include/OgreAxisAlignedBox.h @ 1812

Revision 1812, 12.0 KB checked in by gumbau, 18 years ago (diff)
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25#ifndef __AxisAlignedBox_H_
26#define __AxisAlignedBox_H_
27
28// Precompiler options
29#include "OgrePrerequisites.h"
30
31#include "OgreVector3.h"
32#include "OgreMatrix4.h"
33
34namespace Ogre {
35
36    /** A 3D box aligned with the x/y/z axes.
37            @remarks
38                    This class represents a simple box which is aligned with the
39                    axes. Internally it only stores 2 points as the extremeties of
40                    the box, one which is the minima of all 3 axes, and the other
41                    which is the maxima of all 3 axes. This class is typically used
42                    for an axis-aligned bounding box (AABB) for collision and
43                    visibility determination.
44    */
45    class _OgreExport AxisAlignedBox
46    {
47    protected:
48            Vector3 mMinimum;
49            Vector3 mMaximum;
50            bool mNull;
51
52            Vector3 mCorners[8];
53
54            /** Internal method for updating corner points.
55            */
56            void updateCorners(void)
57            {
58                    // The order of these items is, using right-handed co-ordinates:
59                    // Minimum Z face, starting with Min(all), then anticlockwise
60                    //   around face (looking onto the face)
61                    // Maximum Z face, starting with Max(all), then anticlockwise
62                    //   around face (looking onto the face)
63                    mCorners[0] = mMinimum;
64                    mCorners[1].x = mMinimum.x; mCorners[1].y = mMaximum.y; mCorners[1].z = mMinimum.z;
65                    mCorners[2].x = mMaximum.x; mCorners[2].y = mMaximum.y; mCorners[2].z = mMinimum.z;
66                    mCorners[3].x = mMaximum.x; mCorners[3].y = mMinimum.y; mCorners[3].z = mMinimum.z;           
67
68                    mCorners[4] = mMaximum;
69                    mCorners[5].x = mMinimum.x; mCorners[5].y = mMaximum.y; mCorners[5].z = mMaximum.z;
70                    mCorners[6].x = mMinimum.x; mCorners[6].y = mMinimum.y; mCorners[6].z = mMaximum.z;
71                    mCorners[7].x = mMaximum.x; mCorners[7].y = mMinimum.y; mCorners[7].z = mMaximum.z;           
72            }       
73
74    public:
75            inline AxisAlignedBox()
76            {
77                    // Default to null box
78                    setMinimum( -0.5, -0.5, -0.5 );
79                    setMaximum( 0.5, 0.5, 0.5 );
80                    mNull = true;
81            }
82
83            inline AxisAlignedBox( const Vector3& min, const Vector3& max )
84            {
85                    setExtents( min, max );
86            }
87
88            inline AxisAlignedBox(
89                    Real mx, Real my, Real mz,
90                    Real Mx, Real My, Real Mz )
91            {
92                    setExtents( mx, my, mz, Mx, My, Mz );
93            }
94
95            /** Gets the minimum corner of the box.
96            */
97            inline const Vector3& getMinimum(void) const
98            {
99                    return mMinimum;
100            }
101
102            /** Gets the maximum corner of the box.
103            */
104            inline const Vector3& getMaximum(void) const
105            {
106                    return mMaximum;
107            }
108
109            /** Sets the minimum corner of the box.
110            */
111            inline void setMinimum( const Vector3& vec )
112            {
113                    mNull = false;
114                    mMinimum = vec;
115                    updateCorners();
116            }
117
118            inline void setMinimum( Real x, Real y, Real z )
119            {
120                    mNull = false;
121                    mMinimum.x = x;
122                    mMinimum.y = y;
123                    mMinimum.z = z;
124                    updateCorners();
125            }
126
127            /** Sets the maximum corner of the box.
128            */
129            inline void setMaximum( const Vector3& vec )
130            {
131                    mNull = false;
132                    mMaximum = vec;
133                    updateCorners();
134            }
135
136            inline void setMaximum( Real x, Real y, Real z )
137            {
138                    mNull = false;
139                    mMaximum.x = x;
140                    mMaximum.y = y;
141                    mMaximum.z = z;
142                    updateCorners();
143            }
144
145            /** Sets both minimum and maximum extents at once.
146            */
147            inline void setExtents( const Vector3& min, const Vector3& max )
148            {
149                    mNull = false;
150                    mMinimum = min;
151                    mMaximum = max;
152                    updateCorners();
153            }
154
155            inline void setExtents(
156                    Real mx, Real my, Real mz,
157                    Real Mx, Real My, Real Mz )
158            {
159                    mNull = false;
160
161                    mMinimum.x = mx;
162                    mMinimum.y = my;
163                    mMinimum.z = mz;
164
165                    mMaximum.x = Mx;
166                    mMaximum.y = My;
167                    mMaximum.z = Mz;
168
169                    updateCorners();
170            }
171
172            /** Returns a pointer to an array of 8 corner points, useful for
173                    collision vs. non-aligned objects.
174                    @remarks
175                            If the order of these corners is important, they are as
176                            follows: The 4 points of the minimum Z face (note that
177                            because Ogre uses right-handed coordinates, the minimum Z is
178                            at the 'back' of the box) starting with the minimum point of
179                            all, then anticlockwise around this face (if you are looking
180                            onto the face from outside the box). Then the 4 points of the
181                            maximum Z face, starting with maximum point of all, then
182                            anticlockwise around this face (looking onto the face from
183                            outside the box). Like this:
184                            <pre>
185                               1-----2
186                              /|    /|
187                             / |   / |
188                            5-----4  |
189                            |  0--|--3
190                            | /   | /
191                            |/    |/
192                            6-----7
193                            </pre>
194            */
195            inline const Vector3* getAllCorners(void) const
196            {
197                    assert( !mNull && "Can't get corners of a null AAB" );
198                    return (const Vector3*)mCorners;
199            }
200
201            friend std::ostream& operator<<( std::ostream& o, AxisAlignedBox aab )
202            {
203                    if (aab.isNull())
204                    {
205                            o << "AxisAlignedBox(null)";
206                    }
207                    else
208                    {
209                            o << "AxisAlignedBox(min=" << aab.mMinimum << ", max=" << aab.mMaximum;
210                            o << ", corners=";
211                            for (int i = 0; i < 7; ++i)
212                                    o << aab.mCorners[i] << ", ";
213                            o << aab.mCorners[7] << ")";
214                    }
215                    return o;
216            }
217
218            /** Merges the passed in box into the current box. The result is the
219                    box which encompasses both.
220            */
221            void merge( const AxisAlignedBox& rhs )
222            {
223                    // Do nothing if rhs null
224                    if (rhs.mNull)
225                    {
226                            return;
227                    }
228                    // Otherwise if current null, just take rhs
229                    else if (mNull)
230                    {
231                            setExtents(rhs.mMinimum, rhs.mMaximum);
232                    }
233                    // Otherwise merge
234                    else
235                    {
236                            Vector3 min = mMinimum;
237                            Vector3 max = mMaximum;
238                            max.makeCeil(rhs.mMaximum);
239                            min.makeFloor(rhs.mMinimum);
240
241                            setExtents(min, max);
242                    }
243
244            }
245               
246                /** Extends the box to encompass the specified point (if needed).
247                */
248                void merge( const Vector3& point )
249                {
250                        if (mNull){ // if null, use this point
251                                setExtents(point, point);
252                        } else {
253                                mMaximum.makeCeil(point);
254                                mMinimum.makeFloor(point);
255                                updateCorners();
256                        }
257                }
258
259            /** Transforms the box according to the matrix supplied.
260                    @remarks
261                            By calling this method you get the axis-aligned box which
262                            surrounds the transformed version of this box. Therefore each
263                            corner of the box is transformed by the matrix, then the
264                            extents are mapped back onto the axes to produce another
265                            AABB. Useful when you have a local AABB for an object which
266                            is then transformed.
267            */
268            void transform( const Matrix4& matrix )
269            {
270                    // Do nothing if current null
271                    if( mNull )
272                            return;
273
274                    Vector3 min, max, temp;
275                    bool first = true;
276                    size_t i;
277
278                    for( i = 0; i < 8; ++i )
279                    {
280                            // Transform and check extents
281                            temp = matrix * mCorners[i];
282                            if( first || temp.x > max.x )
283                                    max.x = temp.x;
284                            if( first || temp.y > max.y )
285                                    max.y = temp.y;
286                            if( first || temp.z > max.z )
287                                    max.z = temp.z;
288                            if( first || temp.x < min.x )
289                                    min.x = temp.x;
290                            if( first || temp.y < min.y )
291                                    min.y = temp.y;
292                            if( first || temp.z < min.z )
293                                    min.z = temp.z;
294
295                            first = false;
296                    }
297
298                    setExtents( min,max );
299
300            }
301
302            /** Sets the box to a 'null' value i.e. not a box.
303            */
304            inline void setNull()
305            {
306                    mNull = true;
307            }
308
309            /** Returns true if the box is null i.e. empty.
310            */
311            bool isNull(void) const
312            {
313                    return mNull;
314            }
315
316        /** Returns whether or not this box intersects another. */
317        inline bool intersects(const AxisAlignedBox& b2) const
318        {
319            // Early-fail for nulls
320            if (this->isNull() || b2.isNull())
321                return false;
322
323            // Use up to 6 separating planes
324            if (mMaximum.x < b2.mMinimum.x)
325                return false;
326            if (mMaximum.y < b2.mMinimum.y)
327                return false;
328            if (mMaximum.z < b2.mMinimum.z)
329                return false;
330
331            if (mMinimum.x > b2.mMaximum.x)
332                return false;
333            if (mMinimum.y > b2.mMaximum.y)
334                return false;
335            if (mMinimum.z > b2.mMaximum.z)
336                return false;
337
338            // otherwise, must be intersecting
339            return true;
340
341        }
342
343                /// Calculate the area of intersection of this box and another
344                inline AxisAlignedBox intersection(const AxisAlignedBox& b2) const
345                {
346                        if (!this->intersects(b2))
347                        {
348                                return AxisAlignedBox();
349                        }
350                        Vector3 intMin, intMax;
351
352                        const Vector3& b2max = b2.getMaximum();
353                        const Vector3& b2min = b2.getMinimum();
354
355                        if (b2max.x > mMaximum.x && mMaximum.x > b2min.x)
356                                intMax.x = mMaximum.x;
357                        else
358                                intMax.x = b2max.x;
359                        if (b2max.y > mMaximum.y && mMaximum.y > b2min.y)
360                                intMax.y = mMaximum.y;
361                        else
362                                intMax.y = b2max.y;
363                        if (b2max.z > mMaximum.z && mMaximum.z > b2min.z)
364                                intMax.z = mMaximum.z;
365                        else
366                                intMax.z = b2max.z;
367
368                        if (b2min.x < mMinimum.x && mMinimum.x < b2max.x)
369                                intMin.x = mMinimum.x;
370                        else
371                                intMin.x= b2min.x;
372                        if (b2min.y < mMinimum.y && mMinimum.y < b2max.y)
373                                intMin.y = mMinimum.y;
374                        else
375                                intMin.y= b2min.y;
376                        if (b2min.z < mMinimum.z && mMinimum.z < b2max.z)
377                                intMin.z = mMinimum.z;
378                        else
379                                intMin.z= b2min.z;
380
381                        return AxisAlignedBox(intMin, intMax);
382
383                }
384
385                /// Calculate the volume of this box
386                Real volume(void) const
387                {
388                        if (mNull)
389                        {
390                                return 0.0f;
391                        }
392                        else
393                        {
394                                Vector3 diff = mMaximum - mMinimum;
395                                return diff.x * diff.y * diff.z;
396                        }
397
398                }
399
400        /** Scales the AABB by the vector given. */
401        inline void scale(const Vector3& s)
402        {
403            // NB assumes centered on origin
404            Vector3 min = mMinimum * s;
405            Vector3 max = mMaximum * s;
406            setExtents(min, max);
407        }
408
409                /** Tests whether this box intersects a sphere. */
410                bool intersects(const Sphere& s) const
411                {
412                        return Math::intersects(s, *this);
413                }
414                /** Tests whether this box intersects a plane. */
415                bool intersects(const Plane& p) const
416                {
417                        return Math::intersects(p, *this);
418                }
419        /** Tests whether the vector point is within this box. */
420        bool intersects(const Vector3& v) const
421        {
422                        return(v.x >= mMinimum.x  &&  v.x <= mMaximum.x  &&
423                            v.y >= mMinimum.y  &&  v.y <= mMaximum.y  &&
424                        v.z >= mMinimum.z  &&  v.z <= mMaximum.z);
425        }
426                /// Gets the centre of the box
427                Vector3 getCenter(void) const
428                {
429                        return Vector3((mMaximum + mMinimum) * 0.5);
430                }
431
432
433    };
434
435} // namespace Ogre
436
437#endif
Note: See TracBrowser for help on using the repository browser.