import math from typing import Any, Callable, Mapping DEFAULT_FLOAT = ("FLOAT", {"default": 0.0}) FLOAT_UNARY_OPERATIONS: Mapping[str, Callable[[float], float]] = { "Neg": lambda a: -a, "Inc": lambda a: a + 1, "Dec": lambda a: a - 1, "Abs": lambda a: abs(a), "Sqr": lambda a: a * a, "Cube": lambda a: a * a * a, "Sqrt": lambda a: math.sqrt(a), "Exp": lambda a: math.exp(a), "Ln": lambda a: math.log(a), "Log10": lambda a: math.log10(a), "Log2": lambda a: math.log2(a), "Sin": lambda a: math.sin(a), "Cos": lambda a: math.cos(a), "Tan": lambda a: math.tan(a), "Asin": lambda a: math.asin(a), "Acos": lambda a: math.acos(a), "Atan": lambda a: math.atan(a), "Sinh": lambda a: math.sinh(a), "Cosh": lambda a: math.cosh(a), "Tanh": lambda a: math.tanh(a), "Asinh": lambda a: math.asinh(a), "Acosh": lambda a: math.acosh(a), "Atanh": lambda a: math.atanh(a), "Round": lambda a: round(a), "Floor": lambda a: math.floor(a), "Ceil": lambda a: math.ceil(a), "Trunc": lambda a: math.trunc(a), "Erf": lambda a: math.erf(a), "Erfc": lambda a: math.erfc(a), "Gamma": lambda a: math.gamma(a), "Radians": lambda a: math.radians(a), "Degrees": lambda a: math.degrees(a), } FLOAT_UNARY_CONDITIONS: Mapping[str, Callable[[float], bool]] = { "IsZero": lambda a: a == 0.0, "IsPositive": lambda a: a > 0.0, "IsNegative": lambda a: a < 0.0, "IsNonZero": lambda a: a != 0.0, "IsPositiveInfinity": lambda a: math.isinf(a) and a > 0.0, "IsNegativeInfinity": lambda a: math.isinf(a) and a < 0.0, "IsNaN": lambda a: math.isnan(a), "IsFinite": lambda a: math.isfinite(a), "IsInfinite": lambda a: math.isinf(a), "IsEven": lambda a: a % 2 == 0.0, "IsOdd": lambda a: a % 2 != 0.0, } FLOAT_BINARY_OPERATIONS: Mapping[str, Callable[[float, float], float]] = { "Add": lambda a, b: a + b, "Sub": lambda a, b: a - b, "Mul": lambda a, b: a * b, "Div": lambda a, b: a / b, "Mod": lambda a, b: a % b, "Pow": lambda a, b: a**b, "FloorDiv": lambda a, b: a // b, "Max": lambda a, b: max(a, b), "Min": lambda a, b: min(a, b), "Log": lambda a, b: math.log(a, b), "Atan2": lambda a, b: math.atan2(a, b), } FLOAT_BINARY_CONDITIONS: Mapping[str, Callable[[float, float], bool]] = { "Eq": lambda a, b: a == b, "Neq": lambda a, b: a != b, "Gt": lambda a, b: a > b, "Gte": lambda a, b: a >= b, "Lt": lambda a, b: a < b, "Lte": lambda a, b: a <= b, } class FloatUnaryOperation: @classmethod def INPUT_TYPES(cls) -> Mapping[str, Any]: return { "required": { "op": (list(FLOAT_UNARY_OPERATIONS.keys()),), "a": DEFAULT_FLOAT, } } RETURN_TYPES = ("FLOAT",) FUNCTION = "op" CATEGORY = "math/float" def op(self, op: str, a: float) -> tuple[float]: return (FLOAT_UNARY_OPERATIONS[op](a),) class FloatUnaryCondition: @classmethod def INPUT_TYPES(cls) -> Mapping[str, Any]: return { "required": { "op": (list(FLOAT_UNARY_CONDITIONS.keys()),), "a": DEFAULT_FLOAT, } } RETURN_TYPES = ("BOOL",) FUNCTION = "op" CATEGORY = "math/float" def op(self, op: str, a: float) -> tuple[bool]: return (FLOAT_UNARY_CONDITIONS[op](a),) class FloatBinaryOperation: @classmethod def INPUT_TYPES(cls) -> Mapping[str, Any]: return { "required": { "op": (list(FLOAT_BINARY_OPERATIONS.keys()),), "a": DEFAULT_FLOAT, "b": DEFAULT_FLOAT, } } RETURN_TYPES = ("FLOAT",) FUNCTION = "op" CATEGORY = "math/float" def op(self, op: str, a: float, b: float) -> tuple[float]: return (FLOAT_BINARY_OPERATIONS[op](a, b),) class FloatBinaryCondition: @classmethod def INPUT_TYPES(cls) -> Mapping[str, Any]: return { "required": { "op": (list(FLOAT_BINARY_CONDITIONS.keys()),), "a": DEFAULT_FLOAT, "b": DEFAULT_FLOAT, } } RETURN_TYPES = ("BOOL",) FUNCTION = "op" CATEGORY = "math/float" def op(self, op: str, a: float, b: float) -> tuple[bool]: return (FLOAT_BINARY_CONDITIONS[op](a, b),) NODE_CLASS_MAPPINGS = { "CM_FloatUnaryOperation": FloatUnaryOperation, "CM_FloatUnaryCondition": FloatUnaryCondition, "CM_FloatBinaryOperation": FloatBinaryOperation, "CM_FloatBinaryCondition": FloatBinaryCondition, }