using System;
using System.Runtime.CompilerServices;
using UnityEngine;
namespace Unity.XR.CoreUtils
{
///
/// Math utilities.
///
public static class MathUtility
{
// constants used in approximate equality checks
internal static readonly float EpsilonScaled = Mathf.Epsilon * 8;
///
/// A faster replacement for .
///
///
/// Compares two floating point values and returns true if they are similar.
/// As an optimization, this method does not take into account the magnitude of the values it is comparing.
/// This method may not provide the same results as `Mathf.Approximately` for extremely large values.
///
/// The first float to compare.
/// The second float to compare.
/// if the values are similar. Otherwise, .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool Approximately(float a, float b)
{
var d = b - a;
var absDiff = d >= 0f ? d : -d;
return absDiff < EpsilonScaled;
}
///
/// A slightly faster way to do `Approximately(a, 0f)`.
///
/// The floating point value to compare with 0.
/// if the value is comparable to zero. Otherwise, .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool ApproximatelyZero(float a)
{
return (a >= 0f ? a : -a) < EpsilonScaled;
}
///
/// Constrains a value between a minimum and a maximum.
///
/// The input number.
/// The minimum output.
/// The maximum output.
/// The number, clamped between and (inclusive).
public static double Clamp(double input, double min, double max)
{
if (input > max)
return max;
return input < min ? min : input;
}
///
/// Finds the smallest angle between two angles.
///
/// The start value.
/// The end value.
/// Half of the max angle.
/// The max angle value.
/// The angle distance between start and end.
public static double ShortestAngleDistance(double start, double end, double halfMax, double max)
{
var angleDelta = end - start;
var angleSign = Math.Sign(angleDelta);
angleDelta = Math.Abs(angleDelta) % max;
if (angleDelta > halfMax)
angleDelta = -(max - angleDelta);
return angleDelta * angleSign;
}
///
/// Finds the smallest angle between two angles.
///
/// The start value.
/// The end value.
/// Half of the max angle.
/// The max angle value.
/// The angle distance between start and end.
public static float ShortestAngleDistance(float start, float end, float halfMax, float max)
{
var angleDelta = end - start;
var angleSign = Mathf.Sign(angleDelta);
angleDelta = Math.Abs(angleDelta) % max;
if (angleDelta > halfMax)
angleDelta = -(max - angleDelta);
return angleDelta * angleSign;
}
///
/// Checks whether a value is undefined (,
/// , or ).
///
///
///
/// The float value.
/// True if the value is infinity or NaN (not a number), otherwise false.
public static bool IsUndefined(this float value)
{
return float.IsInfinity(value) || float.IsNaN(value);
}
///
/// Checks if a vector is aligned with one of the axis vectors.
///
/// The vector.
/// True if the vector is aligned with any axis, otherwise false.
public static bool IsAxisAligned(this Vector3 v)
{
return ApproximatelyZero(v.x * v.y) && ApproximatelyZero(v.y * v.z) && ApproximatelyZero(v.z * v.x);
}
///
/// Checks if a value is a positive power of two.
///
/// The value to check.
/// True if the value is a positive power of two, false otherwise.
public static bool IsPositivePowerOfTwo(int value)
{
return value > 0 && (value & (value - 1)) == 0;
}
///
/// Returns the index of the first true bit of a flag.
///
/// The flags value to check.
/// The index of the first active flag.
public static int FirstActiveFlagIndex(int value)
{
if (value == 0)
return 0;
const int bits = sizeof(int) * 8;
for (var i = 0; i < bits; i++)
if ((value & 1 << i) != 0)
return i;
return 0;
}
}
}