using System.Runtime.CompilerServices;
namespace Misaki.HighPerformance.Mathematics.Geometry;
///
/// Represents a three-dimensional sphere defined by a center point and a radius, typically used for spatial bounding or
/// intersection tests.
///
public struct SphereBounds : IEquatable
{
///
/// Gets or sets the coordinates of the center point in three-dimensional space.
///
public float3 Center
{
get; set;
}
///
/// Gets or sets the radius of the shape.
///
public float Radius
{
get; set;
}
public SphereBounds(float3 center, float radius)
{
Center = center;
Radius = radius;
}
///
/// Determines whether the specified point is contained within the sphere.
///
/// The point to test for inclusion within the sphere.
/// true if the point lies inside or on the boundary of the sphere; otherwise, false.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool Contains(float3 point)
{
var toPoint = point - Center;
return math.lengthsq(toPoint) <= Radius * Radius;
}
///
/// Determines whether this sphere intersects with the specified sphere.
///
/// The sphere to test for intersection with this sphere.
/// true if the spheres intersect or touch; otherwise, false.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly bool Overlaps(SphereBounds other)
{
var toOther = other.Center - Center;
var radiusSum = Radius + other.Radius;
return math.lengthsq(toOther) <= radiusSum * radiusSum;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly float3 ClosestPoint(float3 point)
{
var toPoint = point - Center;
var toPointLength = math.length(toPoint);
if (toPointLength <= Radius || toPointLength == 0.0f)
{
return point;
}
return Center + toPoint / toPointLength * Radius;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Encapsulate(SphereBounds other)
{
var toOther = other.Center - Center;
var toOtherLength = math.length(toOther);
if (toOtherLength + other.Radius > Radius)
{
var newRadius = (Radius + toOtherLength + other.Radius) * 0.5f;
var k = (newRadius - Radius) / toOtherLength;
Center += toOther * k;
Radius = newRadius;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Encapsulate(float3 point)
{
var toPoint = point - Center;
var toPointLength = math.length(toPoint);
if (toPointLength > Radius)
{
var newRadius = (Radius + toPointLength) * 0.5f;
var k = (newRadius - Radius) / toPointLength;
Center += toPoint * k;
Radius = newRadius;
}
}
public override readonly string ToString()
{
return $"Center: {Center}, Radius: {Radius}";
}
public override readonly int GetHashCode()
{
return HashCode.Combine(Center, Radius);
}
public override readonly bool Equals(object? obj)
{
return obj is SphereBounds bound && Equals(bound);
}
public readonly bool Equals(SphereBounds other)
{
return Center.Equals(other.Center) && Radius.Equals(other.Radius);
}
public static bool operator ==(SphereBounds left, SphereBounds right)
{
return left.Equals(right);
}
public static bool operator !=(SphereBounds left, SphereBounds right)
{
return !(left == right);
}
}