using System; using System.Collections.Generic; namespace Luneraria.Core { /// /// Scalar helpers with the exact semantics of the GDScript built-ins the rules used /// (clampf, maxf, minf, roundf, floori, ceili, is_equal_approx). Doubles throughout. /// public static class GdMath { public const double CmpEpsilon = 0.00001; public static double Clamp(double value, double low, double high) { return value < low ? low : (value > high ? high : value); } public static int Clamp(int value, int low, int high) { return value < low ? low : (value > high ? high : value); } /// Godot's MAX macro: (a > b) ? a : b. public static double Max(double a, double b) { return a > b ? a : b; } /// Godot's MIN macro: (a < b) ? a : b. public static double Min(double a, double b) { return a < b ? a : b; } public static int Max(int a, int b) { return a > b ? a : b; } public static int Min(int a, int b) { return a < b ? a : b; } public static int FloorI(double value) { return (int)Math.Floor(value); } public static int CeilI(double value) { return (int)Math.Ceiling(value); } /// roundf: half away from zero (C round), not banker's rounding. public static double Round(double value) { return Math.Round(value, MidpointRounding.AwayFromZero); } public static bool IsEqualApprox(double a, double b) { if (a == b) return true; double tolerance = CmpEpsilon * Math.Abs(a); if (tolerance < CmpEpsilon) tolerance = CmpEpsilon; return Math.Abs(a - b) < tolerance; } /// GDScript atan2(y, x) on doubles. public static double Atan2(double y, double x) { return Math.Atan2(y, x); } /// /// Stable insertion sort with a "less than" predicate. Every comparator of the rules is /// a strict order on distinct unit ids or sequence numbers, so the result is unique; /// stability keeps it deterministic even for near ties. /// public static void SortStable(List list, Func less) { for (int i = 1; i < list.Count; i++) { T item = list[i]; int j = i - 1; while (j >= 0 && less(item, list[j])) { list[j + 1] = list[j]; j--; } list[j + 1] = item; } } } }