#region License
/* FNA - XNA4 Reimplementation for Desktop Platforms
* Copyright 2009-2016 Ethan Lee and the MonoGame Team
*
* Released under the Microsoft Public License.
* See LICENSE for details.
*/
/* Derived from code by the Mono.Xna Team (Copyright 2006).
* Released under the MIT License. See monoxna.LICENSE for details.
*/
#endregion
#region Using Statements
using System;
#endregion
namespace Microsoft.Xna.Framework
{
///
/// Contains commonly used precalculated values and mathematical operations.
///
public static class MathHelper
{
#region Public Constants
///
/// 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);
#endregion
#region Internal Static Readonly Fields
internal static readonly float MachineEpsilonFloat = GetMachineEpsilonFloat();
#endregion
#region Public Static Methods
///
/// 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 precision.
*/
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;
}
///
/// 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 precision
* 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;
double result;
double sCubed = s * s * s;
double sSquared = s * s;
if (WithinEpsilon(amount, 0f))
{
result = value1;
}
else if (WithinEpsilon(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 lesser of two values.
///
/// Source value.
/// Source value.
/// The lesser value.
public static float Min(float value1, float 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 precision 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 precision 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 pi and -pi.
///
/// 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;
}
#endregion
#region Internal Static Methods
// FIXME: This could be an extension! ClampIntEXT? -flibit
///
/// 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.
internal static int Clamp(int value, int min, int max)
{
value = (value > max) ? max : value;
value = (value < min) ? min : value;
return value;
}
internal static bool WithinEpsilon(float floatA, float floatB)
{
return Math.Abs(floatA - floatB) < MachineEpsilonFloat;
}
internal static int ClosestMSAAPower(int value)
{
/* Checking for the highest power of two _after_ than the given int:
* http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
* Take result, divide by 2, get the highest power of two _before_!
* -flibit
*/
if (value == 1)
{
// ... Except for 1, which is invalid for MSAA -flibit
return 0;
}
int result = value - 1;
result |= result >> 1;
result |= result >> 2;
result |= result >> 4;
result |= result >> 8;
result |= result >> 16;
result += 1;
if (result == value)
{
return result;
}
return result >> 1;
}
#endregion
#region Private Static Methods
///
/// Find the current machine's Epsilon for the float data type.
/// (That is, the largest float, e, where e == 0.0f is true.)
///
private static float GetMachineEpsilonFloat()
{
float machineEpsilon = 1.0f;
float comparison;
/* Keep halving the working value of machineEpsilon until we get a number that
* when added to 1.0f will still evaluate as equal to 1.0f.
*/
do
{
machineEpsilon *= 0.5f;
comparison = 1.0f + machineEpsilon;
}
while (comparison > 1.0f);
return machineEpsilon;
}
#endregion
}
}