#region CPL License
/*
Nuclex Framework
Copyright (C) 2002-2009 Nuclex Development Labs
This library is free software; you can redistribute it and/or
modify it under the terms of the IBM Common Public License as
published by the IBM Corporation; either version 1.0 of the
License, or (at your option) any later version.
This library 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
IBM Common Public License for more details.
You should have received a copy of the IBM Common Public
License along with this library
*/
#endregion
using System;
using Microsoft.Xna.Framework;
namespace Nuclex.Geometry.Volumes {
/// Three-dimensional axis aligned box
#if !NO_SERIALIZATION
[Serializable]
#endif
public class AxisAlignedBox3 : IVolume3 {
/// Initializes a new box volume
/// Lower left back bounds of the box
/// Upper right front bounds of the box
[System.Diagnostics.DebuggerStepThrough]
public AxisAlignedBox3(Vector3 min, Vector3 max) {
Min = min;
Max = max;
}
/// Initializes a new box volume as copy of an existing box
/// Existing box that will be copied
[System.Diagnostics.DebuggerStepThrough]
public AxisAlignedBox3(AxisAlignedBox3 other)
: this(other.Min, other.Max) { }
/// Accepts a visitor to access the concrete volume implementation
/// Visitor to be accepted
public void Accept(VolumeVisitor visitor) {
visitor.Visit(this);
}
/// Smallest box that encloses the volume in its entirety
///
/// This always produces an optimal box which means a tight-fitting box is generated
/// that will touch the volume on each of its six sides. As a side effect, it is very
/// likely that this box needs to be recalculated whenever the volume changes its
/// orientation.
///
public AxisAlignedBox3 BoundingBox {
get { return new AxisAlignedBox3(Min, Max); } // Create a copy to be on the safe side...
}
/// Smallest sphere that encloses the volume in its entirety
///
/// Bounding spheres have the advantage to not change even when the volume is
/// rotated. That makes them ideal for dynamic objects that are not keeping their
/// original orientation.
///
public Sphere3 BoundingSphere {
get {
Vector3 center = Center;
return new Sphere3(center, (this.Max - center).Length());
}
}
/// Amount of mass that the volume contains
public float Mass {
get { return Width * Height * Depth; }
}
/// The volume's total surface area
public float SurfaceArea {
get {
float width = Width;
float height = Height;
float depth = Depth;
return 2.0f * (width * height + width * depth + height * depth);
}
}
/// Center of the volume's mass
public Vector3 CenterOfMass {
get {
return new Vector3(
(Min.X + Max.X) / 2.0f,
(Min.Y + Max.Y) / 2.0f,
(Min.Z + Max.Z) / 2.0f
);
}
}
/// The inertia tensor matrix of the volume
public Matrix InertiaTensor {
get {
// TODO: Check that this is correct.
// http://www.gamedev.net/community/forums/topic.asp?topic_id=57001
// (Careful, there are different methods depending on whether your box
// is centered on its corner or on its center of mass)
float widthSquared = this.Dimensions.X * this.Dimensions.X;
float heightSquared = this.Dimensions.Y * this.Dimensions.Y;
float depthSquared = this.Dimensions.Z * this.Dimensions.Z;
return new Matrix(
(heightSquared + depthSquared) / 3.0f, 0.0f, 0.0f, 0.0f,
0.0f, (widthSquared + depthSquared) / 3.0f, 0.0f, 0.0f,
0.0f, 0.0f, (widthSquared + heightSquared) / 3.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
);
}
}
/// Locates the nearest point in the volume to some arbitrary location
/// Location to which the closest point is determined
/// The closest point in the volume to the specified location
public Vector3 ClosestPointTo(Vector3 location) {
return new Vector3(
Math.Min(Math.Max(location.X, Min.X), Max.X),
Math.Min(Math.Max(location.Y, Min.Y), Max.Y),
Math.Min(Math.Max(location.Z, Min.Z), Max.Z)
);
}
/// The width of the box (x axis)
public float Width {
[System.Diagnostics.DebuggerStepThrough]
get { return Max.X - Min.X; }
}
/// The height of the box (y axis)
public float Height {
[System.Diagnostics.DebuggerStepThrough]
get { return Max.Y - Min.Y; }
}
/// The depth of the box (z axis)
public float Depth {
[System.Diagnostics.DebuggerStepThrough]
get { return Max.Z - Min.Z; }
}
/// Vector containing the extents of the box
public Vector3 Extents {
[System.Diagnostics.DebuggerStepThrough]
get { return this.Dimensions / 2.0f; }
}
/// Vector containing the dimensions of the box
public Vector3 Dimensions {
[System.Diagnostics.DebuggerStepThrough]
get { return Max - Min; }
}
/// The center of the box
public Vector3 Center {
[System.Diagnostics.DebuggerStepThrough]
get { return (Min + Max) / 2; }
}
/// Determines if the volume clips the circle
/// Circle that will be checked for intersection
/// True if the objects overlap
public bool Intersects(Sphere3 sphere) {
return Collisions.AabbSphereCollider.CheckContact(
this.Min, this.Max, sphere.Center, sphere.Radius
);
}
/// Determines if the volume clips the axis aligned box
/// Box that will be checked for intersection
/// True if the objects overlap
public bool Intersects(AxisAlignedBox3 box) {
return Collisions.AabbAabbCollider.CheckContact(
this.Min, this.Max, box.Min, box.Max
);
}
/// Determines if the volume clips the box
/// Box that will be checked for intersection
/// True if the objects overlap
public bool Intersects(Box3 box) {
return Collisions.AabbObbCollider.CheckContact(
Extents, box.Transform, box.Extents
);
}
/// Returns a random point on the volume's surface
/// Random number generator that will be used
/// A random point on the volume's surface
public Vector3 RandomPointOnSurface(IRandom randomNumberGenerator) {
return PointGenerators.AabbPointGenerator.GenerateRandomPointOnSurface(
randomNumberGenerator, this.Extents
) + this.Center;
}
/// Returns a random point within the volume
/// Random number generator that will be used
/// A random point within the volume
public Vector3 RandomPointWithin(IRandom randomNumberGenerator) {
return PointGenerators.AabbPointGenerator.GenerateRandomPointWithin(
randomNumberGenerator, this.Extents
) + this.Center;
}
/// Determines if two axis aligned boxes are equal
/// First axis aligned box to be compared
/// Second axis aligned box to be compared
/// True if both axis aligned boxes are equal
[System.Diagnostics.DebuggerStepThrough]
public static bool operator ==(AxisAlignedBox3 first, AxisAlignedBox3 second) {
return (first.Min == second.Min) && (first.Max == second.Max);
}
/// Determines if two axis aligned boxes are unequal
/// First axis aligned box to be compared
/// Second axis aligned box to be compared
/// True if both axis aligned boxes are unequal
[System.Diagnostics.DebuggerStepThrough]
public static bool operator !=(AxisAlignedBox3 first, AxisAlignedBox3 second) {
return (first.Min != second.Min) || (first.Max != second.Max);
}
/// Determines if an object is identical to the axis aligned box
/// Object to compare to
/// True if the object is identical to the axis aligned box
public override bool Equals(object obj) {
AxisAlignedBox3 box = obj as AxisAlignedBox3;
if(!ReferenceEquals(box, null))
return (this == box);
else
return false;
}
/// Builds a hashing code for the instance
/// The instance's hashing code
public override int GetHashCode() {
return Min.GetHashCode() ^ Max.GetHashCode();
}
/// Converts the axis aligned box to a readable string representation
/// The axis aligned box as a string
public override string ToString() {
return "{ " + Min.ToString() + " - " + Max.ToString() + " }";
}
/// Lower left back bounds of the box
public Vector3 Min;
/// Upper right front bounds of the box
public Vector3 Max;
}
} // namespace Nuclex.Geometry.Volumes