< Summary

Information
Class: FixedMathSharp.Bounds.FixedBoundCircle
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Bounds/FixedBoundCircle.cs
Line coverage
94%
Covered lines: 50
Uncovered lines: 3
Coverable lines: 53
Total lines: 306
Line coverage: 94.3%
Branch coverage
95%
Covered branches: 23
Total branches: 24
Branch coverage: 95.8%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
.ctor(...)100%11100%
.ctor(...)100%11100%
get_Radius()100%11100%
set_Radius(...)100%11100%
get_RadiusSquared()100%11100%
get_Bounds()100%11100%
get_State()100%11100%
set_State(...)100%210%
Contains(...)100%11100%
Contains(...)100%66100%
Intersects(...)100%11100%
Intersects(...)100%11100%
IntersectsStrict(...)100%44100%
IntersectsStrict(...)100%66100%
ClampPoint(...)100%22100%
ProjectPoint(...)100%22100%
Deconstruct(...)100%11100%
Equals(...)100%22100%
Equals(...)50%22100%
GetHashCode()100%11100%
op_Equality(...)100%11100%
op_Inequality(...)100%11100%
NormalizeRadius(...)100%11100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Bounds/FixedBoundCircle.cs

#LineLine coverage
 1//=======================================================================
 2// FixedBoundCircle.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024–present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8using MemoryPack;
 9using System;
 10using System.Runtime.CompilerServices;
 11using System.Text.Json.Serialization;
 12
 13namespace FixedMathSharp.Bounds;
 14
 15/// <summary>
 16/// Represents a normalized two-dimensional circular bound.
 17/// </summary>
 18/// <remarks>
 19/// Radius inputs are normalized by absolute value so a public circle cannot
 20/// retain a negative radius through construction, assignment, or state load.
 21/// </remarks>
 22[Serializable]
 23[MemoryPackable]
 24public partial struct FixedBoundCircle : IEquatable<FixedBoundCircle>
 25{
 26    #region Nested Types
 27
 28    /// <summary>
 29    /// Represents the normalized serializable state of a two-dimensional circular bound.
 30    /// </summary>
 31    [Serializable]
 32    [MemoryPackable]
 33    public readonly partial struct BoundingCircleState
 34    {
 35        /// <inheritdoc cref="FixedBoundCircle.Center"/>
 36        [JsonInclude]
 37        [MemoryPackInclude]
 38        public readonly Vector2d Center;
 39
 40        /// <inheritdoc cref="FixedBoundCircle.Radius"/>
 41        [JsonInclude]
 42        [MemoryPackInclude]
 43        public readonly Fixed64 Radius;
 44
 45        /// <summary>
 46        /// Initializes a normalized state from center and radius.
 47        /// </summary>
 48        [JsonConstructor]
 49        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 50        public BoundingCircleState(Vector2d center, Fixed64 radius)
 51        {
 352            Center = center;
 353            Radius = NormalizeRadius(radius);
 354        }
 55    }
 56
 57    #endregion
 58
 59    #region Fields
 60
 61    private Fixed64 _radius;
 62
 63    #endregion
 64
 65    #region Constructors
 66
 67    /// <summary>
 68    /// Initializes a new instance from a center point and radius.
 69    /// </summary>
 70    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 71    public FixedBoundCircle(Vector2d center, Fixed64 radius)
 72    {
 4773        Center = center;
 4774        _radius = NormalizeRadius(radius);
 4775    }
 76
 77    /// <summary>
 78    /// Initializes a new instance from serialized or caller-provided state.
 79    /// </summary>
 80    [JsonConstructor]
 81    public FixedBoundCircle(BoundingCircleState state)
 82    {
 283        Center = state.Center;
 284        _radius = state.Radius;
 285    }
 86
 87    #endregion
 88
 89    #region Properties
 90
 91    /// <summary>
 92    /// The center point of the circle.
 93    /// </summary>
 94    [JsonIgnore]
 95    [MemoryPackIgnore]
 96    public Vector2d Center { get; set; }
 97
 98    /// <summary>
 99    /// The non-negative radius of the circle. Assigned values are normalized by absolute value.
 100    /// </summary>
 101    [JsonIgnore]
 102    [MemoryPackIgnore]
 103    public Fixed64 Radius
 104    {
 105        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 168106        get => _radius;
 107
 108        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1109        set => _radius = NormalizeRadius(value);
 110    }
 111
 112    /// <summary>
 113    /// The squared radius of the circle.
 114    /// </summary>
 115    [JsonIgnore]
 116    [MemoryPackIgnore]
 117    public Fixed64 RadiusSquared
 118    {
 119        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 38120        get => Radius * Radius;
 121    }
 122
 123    /// <summary>
 124    /// The normalized axis-aligned area that contains the circle.
 125    /// </summary>
 126    [JsonIgnore]
 127    [MemoryPackIgnore]
 128    public FixedBoundArea Bounds
 129    {
 130        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 7131        get => FixedBoundArea.FromCenterAndScope(Center, new Vector2d(Radius, Radius));
 132    }
 133
 134    /// <summary>
 135    /// Gets or sets the current normalized state of the circle.
 136    /// </summary>
 137    [JsonInclude]
 138    [MemoryPackInclude]
 139    public BoundingCircleState State
 140    {
 1141        get => new(Center, Radius);
 142
 143        internal set
 144        {
 0145            Center = value.Center;
 0146            Radius = value.Radius;
 0147        }
 148    }
 149
 150    #endregion
 151
 152    #region Spatial Queries
 153
 154    /// <summary>
 155    /// Determines whether the point is inside this circle, including the boundary.
 156    /// </summary>
 157    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 158    public bool Contains(Vector2d point)
 159    {
 11160        return Vector2d.DistanceSquared(Center, point) <= RadiusSquared;
 161    }
 162
 163    /// <summary>
 164    /// Classifies another circle against this circle using boundary-inclusive overlap.
 165    /// </summary>
 166    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 167    public FixedEnclosureType Contains(FixedBoundCircle circle)
 168    {
 11169        Fixed64 sqDistance = Vector2d.DistanceSquared(Center, circle.Center);
 11170        Fixed64 combinedRadius = Radius + circle.Radius;
 171
 11172        if (sqDistance > combinedRadius * combinedRadius)
 3173            return FixedEnclosureType.Disjoint;
 174
 8175        Fixed64 radiusDifference = Radius - circle.Radius;
 8176        if (radiusDifference >= Fixed64.Zero && sqDistance <= radiusDifference * radiusDifference)
 2177            return FixedEnclosureType.Contains;
 178
 6179        return FixedEnclosureType.Intersects;
 180    }
 181
 182    /// <summary>
 183    /// Determines whether another circle intersects this circle, including boundary-only contact.
 184    /// </summary>
 185    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 5186    public bool Intersects(FixedBoundCircle circle) => Contains(circle) != FixedEnclosureType.Disjoint;
 187
 188    /// <summary>
 189    /// Determines whether an area intersects this circle, including boundary-only contact.
 190    /// </summary>
 191    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 192    public bool Intersects(FixedBoundArea area)
 193    {
 13194        return Vector2d.DistanceSquared(Center, area.ClampPoint(Center)) <= RadiusSquared;
 195    }
 196
 197    /// <summary>
 198    /// Determines whether another circle overlaps this circle with positive area.
 199    /// </summary>
 200    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 201    public bool IntersectsStrict(FixedBoundCircle circle)
 202    {
 3203        Fixed64 combinedRadius = Radius + circle.Radius;
 3204        return Radius > Fixed64.Zero
 3205            && circle.Radius > Fixed64.Zero
 3206            && Vector2d.DistanceSquared(Center, circle.Center) < combinedRadius * combinedRadius;
 207    }
 208
 209    /// <summary>
 210    /// Determines whether an area overlaps this circle with positive area.
 211    /// </summary>
 212    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 213    public bool IntersectsStrict(FixedBoundArea area)
 214    {
 7215        return Radius > Fixed64.Zero
 7216            && area.Min.X < area.Max.X
 7217            && area.Min.Y < area.Max.Y
 7218            && Vector2d.DistanceSquared(Center, area.ClampPoint(Center)) < RadiusSquared;
 219    }
 220
 221    /// <summary>
 222    /// Clamps a point to this circle, returning the point unchanged when it is already inside.
 223    /// </summary>
 224    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 225    public Vector2d ClampPoint(Vector2d point)
 226    {
 3227        return Contains(point) ? point : ProjectPoint(point);
 228    }
 229
 230    /// <summary>
 231    /// Projects a point onto the circle boundary. The center is returned when the direction is degenerate.
 232    /// </summary>
 233    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 234    public Vector2d ProjectPoint(Vector2d point)
 235    {
 3236        Vector2d direction = point - Center;
 3237        if (direction.EqualsZero())
 1238            return Center;
 239
 2240        return Center + direction.NormalizeInPlace() * Radius;
 241    }
 242
 243    #endregion
 244
 245    #region Deconstruction
 246
 247    /// <summary>
 248    /// Deconstructs the circle into center and normalized radius.
 249    /// </summary>
 250    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 251    public void Deconstruct(out Vector2d center, out Fixed64 radius)
 252    {
 1253        center = Center;
 1254        radius = Radius;
 1255    }
 256
 257    #endregion
 258
 259    #region Equality
 260
 261    /// <inheritdoc />
 262    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 263    public bool Equals(FixedBoundCircle other)
 264    {
 8265        return Center == other.Center && Radius == other.Radius;
 266    }
 267
 268    /// <inheritdoc />
 269    public override bool Equals(object? obj)
 270    {
 1271        return obj is FixedBoundCircle other && Equals(other);
 272    }
 273
 274    /// <inheritdoc />
 275    public override int GetHashCode()
 276    {
 277        unchecked
 278        {
 3279            int hash = 17;
 3280            hash = (hash * 31) + Center.StateHash;
 3281            hash = (hash * 31) + Radius.GetHashCode();
 3282            return hash;
 283        }
 284    }
 285
 286    /// <summary>
 287    /// Determines whether two circles have the same normalized state.
 288    /// </summary>
 289    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2290    public static bool operator ==(FixedBoundCircle left, FixedBoundCircle right) => left.Equals(right);
 291
 292    /// <summary>
 293    /// Determines whether two circles have different normalized state.
 294    /// </summary>
 295    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2296    public static bool operator !=(FixedBoundCircle left, FixedBoundCircle right) => !left.Equals(right);
 297
 298    #endregion
 299
 300    #region Helpers
 301
 302    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 51303    private static Fixed64 NormalizeRadius(Fixed64 radius) => FixedMath.Abs(radius);
 304
 305    #endregion
 306}