Source code for pyunity.values.mathf

## Copyright (c) 2020-2022 The PyUnity Team
## This file is licensed under the MIT License.
## See https://docs.pyunity.x10.bz/en/latest/license.html

__all__ = ["Acos", "Asin", "Atan", "Atan2", "Ceil", "Clamp", "Clamp01", "Cos",
           "DEG_TO_RAD", "DeltaAngle", "EPSILON", "Exp", "Floor", "GLM_SUPPORT",
           "INFINITY", "InverseLerp", "Lerp", "LerpUnclamped", "Log",
           "NEG_INFINITY", "PI", "RAD_TO_DEG", "Sign", "Sin", "SmoothDamper",
           "SmoothStep", "Sqrt", "Tan"]

from .. import Logger
import math
import sys
import os

GLM_SUPPORT = True
try:
    import glm
    if glm is math:
        # Wrapper scripts may replace glm with math in sys.modules
        sys.modules.pop("math", "")
        import glm
except ImportError:
    GLM_SUPPORT = False

if GLM_SUPPORT:
    Logger.LogLine(Logger.INFO, "GLM support enabled")
else:
    Logger.LogLine(Logger.INFO,
                   "GLM support disabled; falling back to builtin math")

PI = math.pi
DEG_TO_RAD = PI / 180
RAD_TO_DEG = 180 / PI
INFINITY = math.inf
NEG_INFINITY = -math.inf
EPSILON = sys.float_info.epsilon

def _wraps(orig, glmfunc=None):
    if glmfunc is None:
        glmfunc = orig

    def decorator(func):
        if "PYUNITY_SPHINX_CHECK" in os.environ:
            return func
        if isinstance(orig, str):
            if GLM_SUPPORT:
                return getattr(glm, glmfunc)
            else:
                return getattr(math, orig)
        return orig
    return decorator

[docs]@_wraps("acos") def Acos(num): """ Returns the angle whose cosine is ``num``. Return value is in radians. Parameters ---------- num : float Input number """ pass
[docs]@_wraps("asin") def Asin(num): """ Returns the angle whose sine is ``num``. Return value is in radians. Parameters ---------- num : float Input number """ pass
[docs]@_wraps("atan") def Atan(num): """ Returns the angle whose tangent is ``num``. Return value is in radians. Parameters ---------- num : float Input number """ pass
[docs]@_wraps("atan2", "atan") def Atan2(x, y): """ Returns the two-argument arctangent of ``x/y``. Parameters ---------- x : float Input x y : float Input y """ pass
[docs]@_wraps("ceil") def Ceil(num): """ Returns the smallest integer greater than or equal to ``num``. Parameters ---------- num : float Input number """ pass
[docs]def Clamp(num, a, b): """ Returns ``a`` if ``num`` is smaller than or equal to ``a``, ``b`` if ``num`` is greater than or equal to ``b``, or ``num`` if it is between ``a`` and ``b``. Parameters ---------- num : float Input number a : float Lower bound b : float Upper bound """ return min(max(num, a), b)
[docs]def Clamp01(num): """ Returns ``num`` clamped between 0 and 1. Parameters ---------- num : float Input number """ if num < 0: return 0 if num > 1: return 1 return num
[docs]@_wraps("cos") def Cos(num): """ Returns the cosine of ``num``. Must be passed in radians. Parameters ---------- num : float Input number """ pass
[docs]def DeltaAngle(a, b): """ Calculates the shortest difference between two given angles given in degrees. Parameters ---------- a : float Input a b : float Input b """ return abs(a - b) % 360
[docs]@_wraps("exp") def Exp(num): """ Returns e raised to the power of ``num``. Parameters ---------- num : float Exponent """ pass
[docs]@_wraps("floor") def Floor(num): """ Returns the largest integer smaller than or equal to ``num``. Parameters ---------- num : float Input number """ pass
[docs]def InverseLerp(num, a, b): """ Determines where ``num`` lies between two points ``a`` and ``b``. Parameters ---------- num : float Number to check a : float Lower bound b : float Upper bound """ prop = (num - a) / (b - a) return Clamp01(prop)
[docs]def Lerp(num, a, b): """ Linearly interpolates between ``a`` and ``b`` by ``num``. Parameters ---------- num : float Amount to interpolate by a : float Lower bound b : float Upper bound """ return a + (b - a) * Clamp01(num)
[docs]def LerpUnclamped(num, a, b): """ Linearly interpolates between ``a`` and ``b`` by ``num`` with no limit for ``num``. Parameters ---------- num : float Amount to interpolate by a : float Lower bound b : float Upper bound """ return a + (b - a) * num
[docs]@_wraps("log") def Log(num): """ Returns the base 10 logarithm of ``num``. Parameters ---------- num : float Input number """ pass
[docs]def Sign(num): """ Returns the sign of ``num`` (either -1 or 1, or 0 if ``num`` is 0). Parameters ---------- num : float Input number """ if num == 0: return 0 if num > 0: return 1 return -1
[docs]@_wraps("sin") def Sin(num): """ Returns the sine of ``num``. Must be passed in radians. Parameters ---------- num : float Input number """ pass
[docs]def SmoothStep(num): """ Used in conjunction with :func:`Lerp` to smoothly interpolate between two numbers. This function takes a number between 0 and 1 and returns a number between 0 and 1, which has a steeper graph around 0.5 and a smoother graph near 0 and 1. Parameters ---------- num : float Input number (between 0 and 1) Notes ----- This uses the mathematical equation f(x) = 3x^2 - 2x^3. """ # 3x^2 - 2x^3 return (3 - 2 * num) * num * num
[docs]@_wraps("sqrt") def Sqrt(num): """ Returns the square root of ``num``. Parameters ---------- num : float Input number """ pass
[docs]@_wraps("tan") def Tan(num): """ Returns the tangent of ``num``. Must be passed in radians. Parameters ---------- num : float Input number """ pass
[docs]class SmoothDamper: def __init__(self, maxSpeed=INFINITY): self.velocity = 0.0 self.maxSpeed = maxSpeed
[docs] def SmoothDamp(self, current, target, smoothTime, dt): smoothTime = max(0.0001, smoothTime) omega = 2 / smoothTime x = omega * dt exp = 1 / (1 + x + 0.48 * x * x + 0.235 * x * x * x) change = current - target originalTo = target maxChange = self.maxSpeed * smoothTime change = Clamp(change, -maxChange, maxChange) target = current - change temp = (self.velocity + omega * change) * dt self.velocity = (self.velocity - omega * temp) * exp output = target + (change + temp) * exp if (originalTo - current > 0.0) == (output > originalTo): output = originalTo self.velocity = (output - originalTo) / dt return output
[docs] def reset(self): self.velocity = 0.0