#if REAL_T_IS_DOUBLE using real_t = System.Double; #else using real_t = System.Single; #endif using System; namespace Godot { public static partial class Mathf { // Define constants with Decimal precision and cast down to double or float. /// /// The circle constant, the circumference of the unit circle in radians. /// // 6.2831855f and 6.28318530717959 public const real_t Tau = (real_t)6.2831853071795864769252867666M; /// /// Constant that represents how many times the diameter of a circle /// fits around its perimeter. This is equivalent to `Mathf.Tau / 2`. /// // 3.1415927f and 3.14159265358979 public const real_t Pi = (real_t)3.1415926535897932384626433833M; /// /// Positive infinity. For negative infinity, use `-Mathf.Inf`. /// public const real_t Inf = real_t.PositiveInfinity; /// /// "Not a Number", an invalid value. `NaN` has special properties, including /// that it is not equal to itself. It is output by some invalid operations, /// such as dividing zero by zero. /// public const real_t NaN = real_t.NaN; // 0.0174532924f and 0.0174532925199433 private const real_t Deg2RadConst = (real_t)0.0174532925199432957692369077M; // 57.29578f and 57.2957795130823 private const real_t Rad2DegConst = (real_t)57.295779513082320876798154814M; /// /// Returns the absolute value of `s` (i.e. positive value). /// /// The input number. /// The absolute value of `s`. public static int Abs(int s) { return Math.Abs(s); } /// /// Returns the absolute value of `s` (i.e. positive value). /// /// The input number. /// The absolute value of `s`. public static real_t Abs(real_t s) { return Math.Abs(s); } /// /// Returns the arc cosine of `s` in radians. Use to get the angle of cosine s. /// /// The input cosine value. Must be on the range of -1.0 to 1.0. /// An angle that would result in the given cosine value. On the range `0` to `Tau/2`. public static real_t Acos(real_t s) { return (real_t)Math.Acos(s); } /// /// Returns the arc sine of `s` in radians. Use to get the angle of sine s. /// /// The input sine value. Must be on the range of -1.0 to 1.0. /// An angle that would result in the given sine value. On the range `-Tau/4` to `Tau/4`. public static real_t Asin(real_t s) { return (real_t)Math.Asin(s); } /// /// Returns the arc tangent of `s` in radians. Use to get the angle of tangent s. /// /// The method cannot know in which quadrant the angle should fall. /// See if you have both `y` and `x`. /// /// The input tangent value. /// An angle that would result in the given tangent value. On the range `-Tau/4` to `Tau/4`. public static real_t Atan(real_t s) { return (real_t)Math.Atan(s); } /// /// Returns the arc tangent of `y` and `x` in radians. Use to get the angle /// of the tangent of `y/x`. To compute the value, the method takes into /// account the sign of both arguments in order to determine the quadrant. /// /// Important note: The Y coordinate comes first, by convention. /// /// The Y coordinate of the point to find the angle to. /// The X coordinate of the point to find the angle to. /// An angle that would result in the given tangent value. On the range `-Tau/2` to `Tau/2`. public static real_t Atan2(real_t y, real_t x) { return (real_t)Math.Atan2(y, x); } /// /// Converts a 2D point expressed in the cartesian coordinate /// system (X and Y axis) to the polar coordinate system /// (a distance from the origin and an angle). /// /// The input X coordinate. /// The input Y coordinate. /// A with X representing the distance and Y representing the angle. public static Vector2 Cartesian2Polar(real_t x, real_t y) { return new Vector2(Sqrt(x * x + y * y), Atan2(y, x)); } /// /// Rounds `s` upward (towards positive infinity). /// /// The number to ceil. /// The smallest whole number that is not less than `s`. public static real_t Ceil(real_t s) { return (real_t)Math.Ceiling(s); } /// /// Clamps a `value` so that it is not less than `min` and not more than `max`. /// /// The value to clamp. /// The minimum allowed value. /// The maximum allowed value. /// The clamped value. public static int Clamp(int value, int min, int max) { return value < min ? min : value > max ? max : value; } /// /// Clamps a `value` so that it is not less than `min` and not more than `max`. /// /// The value to clamp. /// The minimum allowed value. /// The maximum allowed value. /// The clamped value. public static real_t Clamp(real_t value, real_t min, real_t max) { return value < min ? min : value > max ? max : value; } /// /// Returns the cosine of angle `s` in radians. /// /// The angle in radians. /// The cosine of that angle. public static real_t Cos(real_t s) { return (real_t)Math.Cos(s); } /// /// Returns the hyperbolic cosine of angle `s` in radians. /// /// The angle in radians. /// The hyperbolic cosine of that angle. public static real_t Cosh(real_t s) { return (real_t)Math.Cosh(s); } /// /// Converts an angle expressed in degrees to radians. /// /// An angle expressed in degrees. /// The same angle expressed in radians. public static real_t Deg2Rad(real_t deg) { return deg * Deg2RadConst; } /// /// Easing function, based on exponent. The curve values are: /// `0` is constant, `1` is linear, `0` to `1` is ease-in, `1` or more is ease-out. /// Negative values are in-out/out-in. /// /// The value to ease. /// `0` is constant, `1` is linear, `0` to `1` is ease-in, `1` or more is ease-out. /// The eased value. public static real_t Ease(real_t s, real_t curve) { if (s < 0f) { s = 0f; } else if (s > 1.0f) { s = 1.0f; } if (curve > 0f) { if (curve < 1.0f) { return 1.0f - Pow(1.0f - s, 1.0f / curve); } return Pow(s, curve); } if (curve < 0f) { if (s < 0.5f) { return Pow(s * 2.0f, -curve) * 0.5f; } return (1.0f - Pow(1.0f - (s - 0.5f) * 2.0f, -curve)) * 0.5f + 0.5f; } return 0f; } /// /// The natural exponential function. It raises the mathematical /// constant `e` to the power of `s` and returns it. /// /// The exponent to raise `e` to. /// `e` raised to the power of `s`. public static real_t Exp(real_t s) { return (real_t)Math.Exp(s); } /// /// Rounds `s` downward (towards negative infinity). /// /// The number to floor. /// The largest whole number that is not more than `s`. public static real_t Floor(real_t s) { return (real_t)Math.Floor(s); } /// /// Returns a normalized value considering the given range. /// This is the opposite of . /// /// The interpolated value. /// The destination value for interpolation. /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. /// The resulting value of the inverse interpolation. public static real_t InverseLerp(real_t from, real_t to, real_t weight) { return (weight - from) / (to - from); } /// /// Returns true if `a` and `b` are approximately equal to each other. /// The comparison is done using a tolerance calculation with . /// /// One of the values. /// The other value. /// A bool for whether or not the two values are approximately equal. public static bool IsEqualApprox(real_t a, real_t b) { // Check for exact equality first, required to handle "infinity" values. if (a == b) { return true; } // Then check for approximate equality. real_t tolerance = Epsilon * Abs(a); if (tolerance < Epsilon) { tolerance = Epsilon; } return Abs(a - b) < tolerance; } /// /// Returns whether `s` is an infinity value (either positive infinity or negative infinity). /// /// The value to check. /// A bool for whether or not the value is an infinity value. public static bool IsInf(real_t s) { return real_t.IsInfinity(s); } /// /// Returns whether `s` is a `NaN` ("Not a Number" or invalid) value. /// /// The value to check. /// A bool for whether or not the value is a `NaN` value. public static bool IsNaN(real_t s) { return real_t.IsNaN(s); } /// /// Returns true if `s` is approximately zero. /// The comparison is done using a tolerance calculation with . /// /// This method is faster than using with one value as zero. /// /// The value to check. /// A bool for whether or not the value is nearly zero. public static bool IsZeroApprox(real_t s) { return Abs(s) < Epsilon; } /// /// Linearly interpolates between two values by a normalized value. /// This is the opposite . /// /// The start value for interpolation. /// The destination value for interpolation. /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. /// The resulting value of the interpolation. public static real_t Lerp(real_t from, real_t to, real_t weight) { return from + (to - from) * weight; } /// /// Linearly interpolates between two angles (in radians) by a normalized value. /// /// Similar to , /// but interpolates correctly when the angles wrap around . /// /// The start angle for interpolation. /// The destination angle for interpolation. /// A value on the range of 0.0 to 1.0, representing the amount of interpolation. /// The resulting angle of the interpolation. public static real_t LerpAngle(real_t from, real_t to, real_t weight) { real_t difference = (to - from) % Mathf.Tau; real_t distance = ((2 * difference) % Mathf.Tau) - difference; return from + distance * weight; } /// /// Natural logarithm. The amount of time needed to reach a certain level of continuous growth. /// /// Note: This is not the same as the "log" function on most calculators, which uses a base 10 logarithm. /// /// The input value. /// The natural log of `s`. public static real_t Log(real_t s) { return (real_t)Math.Log(s); } /// /// Returns the maximum of two values. /// /// One of the values. /// The other value. /// Whichever of the two values is higher. public static int Max(int a, int b) { return a > b ? a : b; } /// /// Returns the maximum of two values. /// /// One of the values. /// The other value. /// Whichever of the two values is higher. public static real_t Max(real_t a, real_t b) { return a > b ? a : b; } /// /// Returns the minimum of two values. /// /// One of the values. /// The other value. /// Whichever of the two values is lower. public static int Min(int a, int b) { return a < b ? a : b; } /// /// Returns the minimum of two values. /// /// One of the values. /// The other value. /// Whichever of the two values is lower. public static real_t Min(real_t a, real_t b) { return a < b ? a : b; } /// /// Moves `from` toward `to` by the `delta` value. /// /// Use a negative delta value to move away. /// /// The start value. /// The value to move towards. /// The amount to move by. /// The value after moving. public static real_t MoveToward(real_t from, real_t to, real_t delta) { return Abs(to - from) <= delta ? to : from + Sign(to - from) * delta; } /// /// Returns the nearest larger power of 2 for the integer `value`. /// /// The input value. /// The nearest larger power of 2. public static int NearestPo2(int value) { value--; value |= value >> 1; value |= value >> 2; value |= value >> 4; value |= value >> 8; value |= value >> 16; value++; return value; } /// /// Converts a 2D point expressed in the polar coordinate /// system (a distance from the origin `r` and an angle `th`) /// to the cartesian coordinate system (X and Y axis). /// /// The distance from the origin. /// The angle of the point. /// A representing the cartesian coordinate. public static Vector2 Polar2Cartesian(real_t r, real_t th) { return new Vector2(r * Cos(th), r * Sin(th)); } /// /// Performs a canonical Modulus operation, where the output is on the range `[0, b)`. /// /// The dividend, the primary input. /// The divisor. The output is on the range `[0, b)`. /// The resulting output. public static int PosMod(int a, int b) { int c = a % b; if ((c < 0 && b > 0) || (c > 0 && b < 0)) { c += b; } return c; } /// /// Performs a canonical Modulus operation, where the output is on the range `[0, b)`. /// /// The dividend, the primary input. /// The divisor. The output is on the range `[0, b)`. /// The resulting output. public static real_t PosMod(real_t a, real_t b) { real_t c = a % b; if ((c < 0 && b > 0) || (c > 0 && b < 0)) { c += b; } return c; } /// /// Returns the result of `x` raised to the power of `y`. /// /// The base. /// The exponent. /// `x` raised to the power of `y`. public static real_t Pow(real_t x, real_t y) { return (real_t)Math.Pow(x, y); } /// /// Converts an angle expressed in radians to degrees. /// /// An angle expressed in radians. /// The same angle expressed in degrees. public static real_t Rad2Deg(real_t rad) { return rad * Rad2DegConst; } /// /// Rounds `s` to the nearest whole number, /// with halfway cases rounded towards the nearest multiple of two. /// /// The number to round. /// The rounded number. public static real_t Round(real_t s) { return (real_t)Math.Round(s); } /// /// Returns the sign of `s`: `-1` or `1`. Returns `0` if `s` is `0`. /// /// The input number. /// One of three possible values: `1`, `-1`, or `0`. public static int Sign(int s) { if (s == 0) return 0; return s < 0 ? -1 : 1; } /// /// Returns the sign of `s`: `-1` or `1`. Returns `0` if `s` is `0`. /// /// The input number. /// One of three possible values: `1`, `-1`, or `0`. public static int Sign(real_t s) { if (s == 0) return 0; return s < 0 ? -1 : 1; } /// /// Returns the sine of angle `s` in radians. /// /// The angle in radians. /// The sine of that angle. public static real_t Sin(real_t s) { return (real_t)Math.Sin(s); } /// /// Returns the hyperbolic sine of angle `s` in radians. /// /// The angle in radians. /// The hyperbolic sine of that angle. public static real_t Sinh(real_t s) { return (real_t)Math.Sinh(s); } /// /// Returns a number smoothly interpolated between `from` and `to`, /// based on the `weight`. Similar to , /// but interpolates faster at the beginning and slower at the end. /// /// The start value for interpolation. /// The destination value for interpolation. /// A value representing the amount of interpolation. /// The resulting value of the interpolation. public static real_t SmoothStep(real_t from, real_t to, real_t weight) { if (IsEqualApprox(from, to)) { return from; } real_t x = Clamp((weight - from) / (to - from), (real_t)0.0, (real_t)1.0); return x * x * (3 - 2 * x); } /// /// Returns the square root of `s`, where `s` is a non-negative number. /// /// If you need negative inputs, use `System.Numerics.Complex`. /// /// The input number. Must not be negative. /// The square root of `s`. public static real_t Sqrt(real_t s) { return (real_t)Math.Sqrt(s); } /// /// Returns the position of the first non-zero digit, after the /// decimal point. Note that the maximum return value is 10, /// which is a design decision in the implementation. /// /// The input value. /// The position of the first non-zero digit. public static int StepDecimals(real_t step) { double[] sd = new double[] { 0.9999, 0.09999, 0.009999, 0.0009999, 0.00009999, 0.000009999, 0.0000009999, 0.00000009999, 0.000000009999, }; double abs = Mathf.Abs(step); double decs = abs - (int)abs; // Strip away integer part for (int i = 0; i < sd.Length; i++) { if (decs >= sd[i]) { return i; } } return 0; } /// /// Snaps float value `s` to a given `step`. /// This can also be used to round a floating point /// number to an arbitrary number of decimals. /// /// The value to snap. /// The step size to snap to. /// public static real_t Snapped(real_t s, real_t step) { if (step != 0f) { return Floor(s / step + 0.5f) * step; } return s; } /// /// Returns the tangent of angle `s` in radians. /// /// The angle in radians. /// The tangent of that angle. public static real_t Tan(real_t s) { return (real_t)Math.Tan(s); } /// /// Returns the hyperbolic tangent of angle `s` in radians. /// /// The angle in radians. /// The hyperbolic tangent of that angle. public static real_t Tanh(real_t s) { return (real_t)Math.Tanh(s); } /// /// Wraps `value` between `min` and `max`. Usable for creating loop-alike /// behavior or infinite surfaces. If `min` is `0`, this is equivalent /// to , so prefer using that instead. /// /// The value to wrap. /// The minimum allowed value and lower bound of the range. /// The maximum allowed value and upper bound of the range. /// The wrapped value. public static int Wrap(int value, int min, int max) { int range = max - min; return range == 0 ? min : min + ((value - min) % range + range) % range; } /// /// Wraps `value` between `min` and `max`. Usable for creating loop-alike /// behavior or infinite surfaces. If `min` is `0`, this is equivalent /// to , so prefer using that instead. /// /// The value to wrap. /// The minimum allowed value and lower bound of the range. /// The maximum allowed value and upper bound of the range. /// The wrapped value. public static real_t Wrap(real_t value, real_t min, real_t max) { real_t range = max - min; return IsZeroApprox(range) ? min : min + ((value - min) % range + range) % range; } } }