using SPTarkov.DI.Annotations; namespace SPTarkov.Server.Core.Utils; [Injectable(InjectionType.Singleton)] public class MathUtil { /// /// Helper to create the sum of all list elements /// /// List of floats to sum /// sum of all values public double ListSum(List values) { // Sum the list starting with an initial value of 0 return values.Sum(); } public float ListSum(List values) { // Sum the list starting with an initial value of 0 return values.Sum(); } /// /// Helper to create the cumulative sum of all list elements /// ListCumSum([1, 2, 3, 4]) = [1, 3, 6, 10] /// /// The list with numbers of which to calculate the cumulative sum /// cumulative sum of values public List ListCumSum(List values) { if (values.Count == 0) { return []; } var cumSumArray = new double[values.Count]; cumSumArray[0] = values[0]; for (var i = 1; i < values.Count; i++) { cumSumArray[i] = cumSumArray[i - 1] + values[i]; } return [..cumSumArray]; } /// /// Helper to create the product of each element times factor /// /// The list of numbers which shall be multiplied by the factor /// Number to multiply each element by /// A list of elements all multiplied by the factor public List ListProduct(List values, double factor) { return values.Select(v => v * factor).ToList(); } /// /// Helper to add a constant to all list elements /// /// The list of numbers to which the summand should be added /// /// A list of elements with the additive added to all elements public List ListAdd(List values, double additive) { return values.Select(v => v + additive).ToList(); } /// /// Maps a value from an input range to an output range linearly. /// Example: /// a_min = 0; a_max=1; /// b_min = 1; b_max=3; /// MapToRange(0.5, a_min, a_max, b_min, b_max) // returns 2 /// /// The value from the input range to be mapped to the output range. /// Minimum of the input range. /// Maximum of the input range. /// Minimum of the output range. /// Maximum of the output range. /// The result of the mapping. public double MapToRange(double x, double minIn, double maxIn, double minOut, double maxOut) { var deltaIn = maxIn - minIn; var deltaOut = maxOut - minOut; var xScale = (x - minIn) / deltaIn; return Math.Max(minOut, Math.Min(maxOut, minOut + xScale * deltaOut)); } /// /// Linear interpolation /// e.g. used to do a continuous integration for quest rewards which are defined for specific support centers of pmcLevel /// /// The point of x at which to interpolate /// Support points in x (of same length as y) /// Support points in y (of same length as x) /// Interpolated value at xp, or null if xp is out of bounds public double? Interp1(double xp, List x, List y) { if (xp > x[^1]) // ^1 is the last index in C# { return y[^1]; } if (xp < x[0]) { return y[0]; } for (var i = 0; i < x.Count - 1; i++) { if (xp >= x[i] && xp <= x[i + 1]) { return y[i] + (xp - x[i]) * (y[i + 1] - y[i]) / (x[i + 1] - x[i]); } } return null; } }