irrlicht/source/Irrlicht.NET/Box3D.h

319 lines
9.1 KiB
C++

// Copyright (C) 2002-2006 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#pragma once
#include "Vector3D.h"
#include "Plane3D.h"
#include "Line3D.h"
namespace Irrlicht
{
namespace Core
{
/// <summary>
/// Axis aligned bounding box in 3d dimensional space.
/// Has some useful methods used with occlusion culling or clipping.
/// </summary>
public __value class Box3D
{
public:
// Constructors
Box3D(): MinEdge(-1,-1,-1), MaxEdge(1,1,1) {};
Box3D(const Vector3D min, const Vector3D max): MinEdge(min), MaxEdge(max) {};
Box3D(const Vector3D init): MinEdge(init), MaxEdge(init) {};
Box3D(float minx, float miny, float minz, float maxx, float maxy, float maxz): MinEdge(minx, miny, minz), MaxEdge(maxx, maxy, maxz) {};
/// <summary>
/// Adds a point to the bounding box, causing it to grow bigger,
/// if point is outside of the box
/// </summary>
/// <param name="p"> Point to add into the box.</param>
void AddInternalPoint(Vector3D p)
{
AddInternalPoint(p.X, p.Y, p.Z);
}
/// <summary>
/// Adds an other bounding box to the bounding box, causing it to grow bigger,
/// if the box is outside of the box
/// </summary>
/// <param name="b"> Other bounding box to add into this box.</param>
void AddInternalBox(Box3D b)
{
AddInternalPoint(b.MaxEdge);
AddInternalPoint(b.MinEdge);
}
/// <summary>
/// Resets the bounding box.
/// </summary>
void Reset(float x, float y, float z)
{
MaxEdge.Set(x,y,z);
MinEdge = MaxEdge;
}
/// <summary>
/// Resets the bounding box.
/// </summary>
void Reset(Box3D initValue)
{
*this = initValue;
}
/// <summary>
/// Resets the bounding box.
/// </summary>
void Reset(const Vector3D initValue)
{
MaxEdge = initValue;
MinEdge = initValue;
}
/// <summary>
/// Adds a point to the bounding box, causing it to grow bigger,
/// if point is outside of the box.
/// </summary>
/// <param name="x"> X Coordinate of the point to add to this box.</param>
/// <param name="y"> Y Coordinate of the point to add to this box.</param>
/// <param name="z"> Z Coordinate of the point to add to this box.</param>
void AddInternalPoint(float x, float y, float z)
{
if (x>MaxEdge.X) MaxEdge.X = x;
if (y>MaxEdge.Y) MaxEdge.Y = y;
if (z>MaxEdge.Z) MaxEdge.Z = z;
if (x<MinEdge.X) MinEdge.X = x;
if (y<MinEdge.Y) MinEdge.Y = y;
if (z<MinEdge.Z) MinEdge.Z = z;
}
/// <summary>
/// Determinates if a point is within this box.
/// </summary>
/// <param name="p">: Point to check.</param>
/// <returns> Returns true if the point is withing the box, and false if it is not.</returns>
bool IsPointInside(Vector3D p)
{
return ( p.X >= MinEdge.X && p.X <= MaxEdge.X &&
p.Y >= MinEdge.Y && p.Y <= MaxEdge.Y &&
p.Z >= MinEdge.Z && p.Z <= MaxEdge.Z);
};
/// <summary>
/// Determinates if a point is within this box and its borders.
/// </summary>
/// <param name="p"> Point to check.</param>
/// <returns> Returns true if the point is withing the box, and false if it is not.</returns>
bool IsPointTotalInside(Vector3D p)
{
return ( p.X > MinEdge.X && p.X < MaxEdge.X &&
p.Y > MinEdge.Y && p.Y < MaxEdge.Y &&
p.Z > MinEdge.Z && p.Z < MaxEdge.Z);
};
/// <summary>
/// Determinates if the box intersects with an other box.
/// </summary>
/// <param other: Other box to check a intersection with.</param>
/// <returns> Returns true if there is a intersection with the other box,
/// otherwise false.</returns>
bool IntersectsWithBox(Box3D other)
{
return (MinEdge.X <= other.MaxEdge.X &&
MinEdge.Y <= other.MaxEdge.Y &&
MinEdge.Z <= other.MaxEdge.Z &&
MaxEdge.X >= other.MinEdge.X &&
MaxEdge.Y >= other.MinEdge.Y &&
MaxEdge.Z >= other.MinEdge.Z);
}
/// <summary>
/// Tests if the box intersects with a line
/// </summary>
/// <param name="line"> Line to test intersection with.</param>
/// <returns> Returns true if there is an intersection and false if not.</returns>
bool IntersectsWithLine(Line3D line)
{
return IntersectsWithLine(line.GetMiddle(), line.GetVector().Normalize(),
(float)(line.GetLength() * 0.5));
}
/// <summary>
/// Tests if the box intersects with a line
/// </summary>
/// <returns> Returns true if there is an intersection and false if not.</returns>
bool IntersectsWithLine(Vector3D linemiddle,
Vector3D linevect,
float halflength)
{
Vector3D e = (MaxEdge - MinEdge) * (float)0.5;
Vector3D t = (MinEdge + e) - linemiddle;
float r;
if ((mfabs(t.X) > e.X + halflength * mfabs(linevect.X)) ||
(mfabs(t.Y) > e.Y + halflength * mfabs(linevect.Y)) ||
(mfabs(t.Z) > e.Z + halflength * mfabs(linevect.Z)) )
return false;
r = e.Y * (float)mfabs(linevect.Z) + e.Z * (float)mfabs(linevect.Y);
if (mfabs(t.Y*linevect.Z - t.Z*linevect.Y) > r )
return false;
r = e.X * (float)mfabs(linevect.Z) + e.Z * (float)mfabs(linevect.X);
if (mfabs(t.Z*linevect.X - t.X*linevect.Z) > r )
return false;
r = e.X * (float)mfabs(linevect.Y) + e.Y * (float)mfabs(linevect.X);
if (mfabs(t.X*linevect.Y - t.Y*linevect.X) > r)
return false;
return true;
}
/// <summary>
/// Classifies a relation with a plane.
/// </summary>
/// <param name="plane"> Plane to classify relation to.</param>
/// <returns> Returns ISREL3D_FRONT if the box is in front of the plane,
/// ISREL3D_BACK if the box is back of the plane, and
/// ISREL3D_CLIPPED if is on both sides of the plane.</returns>
IntersectionRelation3D classifyPlaneRelation(Plane3D plane)
{
Vector3D nearPoint(MaxEdge);
Vector3D farPoint(MinEdge);
if (plane.Normal.X > (float)0)
{
nearPoint.X = MinEdge.X;
farPoint.X = MaxEdge.X;
}
if (plane.Normal.Y > (float)0)
{
nearPoint.Y = MinEdge.Y;
farPoint.Y = MaxEdge.Y;
}
if (plane.Normal.Z > (float)0)
{
nearPoint.Z = MinEdge.Z;
farPoint.Z = MaxEdge.Z;
}
if (plane.Normal.DotProduct(nearPoint) + plane.D > (float)0)
return ISREL3D_FRONT;
if (plane.Normal.DotProduct(farPoint) + plane.D > (float)0)
return ISREL3D_CLIPPED;
return ISREL3D_BACK;
}
/// <summary>
/// returns center of the bounding box
/// </summary>
Vector3D getCenter()
{
return (MinEdge + MaxEdge) / 2;
}
/// <summary>
/// returns extent of the box
/// </summary>
Vector3D getExtent()
{
return MaxEdge - MinEdge;
}
/// <summary>
/// stores all 8 edges of the box into a array
/// </summary>
/// <param name="edges"> Pointer to array of 8 edges</param>
void getEdges(Vector3D edges __gc[])
{
Vector3D middle = (MinEdge + MaxEdge) / 2;
Vector3D diag = middle - MaxEdge;
/*
Edges are stored in this way:
Hey, am I an ascii artist, or what? :) niko.
/1--------/3
/ | / |
/ | / |
5---------7 |
| 0- - -| -2
| / | /
|/ | /
4---------6/
*/
edges[0].Set(middle.X + diag.X, middle.Y + diag.Y, middle.Z + diag.Z);
edges[1].Set(middle.X + diag.X, middle.Y - diag.Y, middle.Z + diag.Z);
edges[2].Set(middle.X + diag.X, middle.Y + diag.Y, middle.Z - diag.Z);
edges[3].Set(middle.X + diag.X, middle.Y - diag.Y, middle.Z - diag.Z);
edges[4].Set(middle.X - diag.X, middle.Y + diag.Y, middle.Z + diag.Z);
edges[5].Set(middle.X - diag.X, middle.Y - diag.Y, middle.Z + diag.Z);
edges[6].Set(middle.X - diag.X, middle.Y + diag.Y, middle.Z - diag.Z);
edges[7].Set(middle.X - diag.X, middle.Y - diag.Y, middle.Z - diag.Z);
}
/// <summary>
/// returns if the box is empty, which means that there is
/// no space within the min and the max edge.
/// </summary>
bool IsEmpty()
{
Vector3D d = MinEdge - MaxEdge;
if (d.X < 0) d.X = -d.X;
if (d.Y < 0) d.Y = -d.Y;
if (d.Z < 0) d.Z = -d.Z;
return (d.X < ROUNDING_ERROR &&
d.Y < ROUNDING_ERROR &&
d.Z < ROUNDING_ERROR);
}
/// <summary>
/// repairs the box, if for example MinEdge and MaxEdge are swapped.
/// </summary>
void Repair()
{
float t;
if (MinEdge.X > MaxEdge.X)
{ t=MinEdge.X; MinEdge.X = MaxEdge.X; MaxEdge.X=t; }
if (MinEdge.Y > MaxEdge.Y)
{ t=MinEdge.Y; MinEdge.Y = MaxEdge.Y; MaxEdge.Y=t; }
if (MinEdge.Z > MaxEdge.Z)
{ t=MinEdge.Z; MinEdge.Z = MaxEdge.Z; MaxEdge.Z=t; }
}
/// <summary>
/// Calculates a new interpolated bounding box.
/// </summary>
/// <param name="other"> other box to interpolate between</param>
/// <param name="d"> value between 0.0f and 1.0f.</param>
Box3D GetInterpolated(Box3D other, float d)
{
float inv = 1.0f - d;
return Box3D((other.MinEdge*inv) + (MinEdge*d),
(other.MaxEdge*inv) + (MaxEdge*d));
}
// member variables
Vector3D MinEdge;
Vector3D MaxEdge;
};
}
}