using System; using System.Runtime.CompilerServices; namespace RGB.NET.Core; /// /// Offers some extensions and helper-methods for the work with floats. /// public static class FloatExtensions { #region Constants /// /// Defines the precision RGB.NET processes floating point comparisons in. /// public const float TOLERANCE = 1E-7f; #endregion #region Methods /// /// Checks if two values are equal respecting the . /// /// The first value to compare. /// The first value to compare. /// true if the difference is smaller than the ; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool EqualsInTolerance(this float value1, float value2) => Math.Abs(value1 - value2) < TOLERANCE; /// /// Clamps the provided value to be bigger or equal min and smaller or equal max. /// /// The value to clamp. /// The lower value of the range the value is clamped to. /// The higher value of the range the value is clamped to. /// The clamped value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Clamp(this float value, float min, float max) { // ReSharper disable ConvertIfStatementToReturnStatement - I'm not sure why, but inlining this statement reduces performance by ~10% if (value < min) return min; if (value > max) return max; return value; // ReSharper restore ConvertIfStatementToReturnStatement } /// /// Clamps the provided value to be bigger or equal min and smaller or equal max. /// /// The value to clamp. /// The lower value of the range the value is clamped to. /// The higher value of the range the value is clamped to. /// The clamped value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Clamp(this int value, int min, int max) { // ReSharper disable ConvertIfStatementToReturnStatement - I'm not sure why, but inlining this statement reduces performance by ~10% if (value < min) return min; if (value > max) return max; return value; // ReSharper restore ConvertIfStatementToReturnStatement } /// /// Enforces the provided value to be in the specified range by wrapping it around the edges if it exceeds them. /// /// The value to wrap. /// The lower value of the range the value is wrapped into. /// The higher value of the range the value is wrapped into. /// The wrapped value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Wrap(this float value, float min, float max) { float range = max - min; while (value >= max) value -= range; while (value < min) value += range; return value; } /// /// Converts a normalized float value in the range [0..1] to a byte [0..255]. /// /// The normalized float value to convert. /// The byte value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte GetByteValueFromPercentage(this float percentage) { if (float.IsNaN(percentage)) return 0; percentage = percentage.Clamp(0, 1.0f); return (byte)(percentage >= 1.0f ? 255 : percentage * 256.0f); } /// /// Converts a byte value [0..255] to a normalized float value in the range [0..1]. /// /// The byte value to convert. /// The normalized float value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetPercentageFromByteValue(this byte value) => value == 255 ? 1.0f : (value / 256.0f); #endregion }