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