< Summary

Information
Class: FixedMathSharp.Geometry.FixedBoundCircle
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Geometry/Bounds/FixedBoundCircle.cs
Line coverage
100%
Covered lines: 61
Uncovered lines: 0
Coverable lines: 61
Total lines: 308
Line coverage: 100%
Branch coverage
100%
Covered branches: 26
Total branches: 26
Branch coverage: 100%
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_Bounds()100%11100%
get_State()100%11100%
Contains(...)100%11100%
ContainsStrict(...)100%22100%
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(...)100%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 System;
 9using System.Runtime.CompilerServices;
 10using System.Text.Json.Serialization;
 11using MemoryPack;
 12
 13namespace FixedMathSharp.Geometry;
 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    {
 9073        Center = center;
 9074        _radius = NormalizeRadius(radius);
 9075    }
 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)]
 206106        get => _radius;
 107
 108        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 1109        set => _radius = NormalizeRadius(value);
 110    }
 111
 112    /// <summary>
 113    /// The normalized axis-aligned representable-domain intersection that
 114    /// contains every representable point of the circle.
 115    /// </summary>
 116    [JsonIgnore]
 117    [MemoryPackIgnore]
 118    public FixedBoundArea Bounds
 119    {
 120        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 4121        get => FixedBoundArea.FromCenterAndScopeClippedToDomain(Center, new Vector2d(Radius, Radius));
 122    }
 123
 124    /// <summary>
 125    /// Gets the current normalized state of the circle.
 126    /// </summary>
 127    [JsonInclude]
 128    [MemoryPackInclude]
 1129    public BoundingCircleState State => new(Center, Radius);
 130
 131    #endregion
 132
 133    #region Spatial Queries
 134
 135    /// <summary>
 136    /// Determines whether the point is inside this circle, including the boundary.
 137    /// </summary>
 138    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 139    public bool Contains(Vector2d point)
 140    {
 10141        return WideGeometry.CompareDistanceToRadiusSum(Center, point, Radius, Fixed64.Zero) <= 0;
 142    }
 143
 144    /// <summary>
 145    /// Returns whether the point lies strictly inside this circle.
 146    /// </summary>
 147    /// <remarks>
 148    /// Boundary points and every point tested against a zero-radius circle
 149    /// return <see langword="false"/>.
 150    /// </remarks>
 151    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 152    public bool ContainsStrict(Vector2d point) =>
 3153        Radius > Fixed64.Zero
 3154        && WideGeometry.CompareDistanceToRadiusSum(Center, point, Radius, Fixed64.Zero) < 0;
 155
 156    /// <summary>
 157    /// Classifies another circle against this circle using boundary-inclusive overlap.
 158    /// </summary>
 159    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 160    public FixedEnclosureType Contains(FixedBoundCircle circle)
 161    {
 14162        if (WideGeometry.CompareDistanceToRadiusSum(Center, circle.Center, Radius, circle.Radius) > 0)
 5163            return FixedEnclosureType.Disjoint;
 164
 9165        Fixed64 radiusDifference = Radius - circle.Radius;
 9166        if (radiusDifference >= Fixed64.Zero
 9167            && WideGeometry.CompareDistanceToRadiusSum(
 9168                Center,
 9169                circle.Center,
 9170                radiusDifference,
 9171                Fixed64.Zero) <= 0)
 2172            return FixedEnclosureType.Contains;
 173
 7174        return FixedEnclosureType.Intersects;
 175    }
 176
 177    /// <summary>
 178    /// Determines whether another circle intersects this circle, including boundary-only contact.
 179    /// </summary>
 180    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 5181    public bool Intersects(FixedBoundCircle circle) => Contains(circle) != FixedEnclosureType.Disjoint;
 182
 183    /// <summary>
 184    /// Determines whether an area intersects this circle, including boundary-only contact.
 185    /// </summary>
 186    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 187    public bool Intersects(FixedBoundArea area)
 188    {
 19189        return WideGeometry.CompareDistanceToRadiusSum(
 19190            Center,
 19191            area.ClampPoint(Center),
 19192            Radius,
 19193            Fixed64.Zero) <= 0;
 194    }
 195
 196    /// <summary>
 197    /// Determines whether another circle overlaps this circle with positive area.
 198    /// </summary>
 199    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 200    public bool IntersectsStrict(FixedBoundCircle circle)
 201    {
 4202        return Radius > Fixed64.Zero
 4203            && circle.Radius > Fixed64.Zero
 4204            && WideGeometry.CompareDistanceToRadiusSum(Center, circle.Center, Radius, circle.Radius) < 0;
 205    }
 206
 207    /// <summary>
 208    /// Determines whether an area overlaps this circle with positive area.
 209    /// </summary>
 210    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 211    public bool IntersectsStrict(FixedBoundArea area)
 212    {
 7213        return Radius > Fixed64.Zero
 7214            && area.Min.X < area.Max.X
 7215            && area.Min.Y < area.Max.Y
 7216            && WideGeometry.CompareDistanceToRadiusSum(
 7217                Center,
 7218                area.ClampPoint(Center),
 7219                Radius,
 7220                Fixed64.Zero) < 0;
 221    }
 222
 223    /// <summary>
 224    /// Clamps a point to this circle, returning the point unchanged when it is already inside.
 225    /// </summary>
 226    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 227    public Vector2d ClampPoint(Vector2d point)
 228    {
 3229        return Contains(point) ? point : ProjectPoint(point);
 230    }
 231
 232    /// <summary>
 233    /// Projects a point onto the circle boundary. The center is returned when the direction is degenerate.
 234    /// </summary>
 235    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 236    public Vector2d ProjectPoint(Vector2d point)
 237    {
 3238        Vector2d direction = point - Center;
 3239        if (direction.EqualsZero())
 1240            return Center;
 241
 2242        return Center + direction.NormalizeInPlace() * Radius;
 243    }
 244
 245    #endregion
 246
 247    #region Deconstruction
 248
 249    /// <summary>
 250    /// Deconstructs the circle into center and normalized radius.
 251    /// </summary>
 252    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 253    public void Deconstruct(out Vector2d center, out Fixed64 radius)
 254    {
 1255        center = Center;
 1256        radius = Radius;
 1257    }
 258
 259    #endregion
 260
 261    #region Equality
 262
 263    /// <inheritdoc />
 264    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 265    public bool Equals(FixedBoundCircle other)
 266    {
 9267        return Center == other.Center && Radius == other.Radius;
 268    }
 269
 270    /// <inheritdoc />
 271    public override bool Equals(object? obj)
 272    {
 2273        return obj is FixedBoundCircle other && Equals(other);
 274    }
 275
 276    /// <inheritdoc />
 277    public override int GetHashCode()
 278    {
 279        unchecked
 280        {
 3281            int hash = 17;
 3282            hash = (hash * 31) + Center.StateHash;
 3283            hash = (hash * 31) + Radius.GetHashCode();
 3284            return hash;
 285        }
 286    }
 287
 288    /// <summary>
 289    /// Determines whether two circles have the same normalized state.
 290    /// </summary>
 291    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2292    public static bool operator ==(FixedBoundCircle left, FixedBoundCircle right) => left.Equals(right);
 293
 294    /// <summary>
 295    /// Determines whether two circles have different normalized state.
 296    /// </summary>
 297    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 2298    public static bool operator !=(FixedBoundCircle left, FixedBoundCircle right) => !left.Equals(right);
 299
 300    #endregion
 301
 302    #region Helpers
 303
 304    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 94305    private static Fixed64 NormalizeRadius(Fixed64 radius) => FixedMath.Abs(radius);
 306
 307    #endregion
 308}