[1809] | 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
|
---|