// MIT License - Copyright (C) The Mono.Xna Team // This file is subject to the terms and conditions defined in // file 'LICENSE.txt', which is part of this source code package. using System; namespace CommonLang.Geometry { /// /// Contains commonly used precalculated values and mathematical operations. /// public static class MathHelper { /// /// Represents the mathematical constant e(2.71828175). /// public const float E = (float)Math.E; /// /// Represents the log base ten of e(0.4342945). /// public const float Log10E = 0.4342945f; /// /// Represents the log base two of e(1.442695). /// public const float Log2E = 1.442695f; /// /// Represents the value of pi(3.14159274). /// public const float Pi = (float)Math.PI; /// /// Represents the value of pi divided by two(1.57079637). /// public const float PiOver2 = (float)(Math.PI / 2.0); /// /// Represents the value of pi divided by four(0.7853982). /// public const float PiOver4 = (float)(Math.PI / 4.0); /// /// Represents the value of pi times two(6.28318548). /// public const float TwoPi = (float)(Math.PI * 2.0); /// /// Returns the Cartesian coordinate for one axis of a point that is defined by a given triangle and two normalized barycentric (areal) coordinates. /// /// The coordinate on one axis of vertex 1 of the defining triangle. /// The coordinate on the same axis of vertex 2 of the defining triangle. /// The coordinate on the same axis of vertex 3 of the defining triangle. /// The normalized barycentric (areal) coordinate b2, equal to the weighting factor for vertex 2, the coordinate of which is specified in value2. /// The normalized barycentric (areal) coordinate b3, equal to the weighting factor for vertex 3, the coordinate of which is specified in value3. /// Cartesian coordinate of the specified point with respect to the axis being used. public static float Barycentric(float value1, float value2, float value3, float amount1, float amount2) { return value1 + (value2 - value1) * amount1 + (value3 - value1) * amount2; } /// /// Performs a Catmull-Rom interpolation using the specified positions. /// /// The first position in the interpolation. /// The second position in the interpolation. /// The third position in the interpolation. /// The fourth position in the interpolation. /// Weighting factor. /// A position that is the result of the Catmull-Rom interpolation. public static float CatmullRom(float value1, float value2, float value3, float value4, float amount) { // Using formula from http://www.mvps.org/directx/articles/catmull/ // Internally using doubles not to lose precission double amountSquared = amount * amount; double amountCubed = amountSquared * amount; return (float)(0.5 * (2.0 * value2 + (value3 - value1) * amount + (2.0 * value1 - 5.0 * value2 + 4.0 * value3 - value4) * amountSquared + (3.0 * value2 - value1 - 3.0 * value3 + value4) * amountCubed)); } /// /// Restricts a value to be within a specified range. /// /// The value to clamp. /// The minimum value. If value is less than min, min will be returned. /// The maximum value. If value is greater than max, max will be returned. /// The clamped value. public static float Clamp(float value, float min, float max) { // First we check to see if we're greater than the max value = (value > max) ? max : value; // Then we check to see if we're less than the min. value = (value < min) ? min : value; // There's no check to see if min > max. return value; } /// /// Restricts a value to be within a specified range. /// /// The value to clamp. /// The minimum value. If value is less than min, min will be returned. /// The maximum value. If value is greater than max, max will be returned. /// The clamped value. public static int Clamp(int value, int min, int max) { value = (value > max) ? max : value; value = (value < min) ? min : value; return value; } /// /// Calculates the absolute value of the difference of two values. /// /// Source value. /// Source value. /// Distance between the two values. public static float Distance(float value1, float value2) { return Math.Abs(value1 - value2); } /// /// Performs a Hermite spline interpolation. /// /// Source position. /// Source tangent. /// Source position. /// Source tangent. /// Weighting factor. /// The result of the Hermite spline interpolation. public static float Hermite(float value1, float tangent1, float value2, float tangent2, float amount) { // All transformed to double not to lose precission // Otherwise, for high numbers of param:amount the result is NaN instead of Infinity double v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount, result; double sCubed = s * s * s; double sSquared = s * s; if (amount == 0f) result = value1; else if (amount == 1f) result = value2; else result = (2 * v1 - 2 * v2 + t2 + t1) * sCubed + (3 * v2 - 3 * v1 - 2 * t1 - t2) * sSquared + t1 * s + v1; return (float)result; } /// /// Linearly interpolates between two values. /// /// Source value. /// Source value. /// Value between 0 and 1 indicating the weight of value2. /// Interpolated value. /// This method performs the linear interpolation based on the following formula. /// value1 + (value2 - value1) * amount /// Passing amount a value of 0 will cause value1 to be returned, a value of 1 will cause value2 to be returned. /// public static float Lerp(float value1, float value2, float amount) { return value1 + (value2 - value1) * amount; } /// /// Returns the greater of two values. /// /// Source value. /// Source value. /// The greater value. public static float Max(float value1, float value2) { return value1 > value2 ? value1 : value2; } /// /// Returns the greater of two values. /// /// Source value. /// Source value. /// The greater value. public static int Max(int value1, int value2) { return value1 > value2 ? value1 : value2; } /// /// Returns the lesser of two values. /// /// Source value. /// Source value. /// The lesser value. public static float Min(float value1, float value2) { return value1 < value2 ? value1 : value2; } /// /// Returns the lesser of two values. /// /// Source value. /// Source value. /// The lesser value. public static int Min(int value1, int value2) { return value1 < value2 ? value1 : value2; } /// /// Interpolates between two values using a cubic equation. /// /// Source value. /// Source value. /// Weighting value. /// Interpolated value. public static float SmoothStep(float value1, float value2, float amount) { // It is expected that 0 < amount < 1 // If amount < 0, return value1 // If amount > 1, return value2 float result = MathHelper.Clamp(amount, 0f, 1f); result = MathHelper.Hermite(value1, 0f, value2, 0f, result); return result; } /// /// Converts radians to degrees. /// /// The angle in radians. /// The angle in degrees. /// /// This method uses double precission internally, /// though it returns single float /// Factor = 180 / pi /// public static float ToDegrees(float radians) { return (float)(radians * 57.295779513082320876798154814105); } /// /// Converts degrees to radians. /// /// The angle in degrees. /// The angle in radians. /// /// This method uses double precission internally, /// though it returns single float /// Factor = pi / 180 /// public static float ToRadians(float degrees) { return (float)(degrees * 0.017453292519943295769236907684886); } /// /// Reduces a given angle to a value between π and -π. /// /// The angle to reduce, in radians. /// The new angle, in radians. public static float WrapAngle(float angle) { angle = (float)Math.IEEERemainder((double)angle, 6.2831854820251465); if (angle <= -3.14159274f) { angle += 6.28318548f; } else { if (angle > 3.14159274f) { angle -= 6.28318548f; } } return angle; } /// /// Determines if value is powered by two. /// /// A value. /// true if value is powered by two; otherwise false. public static bool IsPowerOfTwo(int value) { return (value > 0) && ((value & (value - 1)) == 0); } } }