< Summary

Information
Class: FixedMathSharp.FixedCurve
Assembly: FixedMathSharp
File(s): /home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Numerics/FixedCurve.cs
Line coverage
97%
Covered lines: 45
Uncovered lines: 1
Coverable lines: 46
Total lines: 140
Line coverage: 97.8%
Branch coverage
88%
Covered branches: 32
Total branches: 36
Branch coverage: 88.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%88100%
get_Mode()100%11100%
get_Keyframes()100%11100%
Evaluate(...)87.5%161695.23%
Equals(...)66.66%66100%
Equals(...)100%22100%
GetHashCode()100%22100%
op_Equality(...)100%22100%
op_Inequality(...)100%11100%

File(s)

/home/runner/work/FixedMathSharp/FixedMathSharp/src/FixedMathSharp/Numerics/FixedCurve.cs

#LineLine coverage
 1using MemoryPack;
 2using System;
 3using System.Linq;
 4using System.Text.Json.Serialization;
 5
 6namespace FixedMathSharp;
 7
 8/// <summary>
 9/// Specifies the interpolation method used when evaluating a <see cref="FixedCurve"/>.
 10/// </summary>
 11public enum FixedCurveMode
 12{
 13    /// <summary>Linear interpolation between keyframes.</summary>
 14    Linear,
 15
 16    /// <summary>Step interpolation, instantly jumping between keyframe values.</summary>
 17    Step,
 18
 19    /// <summary>Smooth interpolation using a cosine function (SmoothStep).</summary>
 20    Smooth,
 21
 22    /// <summary>Cubic interpolation for smoother curves using tangents.</summary>
 23    Cubic
 24}
 25
 26/// <summary>
 27/// A deterministic fixed-point curve that interpolates values between keyframes.
 28/// Used for animations, physics calculations, and procedural data.
 29/// </summary>
 30[Serializable]
 31[MemoryPackable]
 32public partial class FixedCurve : IEquatable<FixedCurve>
 33{
 34    #region Constructors
 35
 36    /// <summary>
 37    /// Initializes a new instance of the <see cref="FixedCurve"/> with a default linear interpolation mode.
 38    /// </summary>
 39    /// <param name="keyframes">The keyframes defining the curve.</param>
 40    public FixedCurve(params FixedCurveKey[] keyframes)
 1541        : this(FixedCurveMode.Linear, keyframes) { }
 42
 43    /// <summary>
 44    /// Initializes a new instance of the <see cref="FixedCurve"/> with a specified interpolation mode.
 45    /// </summary>
 46    /// <param name="mode">The interpolation method to use.</param>
 47    /// <param name="keyframes">The keyframes defining the curve.</param>
 48    [JsonConstructor]
 49    [MemoryPackConstructor]
 2050    public FixedCurve(FixedCurveMode mode, params FixedCurveKey[] keyframes)
 2051    {
 2052        Keyframes = keyframes?.Length > 1
 4153            ? keyframes.OrderBy(k => k.Time).ToArray()
 2054            : keyframes?.Clone() as FixedCurveKey[] ?? Array.Empty<FixedCurveKey>();
 2055        Mode = mode;
 2056    }
 57
 58    #endregion
 59
 60    #region Properties
 61
 62    [JsonInclude]
 63    [MemoryPackOrder(0)]
 4364    public FixedCurveMode Mode { get; private set; }
 65
 66    [JsonInclude]
 67    [MemoryPackOrder(1)]
 17468    public FixedCurveKey[] Keyframes { get; private set; }
 69
 70    #endregion
 71
 72    #region Methods
 73
 74    /// <summary>
 75    /// Evaluates the curve at a given time using the specified interpolation mode.
 76    /// </summary>
 77    /// <param name="time">The time at which to evaluate the curve.</param>
 78    /// <returns>The interpolated value at the given time.</returns>
 79    public Fixed64 Evaluate(Fixed64 time)
 2280    {
 2381        if (Keyframes.Length == 0) return Fixed64.One;
 82
 83        // Clamp input within the keyframe range
 2884        if (time <= Keyframes[0].Time) return Keyframes[0].Value;
 2185        if (time >= Keyframes[^1].Time) return Keyframes[^1].Value;
 86
 87        // Find the surrounding keyframes
 2088        for (int i = 0; i < Keyframes.Length - 1; i++)
 1089        {
 1090            if (time >= Keyframes[i].Time && time < Keyframes[i + 1].Time)
 791            {
 92                // Compute interpolation factor
 793                Fixed64 t = (time - Keyframes[i].Time) / (Keyframes[i + 1].Time - Keyframes[i].Time);
 94
 95                // Choose interpolation method
 796                return Mode switch
 797                {
 398                    FixedCurveMode.Step => Keyframes[i].Value,// Immediate transition
 199                    FixedCurveMode.Smooth => FixedMath.SmoothStep(Keyframes[i].Value, Keyframes[i + 1].Value, t),
 1100                    FixedCurveMode.Cubic => FixedMath.CubicInterpolate(
 1101                                                    Keyframes[i].Value, Keyframes[i + 1].Value,
 1102                                                    Keyframes[i].OutTangent, Keyframes[i + 1].InTangent, t),
 2103                    _ => FixedMath.LinearInterpolate(Keyframes[i].Value, Keyframes[i + 1].Value, t),
 7104                };
 105            }
 3106        }
 107
 0108        return Fixed64.One; // Fallback (should never be hit)
 22109    }
 110
 111    #endregion
 112
 113    #region Equality
 114
 115    public bool Equals(FixedCurve? other)
 8116    {
 10117        if (other is null) return false;
 6118        if (ReferenceEquals(this, other)) return true;
 6119        return Mode == other.Mode && Keyframes.SequenceEqual(other.Keyframes);
 8120    }
 121
 2122    public override bool Equals(object? obj) => obj is FixedCurve other && Equals(other);
 123
 124    public override int GetHashCode()
 2125    {
 126        unchecked
 2127        {
 2128            int hash = (int)Mode;
 14129            foreach (var key in Keyframes)
 4130                hash = (hash * 31) ^ key.GetHashCode();
 2131            return hash;
 132        }
 2133    }
 134
 7135    public static bool operator ==(FixedCurve? left, FixedCurve? right) => left?.Equals(right) ?? right is null;
 136
 2137    public static bool operator !=(FixedCurve? left, FixedCurve? right) => !(left == right);
 138
 139    #endregion
 140}