using System.Runtime.InteropServices;
using System.Text.Json.Serialization;
namespace Sandbox;
///
/// Represents a sphere.
///
[StructLayout( LayoutKind.Sequential )]
public struct Sphere
{
///
/// A sphere centered at the origin, with radius 1.
///
public static Sphere Unit { get; } = new( 0f, 1f );
public Sphere( Vector3 center, float radius )
{
Center = center;
Radius = radius;
}
public override readonly string ToString()
{
return $"Center({Center}), Radius({Radius})";
}
///
/// Center of the sphere.
///
[JsonInclude]
public Vector3 Center;
///
/// Radius of the sphere.
///
[JsonInclude]
public float Radius;
///
/// Performs an intersection test between this sphere and given ray.
///
public readonly bool Trace( Ray ray, float maxDistance, out float distance )
{
distance = 0;
var dirToCenter = ray.Position - Center;
var v = (ray.Forward.Dot( Center - ray.Position ));
var disc = Radius * Radius - ((dirToCenter.Dot( dirToCenter )) - v * v);
if ( disc >= 0.0f )
{
var time = (v - MathF.Sqrt( disc )) / maxDistance;
distance = maxDistance * time;
return (time >= 0.0f && time <= 1.0f);
}
return false;
}
///
/// Performs an intersection test between this sphere and given ray.
///
public readonly bool Trace( Ray ray, float maxDistance )
{
var dirToCenter = ray.Position - Center;
var v = (ray.Forward.Dot( Center - ray.Position ));
var disc = Radius * Radius - ((dirToCenter.Dot( dirToCenter )) - v * v);
if ( disc >= 0.0f )
{
var time = (v - MathF.Sqrt( disc )) / maxDistance;
return (time >= 0.0f && time <= 1.0f);
}
return false;
}
///
/// Returns true if sphere contains point. False if the point falls outside the sphere.
///
public bool Contains( in Vector3 value )
{
return (value - Center).Length <= Radius;
}
///
/// Volume of this sphere
///
[JsonIgnore]
public readonly float Volume
{
get
{
return (4.0f / 3.0f) * MathF.PI * Radius * Radius * Radius;
}
}
///
/// Get the volume of this sphere
///
[Obsolete( "Use Sphere.Volume instead." )]
public readonly float GetVolume()
{
return Volume;
}
///
/// Calculates the shortest distance from the specified local position to the nearest edge of the object.
///
public readonly float GetEdgeDistance( Vector3 localPos )
{
float distanceToCenter = (localPos - Center).Length;
return MathF.Abs( distanceToCenter - Radius );
}
///
/// Returns a random point within this sphere.
///
[JsonIgnore]
public readonly Vector3 RandomPointInside
{
get
{
return Center + System.Random.Shared.VectorInSphere( Radius );
}
}
///
/// Returns a random point on the edge of this sphere.
///
[JsonIgnore]
public readonly Vector3 RandomPointOnEdge
{
get
{
return Center + System.Random.Shared.VectorInSphere( 1 ).Normal * Radius;
}
}
}