#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