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; } } }