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); } }