using System; using System.Collections.Generic; using System.Linq; using ICD.Common.Utils.Collections; using ICD.Common.Utils.Extensions; namespace ICD.Common.Utils { /// /// Utility methods for math operations. /// public static class MathUtils { /// /// Clamps the number between the two values. /// /// /// /// /// public static int Clamp(int number, int min, int max) { return (int)Clamp((double)number, min, max); } /// /// Clamps the number between the two values. /// /// /// /// /// public static ushort Clamp(ushort number, ushort min, ushort max) { return (ushort)Clamp((double)number, min, max); } /// /// Clamps the number between the two values. /// /// /// /// /// public static float Clamp(float number, float min, float max) { return (float)Clamp((double)number, min, max); } /// /// Clamps the number between the two values. /// /// /// /// /// public static double Clamp(double number, double min, double max) { return min < max ? Math.Min(Math.Max(number, min), max) : Math.Min(Math.Max(number, max), min); } /// /// Returns the value after the input range has been mapped to a new range /// /// Input start. /// Input end. /// Output start. /// Output end. /// Value. /// The newly mapped value public static double MapRange(double inputStart, double inputEnd, double outputStart, double outputEnd, double value) { double slope = (outputEnd - outputStart) / (inputEnd - inputStart); return outputStart + slope * (value - inputStart); } /// /// Returns the value after the input range has been mapped to a new range /// /// Input start. /// Input end. /// Output start. /// Output end. /// Value. /// The newly mapped value public static float MapRange(float inputStart, float inputEnd, float outputStart, float outputEnd, float value) { return (float)MapRange((double)inputStart, inputEnd, outputStart, outputEnd, value); } /// /// Returns the value after the input range has been mapped to a new range /// /// Input start. /// Input end. /// Output start. /// Output end. /// Value. /// The newly mapped value public static int MapRange(int inputStart, int inputEnd, int outputStart, int outputEnd, int value) { return (int)MapRange((double)inputStart, inputEnd, outputStart, outputEnd, value); } /// /// Returns the value after the input range has been mapped to a new range /// /// Input start. /// Input end. /// Output start. /// Output end. /// Value. /// The newly mapped value public static ushort MapRange(ushort inputStart, ushort inputEnd, ushort outputStart, ushort outputEnd, ushort value) { return (ushort)MapRange((double)inputStart, inputEnd, outputStart, outputEnd, value); } /// /// Maps the date in the given range to the float range 0.0f to 1.0f. /// 0.5f - The date is half way between the end points. /// less than 0.0f - the date is before the start. /// greater than 1.0f - the date is after the end. /// /// /// /// /// public static double MapRange(DateTime start, DateTime end, DateTime value) { return MapRange(new TimeSpan(start.Ticks).TotalSeconds, new TimeSpan(end.Ticks).TotalSeconds, 0.0f, 1.0f, new TimeSpan(value.Ticks).TotalSeconds); } /// /// Gets the digit count for the given number. /// /// /// public static int GetNumberOfDigits(int number) { int output = number.ToString().Length; if (number < 0) output--; return output; } /// /// Gets the digit count for the given number. /// /// /// public static int GetNumberOfDigits(uint number) { return number.ToString().Length; } /// /// Takes a sequence of numbers: /// 1, 3, 5, 6, 7, 8, 9, 10, 12 /// And calculates the continuous ranges: /// (1, 1), (3, 3), (5, 10), (12, 12) /// public static IEnumerable GetRanges(IEnumerable numbers) { if (numbers == null) throw new ArgumentNullException("numbers"); int[] currentRange = null; foreach (int number in numbers.Order()) { if (currentRange == null) currentRange = new[] {number, number}; else if (currentRange[1] == number - 1) currentRange = new[] {currentRange[0], number}; else { yield return currentRange; currentRange = new[] {number, number}; } } if (currentRange != null) yield return currentRange; } /// /// Rounds the given number to the nearest item in the given sequence. /// /// /// /// public static int RoundToNearest(int number, IEnumerable nearest) { if (nearest == null) throw new ArgumentNullException("nearest"); return nearest.Aggregate((x, y) => Math.Abs(x - number) < Math.Abs(y - number) ? x : y); } /// /// Gets a new, unique id given a sequence of existing ids. /// /// /// public static int GetNewId(IEnumerable existingIds) { if (existingIds == null) throw new ArgumentNullException("existingIds"); IcdHashSet existing = existingIds.ToHashSet(); return Enumerable.Range(1, int.MaxValue).First(i => !existing.Contains(i)); } } }