using System;
using System.Runtime.CompilerServices;
using Unity.IL2CPP.CompilerServices;
using static Unity.Mathematics.math;
namespace Unity.Mathematics.Geometry
{
///
/// Axis aligned bounding box (AABB) stored in min and max form.
///
///
/// Axis aligned bounding boxes (AABB) are boxes where each side is parallel with one of the Cartesian coordinate axes
/// X, Y, and Z. AABBs are useful for approximating the region an object (or collection of objects) occupies and quickly
/// testing whether or not that object (or collection of objects) is relevant. Because they are axis aligned, they
/// are very cheap to construct and perform overlap tests with them.
///
[System.Serializable]
[Il2CppEagerStaticClassConstruction]
internal struct MinMaxAABB : IEquatable
{
///
/// The minimum point contained by the AABB.
///
///
/// If any component of is greater than then this AABB is invalid.
///
///
public float3 Min;
///
/// The maximum point contained by the AABB.
///
///
/// If any component of is less than then this AABB is invalid.
///
///
public float3 Max;
///
/// 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 MinMaxAABB(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 MinMaxAABB 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 MinMaxAABB CreateFromCenterAndHalfExtents(float3 center, float3 halfExtents)
{
return new MinMaxAABB(center - halfExtents, center + halfExtents);
}
///
/// Computes the extents of the AABB.
///
///
/// Extents is the componentwise distance between min and max.
///
public 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 float3 HalfExtents => (Max - Min) * 0.5f;
///
/// Computes the center of the AABB.
///
public 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 bool IsValid => math.all(Min <= Max);
///
/// Computes the surface area for this axis aligned bounding box.
///
public float SurfaceArea
{
get
{
float3 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 bool Contains(float3 point) => math.all(point >= Min & point <= 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 bool Contains(MinMaxAABB aabb) => math.all((Min <= aabb.Min) & (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 bool Overlaps(MinMaxAABB aabb)
{
return math.all(Max >= aabb.Min & Min <= 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 -= signedDistance;
Max += 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(MinMaxAABB 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 bool Equals(MinMaxAABB other)
{
return Min.Equals(other.Min) && Max.Equals(other.Max);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString()
{
return string.Format("MinMaxAABB({0}, {1})", Min, Max);
}
}
internal static partial class Math
{
///
/// Transforms the AABB with the given transform.
///
///
/// The resulting AABB encapsulates the transformed AABB which may not be axis aligned after the transformation.
///
/// Transform to apply to AABB.
/// AABB to be transformed.
/// Transformed AABB.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MinMaxAABB Transform(RigidTransform transform, MinMaxAABB aabb)
{
float3 halfExtentsInA = aabb.HalfExtents;
// Rotate each axis individually and find their new positions in the rotated space.
float3 x = math.rotate(transform.rot, new float3(halfExtentsInA.x, 0, 0));
float3 y = math.rotate(transform.rot, new float3(0, halfExtentsInA.y, 0));
float3 z = math.rotate(transform.rot, new float3(0, 0, halfExtentsInA.z));
// Find the new max corner by summing the rotated axes. Absolute value of each axis
// since we are trying to find the max corner.
float3 halfExtentsInB = math.abs(x) + math.abs(y) + math.abs(z);
float3 centerInB = math.transform(transform, aabb.Center);
return new MinMaxAABB(centerInB - halfExtentsInB, centerInB + halfExtentsInB);
}
///
/// Transforms the AABB with the given transform.
///
///
/// The resulting AABB encapsulates the transformed AABB which may not be axis aligned after the transformation.
///
/// Transform to apply to AABB.
/// AABB to be transformed.
/// Transformed AABB.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MinMaxAABB Transform(float4x4 transform, MinMaxAABB aabb)
{
var transformed = Transform(new float3x3(transform), aabb);
transformed.Min += transform.c3.xyz;
transformed.Max += transform.c3.xyz;
return transformed;
}
///
/// Transforms the AABB with the given transform.
///
///
/// The resulting AABB encapsulates the transformed AABB which may not be axis aligned after the transformation.
///
/// Transform to apply to AABB.
/// AABB to be transformed.
/// Transformed AABB.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static MinMaxAABB Transform(float3x3 transform, MinMaxAABB aabb)
{
// From Christer Ericson's Real-Time Collision Detection on page 86 and 87.
// We want the transformed minimum and maximums of the AABB. Multiplying a 3x3 matrix on the left of a
// column vector looks like so:
//
// [ c0.x c1.x c2.x ] [ x ] [ c0.x * x + c1.x * y + c2.x * z ]
// [ c0.y c1.y c2.y ] [ y ] = [ c0.y * x + c1.y * y + c2.y * z ]
// [ c0.z c1.z c2.z ] [ z ] [ c0.z * x + c1.z * y + c2.z * z ]
//
// The column vectors we will use are the input AABB's min and max. Simply multiplying those two vectors
// with the transformation matrix won't guarantee we get the new min and max since those are only two
// points out of eight in the AABB and one of the other six may set the new min or max.
//
// To ensure we get the correct min and max, we must transform all eight points. But it's not necessary
// to actually perform eight matrix multiplies to get our final result. Instead, we can build the min and
// max incrementally by computing each term in the above matrix multiply separately then summing the min
// (or max). For instance, to find the new minimum contributed by the original min and max x component, we
// compute this:
//
// newMin.x = min(c0.x * Min.x, c0.x * Max.x);
// newMin.y = min(c0.y * Min.x, c0.y * Max.x);
// newMin.z = min(c0.z * Min.x, c0.z * Max.x);
//
// Then we add minimum contributed by the original min and max y components:
//
// newMin.x += min(c1.x * Min.y, c1.x * Max.y);
// newMin.y += min(c1.y * Min.y, c1.y * Max.y);
// newMin.z += min(c1.z * Min.y, c1.z * Max.y);
//
// And so on. Translation can be handled by simply initializing the new min and max with the translation
// amount since it does not affect the min and max bounds in local space.
var t1 = transform.c0.xyz * aabb.Min.xxx;
var t2 = transform.c0.xyz * aabb.Max.xxx;
var minMask = t1 < t2;
var transformed = new MinMaxAABB(select(t2, t1, minMask), select(t2, t1, !minMask));
t1 = transform.c1.xyz * aabb.Min.yyy;
t2 = transform.c1.xyz * aabb.Max.yyy;
minMask = t1 < t2;
transformed.Min += select(t2, t1, minMask);
transformed.Max += select(t2, t1, !minMask);
t1 = transform.c2.xyz * aabb.Min.zzz;
t2 = transform.c2.xyz * aabb.Max.zzz;
minMask = t1 < t2;
transformed.Min += select(t2, t1, minMask);
transformed.Max += select(t2, t1, !minMask);
return transformed;
}
}
}