1 | /*
|
---|
2 | -----------------------------------------------------------------------------
|
---|
3 | This source file is part of OGRE
|
---|
4 | (Object-oriented Graphics Rendering Engine)
|
---|
5 | For the latest info, see http://www.ogre3d.org/
|
---|
6 |
|
---|
7 | Copyright (c) 2000-2005 The OGRE Team
|
---|
8 | Also see acknowledgements in Readme.html
|
---|
9 |
|
---|
10 | This program is free software; you can redistribute it and/or modify it under
|
---|
11 | the terms of the GNU Lesser General Public License as published by the Free Software
|
---|
12 | Foundation; either version 2 of the License, or (at your option) any later
|
---|
13 | version.
|
---|
14 |
|
---|
15 | This program is distributed in the hope that it will be useful, but WITHOUT
|
---|
16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
---|
17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
---|
18 |
|
---|
19 | You should have received a copy of the GNU Lesser General Public License along with
|
---|
20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
---|
21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to
|
---|
22 | http://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 |
|
---|
34 | namespace 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
|
---|