using System.Runtime.CompilerServices; namespace Misaki.HighPerformance.Mathematics.Geometry; /// /// Represents an axis-aligned bounding box (AABB) defined by minimum and maximum points in 3D space. /// public struct AABB : IEquatable { /// /// The minimum point contained by the AABB. /// /// /// If any component of is greater than then this AABB is invalid. /// /// public float3 Min { get; set; } /// /// The maximum point contained by the AABB. /// /// /// If any component of is less than then this AABB is invalid. /// /// public float3 Max { get; set; } /// /// Constructs the AABB with the given minimum and maximum. /// /// /// If you have a center and extents, you can call or /// to create the AABB. /// /// Minimum point inside AABB. /// Maximum point inside AABB. [MethodImpl(MethodImplOptions.AggressiveInlining)] public AABB(float3 min, float3 max) { Min = min; Max = max; } /// /// Creates the AABB from a center and extents. /// /// /// This function takes full extents. It is the distance between and . /// If you have half extents, you can call . /// /// Center of AABB. /// Full extents of AABB. /// AABB created from inputs. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static AABB CreateFromCenterAndExtents(float3 center, float3 extents) { return CreateFromCenterAndHalfExtents(center, extents * 0.5f); } /// /// Creates the AABB from a center and half extents. /// /// /// This function takes half extents. It is half the distance between and . /// If you have full extents, you can call . /// /// Center of AABB. /// Half extents of AABB. /// AABB created from inputs. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static AABB CreateFromCenterAndHalfExtents(float3 center, float3 halfExtents) { return new AABB(center - halfExtents, center + halfExtents); } /// /// Creates a new AABB with zero extents, centered at the origin. /// public static AABB Zero { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new AABB(float3.zero, float3.zero); } } /// /// Computes the extents of the AABB. /// /// /// Extents is the componentwise distance between min and max. /// public readonly float3 Extents => Max - Min; /// /// Computes the half extents of the AABB. /// /// /// HalfExtents is half of the componentwise distance between min and max. Subtracting HalfExtents from Center /// gives Min and adding HalfExtents to Center gives Max. /// public readonly float3 HalfExtents => (Max - Min) * 0.5f; /// /// Computes the center of the AABB. /// public readonly float3 Center => (Max + Min) * 0.5f; /// /// Check if the AABB is valid. /// /// /// An AABB is considered valid if is componentwise less than or equal to . /// /// True if is componentwise less than or equal to . public readonly bool IsValid => math.dot(Min, Min) <= math.dot(Max, Max); /// /// Computes the surface area for this axis aligned bounding box. /// public readonly float SurfaceArea { get { var diff = Max - Min; return 2 * math.dot(diff, diff.yzx); } } /// /// Tests if the input point is contained by the AABB. /// /// Point to test. /// True if AABB contains the input point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(float3 point) => math.dot(point, point) >= math.dot(Min, Min) && math.dot(point, point) <= math.dot(Max, Max); /// /// Tests if the input AABB is contained entirely by this AABB. /// /// AABB to test. /// True if input AABB is contained entirely by this AABB. [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Contains(AABB aabb) => math.dot(Min, Min) <= math.dot(aabb.Min, aabb.Min) && math.dot(Max, Max) >= math.dot(aabb.Max, aabb.Max); /// /// Tests if the input AABB overlaps this AABB. /// /// AABB to test. /// True if input AABB overlaps with this AABB. [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Overlaps(AABB aabb) { return math.dot(Max, Max) >= math.dot(aabb.Min, aabb.Min) && math.dot(Min, Min) <= math.dot(aabb.Max, aabb.Max); } /// /// Expands the AABB by the given signed distance. /// /// /// Positive distance expands the AABB while negative distance shrinks the AABB. /// /// Signed distance to expand the AABB with. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Expand(float signedDistance) { Min -= new float3(signedDistance); Max += new float3(signedDistance); } /// /// Encapsulates the given AABB. /// /// /// Modifies this AABB so that it contains the given AABB. If the given AABB is already contained by this AABB, /// then this AABB doesn't change. /// /// /// AABB to encapsulate. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Encapsulate(AABB aabb) { Min = math.min(Min, aabb.Min); Max = math.max(Max, aabb.Max); } /// /// Encapsulate the given point. /// /// /// Modifies this AABB so that it contains the given point. If the given point is already contained by this AABB, /// then this AABB doesn't change. /// /// /// Point to encapsulate. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Encapsulate(float3 point) { Min = math.min(Min, point); Max = math.max(Max, point); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly bool Equals(AABB other) { return Min.Equals(other.Min) && Max.Equals(other.Max); } public override bool Equals(object? obj) { if (obj is AABB AABB) { return Equals(AABB); } return false; } public static bool operator ==(AABB left, AABB right) { return left.Equals(right); } public static bool operator !=(AABB left, AABB right) { return !(left == right); } public override readonly int GetHashCode() { return HashCode.Combine(Min, Max); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public override readonly string ToString() { return string.Format("AABB({0}, {1})", Min, Max); } }