//
// Distributed under the BSD Licence (see LICENCE file).
//
// Copyright (c) 2014, Nition, http://www.momentstudio.co.nz/
// Copyright (c) 2017, Máté Cserép, http://codenet.hu
// All rights reserved.
//
namespace TerraBrush.NetOctree
{
using System;
using System.Runtime.Serialization;
using Godot;
///
/// Represents an axis aligned bounding box (AABB).
///
///
/// This class was inspired by the Bounds type of the Unity Engine and
/// designed with the exact same interface to provide maximum compatibility.
///
[DataContract]
public struct BoundingBox
{
///
/// Gets or sets the center of the bounding box.
///
[DataMember]
public Vector3 Center { get; set; }
///
/// Gets or sets the extents of the bounding box. This is always half of the .
///
[DataMember]
public Vector3 Extents { get; set; }
///
/// Gets or sets the size of the bounding box. This is always twice as large as the .
///
public Vector3 Size
{
get { return Extents * 2; }
set { Extents = value * 0.5f; }
}
///
/// Gets or sets the minimal point of the box.
///
///
/// This is always equal to center-extents.
///
public Vector3 Min
{
get { return Center - Extents; }
set { SetMinMax(value, Max); }
}
///
/// Gets or sets the maximal point of the box.
///
///
/// This is always equal to center+extents.
///
public Vector3 Max
{
get { return Center + Extents; }
set { SetMinMax(Min, value); }
}
///
/// Creates a new bounding box.
///
/// The center of the box.
/// The size of the box.
public BoundingBox(Vector3 center, Vector3 size)
{
Center = center;
Extents = size * 0.5f;
}
///
/// Sets the bounds to the min and max value of the box.
///
/// The minimal point.
/// The maximal point.
public void SetMinMax(Vector3 min, Vector3 max)
{
Extents = (max - min) * 0.5f;
Center = min + Extents;
}
///
/// Grows the bounding box include the point.
///
/// The specified point to include.
public void Encapsulate(Vector3 point)
{
SetMinMax(point.Min(Min), point.Max(Max));
}
///
/// Grows the bounding box include the other box.
///
/// The specified box to include.
public void Encapsulate(BoundingBox box)
{
Encapsulate(box.Center - box.Extents);
Encapsulate(box.Center + box.Extents);
}
///
/// Expands the bounds by increasing its by along each side.
///
/// The expansions for each dimension.
public void Expand(float amount)
{
amount *= 0.5f;
Extents += new Vector3(amount, amount, amount);
}
///
/// Expands the bounds by increasing its by along each side.
///
/// The expansions for each dimension in order.
public void Expand(Vector3 amount)
{
Extents += amount * 0.5f;
}
///
/// Determines whether the box contains the point.
///
/// The point to test.
/// true if the box contains the point; otherwise, false.
public bool Contains(Vector3 point)
{
return
Min.X <= point.X && Max.X >= point.X &&
Min.Y <= point.Y && Max.Y >= point.Y &&
Min.Z <= point.Z && Max.Z >= point.Z;
}
///
/// Determines whether the bounding box intersects with another box.
///
/// The box to test.
/// true if the bounding box intersects with another box, false otherwise.
public bool Intersects(BoundingBox box)
{
return
Min.X <= box.Max.X && Max.X >= box.Min.X &&
Min.Y <= box.Max.Y && Max.Y >= box.Min.Y &&
Min.Z <= box.Max.Z && Max.Z >= box.Min.Z;
}
///
/// Determines whether the bounding box intersects with a ray.
///
/// The ray to test.
/// true if the box intersects with the ray, false otherwise.
public bool IntersectRay(Ray ray)
{
float distance;
return IntersectRay(ray, out distance);
}
///
/// Determines whether the bounding box intersects with a ray.
///
/// The ray to test.
/// The calculated distance from the origin of the ray to the box along the ray.
/// true if the box intersects with the ray, false otherwise.
public bool IntersectRay(Ray ray, out float distance)
{
Vector3 dirFrac = new Vector3(
1f / ray.Direction.X,
1f / ray.Direction.Y,
1f / ray.Direction.Z
);
float t1 = (Min.X - ray.Origin.X) * dirFrac.X;
float t2 = (Max.X - ray.Origin.X) * dirFrac.X;
float t3 = (Min.Y - ray.Origin.Y) * dirFrac.Y;
float t4 = (Max.Y - ray.Origin.Y) * dirFrac.Y;
float t5 = (Min.Z - ray.Origin.Z) * dirFrac.Z;
float t6 = (Max.Z - ray.Origin.Z) * dirFrac.Z;
float tmin = Math.Max(Math.Max(Math.Min(t1, t2), Math.Min(t3, t4)), Math.Min(t5, t6));
float tmax = Math.Min(Math.Min(Math.Max(t1, t2), Math.Max(t3, t4)), Math.Max(t5, t6));
// if tmax < 0, ray (line) is intersecting AABB, but the whole AABB is behind us
if (tmax < 0)
{
distance = tmax;
return false;
}
// if tmin > tmax, ray doesn't intersect AABB
if (tmin > tmax)
{
distance = tmax;
return false;
}
distance = tmin;
return true;
}
///
/// Returns a hash code for this instance.
///
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
public override int GetHashCode()
{
return Center.GetHashCode() ^ Extents.GetHashCode() << 2;
}
///
/// Determines whether the specified object as a is equal to this instance.
///
/// The object to compare with this instance.
/// true if the specified box is equal to this instance; otherwise, false.
public override bool Equals(object other)
{
bool result;
if (!(other is BoundingBox))
{
result = false;
}
else
{
BoundingBox box = (BoundingBox)other;
result = (Center.Equals(box.Center) && Extents.Equals(box.Extents));
}
return result;
}
///
/// Returns a nicely formatted string for this bounding box.
///
public override string ToString()
{
return String.Format("Center: {0}, Extents: {1}",
Center,
Extents
);
}
///
/// Returns a nicely formatted string for this bounding box.
///
/// The format for the center and the extent.
public string ToString(string format)
{
return String.Format("Center: {0}, Extents: {1}",
Center.ToString(format),
Extents.ToString(format)
);
}
///
/// Determines whether two bounding boxes are equal.
///
/// The first box.
/// The second box.
public static bool operator ==(BoundingBox lhs, BoundingBox rhs)
{
return lhs.Center == rhs.Center && lhs.Extents == rhs.Extents;
}
///
/// Determines whether two bounding boxes are different.
///
/// The first box.
/// The second box.
public static bool operator !=(BoundingBox lhs, BoundingBox rhs)
{
return !(lhs == rhs);
}
}
}