using System;
using System.Text.Json.Serialization;
using CultMath;
using MessagePack;
namespace GameCult.Geometry
{
///
/// Two-dimensional circle for spatial queries.
///
[MessagePackObject]
public readonly struct CultCircle : IEquatable
{
/// Creates a circle.
[JsonConstructor]
public CultCircle(float2 center, float radius)
{
if (radius < 0f)
{
throw new ArgumentOutOfRangeException(nameof(radius), "Radius cannot be negative.");
}
Center = center;
Radius = radius;
}
/// Gets the circle center.
[Key(0)]
public float2 Center { get; }
/// Gets the circle radius.
[Key(1)]
public float Radius { get; }
/// Gets the circle bounds.
[IgnoreMember]
[JsonIgnore]
public rect Bounds => new(
Center.x - Radius,
Center.y - Radius,
Center.x + Radius,
Center.y + Radius);
/// Returns whether the point lies inside or on the circle edge.
public bool Contains(float2 point)
{
var delta = point - Center;
return math.lengthsq(delta) <= Radius * Radius;
}
/// Returns whether this circle intersects a rectangle.
public bool Intersects(rect rect)
{
var clampedX = Math.Max(rect.min.x, Math.Min(Center.x, rect.max.x));
var clampedY = Math.Max(rect.min.y, Math.Min(Center.y, rect.max.y));
return Contains(new float2(clampedX, clampedY));
}
/// Returns whether this circle is equal to another circle.
public bool Equals(CultCircle other) => Center.Equals(other.Center) && Radius.Equals(other.Radius);
///
public override bool Equals(object? obj) => obj is CultCircle other && Equals(other);
///
public override int GetHashCode() => HashCode.Combine(Center, Radius);
public static bool operator ==(CultCircle left, CultCircle right) => left.Equals(right);
public static bool operator !=(CultCircle left, CultCircle right) => !left.Equals(right);
}
///
/// Three-dimensional sphere for physics and spatial queries.
///
[MessagePackObject]
public readonly struct CultSphere : IEquatable
{
/// Creates a sphere.
[JsonConstructor]
public CultSphere(float3 center, float radius)
{
if (radius < 0f)
{
throw new ArgumentOutOfRangeException(nameof(radius), "Radius cannot be negative.");
}
Center = center;
Radius = radius;
}
/// Gets the sphere center.
[Key(0)]
public float3 Center { get; }
/// Gets the sphere radius.
[Key(1)]
public float Radius { get; }
/// Gets the XY circle projection.
[IgnoreMember]
[JsonIgnore]
public CultCircle XyCircle => new(Center.xy, Radius);
/// Returns whether the point lies inside or on the sphere surface.
public bool Contains(float3 point)
{
var delta = point - Center;
return math.lengthsq(delta) <= Radius * Radius;
}
/// Returns whether this sphere is equal to another sphere.
public bool Equals(CultSphere other) => Center.Equals(other.Center) && Radius.Equals(other.Radius);
///
public override bool Equals(object? obj) => obj is CultSphere other && Equals(other);
///
public override int GetHashCode() => HashCode.Combine(Center, Radius);
public static bool operator ==(CultSphere left, CultSphere right) => left.Equals(right);
public static bool operator !=(CultSphere left, CultSphere right) => !left.Equals(right);
}
}