567 lines
17 KiB
Python
567 lines
17 KiB
Python
import math
|
|
from inspect import cleandoc
|
|
from typing import Literal, Union
|
|
|
|
try:
|
|
from comfy.comfy_types.node_typing import IO, ComfyNodeABC
|
|
except:
|
|
class IO:
|
|
BOOLEAN = "BOOLEAN"
|
|
INT = "INT"
|
|
FLOAT = "FLOAT"
|
|
STRING = "STRING"
|
|
NUMBER = "FLOAT,INT"
|
|
ANY = "*"
|
|
ComfyNodeABC = object
|
|
|
|
class MathAbs(ComfyNodeABC):
|
|
"""
|
|
Returns the absolute value of a number.
|
|
|
|
This node takes a number and returns its absolute value (magnitude without sign).
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"value": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, value: Union[float, int, str]) -> tuple[Union[float, int]]:
|
|
return (abs(float(value)),)
|
|
|
|
|
|
class MathAcos(ComfyNodeABC):
|
|
"""
|
|
Calculates the arc cosine (inverse cosine) of a value.
|
|
|
|
This node takes a value between -1 and 1, and returns the arc cosine in radians or degrees.
|
|
The arc cosine is the inverse operation of cosine, returning the angle whose cosine is the input value.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"value": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
"unit": (["radians", "degrees"], {"default": "degrees"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, value: Union[float, int, str], unit: Literal["radians", "degrees"]) -> tuple[float]:
|
|
result = math.acos(float(value))
|
|
if unit == "degrees":
|
|
result = math.degrees(result)
|
|
return (result,)
|
|
|
|
|
|
class MathAsin(ComfyNodeABC):
|
|
"""
|
|
Calculates the arc sine (inverse sine) of a value.
|
|
|
|
This node takes a value between -1 and 1, and returns the arc sine in radians or degrees.
|
|
The arc sine is the inverse operation of sine, returning the angle whose sine is the input value.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"value": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
"unit": (["radians", "degrees"], {"default": "degrees"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, value: Union[float, int, str], unit: Literal["radians", "degrees"]) -> tuple[float]:
|
|
result = math.asin(float(value))
|
|
if unit == "degrees":
|
|
result = math.degrees(result)
|
|
return (result,)
|
|
|
|
|
|
class MathAtan(ComfyNodeABC):
|
|
"""
|
|
Calculates the arc tangent (inverse tangent) of a value.
|
|
|
|
This node takes a value and returns the arc tangent in radians or degrees.
|
|
The arc tangent is the inverse operation of tangent, returning the angle whose tangent is the input value.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"value": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
"unit": (["radians", "degrees"], {"default": "degrees"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, value: Union[float, int, str], unit: Literal["radians", "degrees"]) -> tuple[float]:
|
|
result = math.atan(float(value))
|
|
if unit == "degrees":
|
|
result = math.degrees(result)
|
|
return (result,)
|
|
|
|
|
|
class MathAtan2(ComfyNodeABC):
|
|
"""
|
|
Calculates the arc tangent of y/x, considering the quadrant.
|
|
|
|
This node takes y and x coordinates and returns the arc tangent in radians or degrees.
|
|
Unlike atan(y/x), this function handles the case where x is zero and correctly determines
|
|
the quadrant of the resulting angle.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"y": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
"x": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
"unit": (["radians", "degrees"], {"default": "degrees"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, y: Union[float, int, str], x: Union[float, int, str], unit: Literal["radians", "degrees"]) -> tuple[float]:
|
|
result = math.atan2(float(y), float(x))
|
|
if unit == "degrees":
|
|
result = math.degrees(result)
|
|
return (result,)
|
|
|
|
|
|
class MathCeil(ComfyNodeABC):
|
|
"""
|
|
Returns the ceiling of a number.
|
|
|
|
This node takes a number and returns the smallest integer greater than or equal to the input value.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"value": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.INT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, value: Union[float, int, str]) -> tuple[int]:
|
|
return (math.ceil(float(value)),)
|
|
|
|
|
|
class MathCos(ComfyNodeABC):
|
|
"""
|
|
Calculates the cosine of an angle in radians or degrees.
|
|
|
|
This node takes an angle value and unit type, and returns the cosine of that angle.
|
|
The cosine of an angle is the ratio of the length of the adjacent side to the length
|
|
of the hypotenuse in a right-angled triangle.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"angle": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
"unit": (["radians", "degrees"], {"default": "degrees"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, angle: Union[float, int, str], unit: Literal["radians", "degrees"]) -> tuple[float]:
|
|
if unit == "degrees":
|
|
# Convert degrees to radians
|
|
angle = math.radians(float(angle))
|
|
return (math.cos(float(angle)),)
|
|
|
|
|
|
class MathDegrees(ComfyNodeABC):
|
|
"""
|
|
Converts an angle from radians to degrees.
|
|
|
|
This node takes an angle in radians and returns the equivalent angle in degrees.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"radians": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, radians: Union[float, int, str]) -> tuple[float]:
|
|
return (math.degrees(float(radians)),)
|
|
|
|
|
|
class MathE(ComfyNodeABC):
|
|
"""
|
|
Returns the mathematical constant e.
|
|
|
|
This node returns the value of e (Euler's number), which is approximately 2.71828.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {"required": {}}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self) -> tuple[float]:
|
|
return (math.e,)
|
|
|
|
|
|
class MathExp(ComfyNodeABC):
|
|
"""
|
|
Calculates the exponential of a number (e^x).
|
|
|
|
This node takes a number and returns e (Euler's number) raised to the power of that number.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"value": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, value: Union[float, int, str]) -> tuple[float]:
|
|
return (math.exp(float(value)),)
|
|
|
|
|
|
class MathFloor(ComfyNodeABC):
|
|
"""
|
|
Returns the floor of a number.
|
|
|
|
This node takes a number and returns the largest integer less than or equal to the input value.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"value": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.INT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, value: Union[float, int, str]) -> tuple[int]:
|
|
return (math.floor(float(value)),)
|
|
|
|
|
|
class MathLog(ComfyNodeABC):
|
|
"""
|
|
Calculates the natural logarithm (base e) of a number.
|
|
|
|
This node takes a positive number and returns its natural logarithm.
|
|
If the specified base is not 'e', calculates the logarithm with the specified base.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"value": (IO.NUMBER, {"default": 1.0, "min": 0.0000001, "widgetType": "STRING"}),
|
|
},
|
|
"optional": {
|
|
"base": (IO.NUMBER, {"default": math.e, "min": 0.0000001, "widgetType": "STRING"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, value: Union[float, int, str], base: Union[float, int, str] = math.e) -> tuple[float]:
|
|
return (math.log(float(value), float(base)),)
|
|
|
|
|
|
class MathLog10(ComfyNodeABC):
|
|
"""
|
|
Calculates the base-10 logarithm of a number.
|
|
|
|
This node takes a positive number and returns its base-10 logarithm.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"value": (IO.NUMBER, {"default": 1.0, "min": 0.0000001, "widgetType": "STRING"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, value: Union[float, int, str]) -> tuple[float]:
|
|
return (math.log10(float(value)),)
|
|
|
|
|
|
class MathMax(ComfyNodeABC):
|
|
"""
|
|
Returns the maximum value among the inputs.
|
|
|
|
This node takes two or more values and returns the maximum value among them.
|
|
The function works with both FLOAT and INT types.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"value1": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
"value2": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("*",)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, value1: Union[float, int, str], value2: Union[float, int, str]) -> tuple[Union[float, int]]:
|
|
return (max(float(value1), float(value2)),)
|
|
|
|
|
|
class MathMin(ComfyNodeABC):
|
|
"""
|
|
Returns the minimum value among the inputs.
|
|
|
|
This node takes two or more values and returns the minimum value among them.
|
|
The function works with both FLOAT and INT types.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"value1": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
"value2": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("*",)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, value1: Union[float, int, str], value2: Union[float, int, str]) -> tuple[Union[float, int]]:
|
|
return (min(float(value1), float(value2)),)
|
|
|
|
|
|
class MathPi(ComfyNodeABC):
|
|
"""
|
|
Returns the mathematical constant π (pi).
|
|
|
|
This node returns the value of π, which is approximately 3.14159.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {"required": {}}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self) -> tuple[float]:
|
|
return (math.pi,)
|
|
|
|
|
|
class MathRadians(ComfyNodeABC):
|
|
"""
|
|
Converts an angle from degrees to radians.
|
|
|
|
This node takes an angle in degrees and returns the equivalent angle in radians.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"degrees": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, degrees: Union[float, int, str]) -> tuple[float]:
|
|
return (math.radians(float(degrees)),)
|
|
|
|
|
|
class MathSin(ComfyNodeABC):
|
|
"""
|
|
Calculates the sine of an angle in radians or degrees.
|
|
|
|
This node takes an angle value and unit type, and returns the sine of that angle.
|
|
The sine of an angle is the ratio of the length of the opposite side to the length
|
|
of the hypotenuse in a right-angled triangle.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"angle": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
"unit": (["radians", "degrees"], {"default": "degrees"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, angle: Union[float, int, str], unit: Literal["radians", "degrees"]) -> tuple[float]:
|
|
if unit == "degrees":
|
|
# Convert degrees to radians
|
|
angle = math.radians(float(angle))
|
|
return (math.sin(float(angle)),)
|
|
|
|
|
|
class MathSqrt(ComfyNodeABC):
|
|
"""
|
|
Calculates the square root of a non-negative number.
|
|
|
|
This node takes a non-negative number and returns its square root.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"value": (IO.NUMBER, {"default": 0.0, "min": 0.0, "widgetType": "STRING"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, value: Union[float, int, str]) -> tuple[float]:
|
|
return (math.sqrt(float(value)),)
|
|
|
|
|
|
class MathTan(ComfyNodeABC):
|
|
"""
|
|
Calculates the tangent of an angle in radians or degrees.
|
|
|
|
This node takes an angle value and unit type, and returns the tangent of that angle.
|
|
The tangent of an angle is the ratio of the length of the opposite side to the length
|
|
of the adjacent side in a right-angled triangle.
|
|
"""
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"angle": (IO.NUMBER, {"default": 0.0, "widgetType": "STRING"}),
|
|
"unit": (["radians", "degrees"], {"default": "degrees"}),
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = (IO.FLOAT,)
|
|
CATEGORY = "Basic/maths"
|
|
DESCRIPTION = cleandoc(__doc__ or "")
|
|
FUNCTION = "calculate"
|
|
|
|
def calculate(self, angle: Union[float, int, str], unit: Literal["radians", "degrees"]) -> tuple[float]:
|
|
if unit == "degrees":
|
|
# Convert degrees to radians
|
|
angle = math.radians(float(angle))
|
|
|
|
# Handle specific angles that would result in division by zero
|
|
if abs(math.cos(float(angle))) < 1e-10:
|
|
raise ValueError("Tangent is undefined at this angle (division by zero)")
|
|
|
|
return (math.tan(float(angle)),)
|
|
|
|
|
|
NODE_CLASS_MAPPINGS = {
|
|
"Basic data handling: MathAbs": MathAbs,
|
|
"Basic data handling: MathAcos": MathAcos,
|
|
"Basic data handling: MathAsin": MathAsin,
|
|
"Basic data handling: MathAtan": MathAtan,
|
|
"Basic data handling: MathAtan2": MathAtan2,
|
|
"Basic data handling: MathCeil": MathCeil,
|
|
"Basic data handling: MathCos": MathCos,
|
|
"Basic data handling: MathDegrees": MathDegrees,
|
|
"Basic data handling: MathE": MathE,
|
|
"Basic data handling: MathExp": MathExp,
|
|
"Basic data handling: MathFloor": MathFloor,
|
|
"Basic data handling: MathLog": MathLog,
|
|
"Basic data handling: MathLog10": MathLog10,
|
|
"Basic data handling: MathMax": MathMax,
|
|
"Basic data handling: MathMin": MathMin,
|
|
"Basic data handling: MathPi": MathPi,
|
|
"Basic data handling: MathRadians": MathRadians,
|
|
"Basic data handling: MathSin": MathSin,
|
|
"Basic data handling: MathSqrt": MathSqrt,
|
|
"Basic data handling: MathTan": MathTan,
|
|
}
|
|
|
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
"Basic data handling: MathAbs": "abs",
|
|
"Basic data handling: MathAcos": "acos",
|
|
"Basic data handling: MathAsin": "asin",
|
|
"Basic data handling: MathAtan": "atan",
|
|
"Basic data handling: MathAtan2": "atan2",
|
|
"Basic data handling: MathCeil": "ceil",
|
|
"Basic data handling: MathCos": "cos",
|
|
"Basic data handling: MathDegrees": "degrees",
|
|
"Basic data handling: MathE": "e (2.71828)",
|
|
"Basic data handling: MathExp": "exp",
|
|
"Basic data handling: MathFloor": "floor",
|
|
"Basic data handling: MathLog": "log",
|
|
"Basic data handling: MathLog10": "log10",
|
|
"Basic data handling: MathMax": "max",
|
|
"Basic data handling: MathMin": "min",
|
|
"Basic data handling: MathPi": "pi (3.14159)",
|
|
"Basic data handling: MathRadians": "radians",
|
|
"Basic data handling: MathSin": "sin",
|
|
"Basic data handling: MathSqrt": "sqrt",
|
|
"Basic data handling: MathTan": "tan",
|
|
}
|