linear curve
Some checks are pending
Python Linting / Run Ruff (push) Waiting to run
Python Linting / Run Pylint (push) Waiting to run

This commit is contained in:
Terry Jia 2026-03-16 14:42:28 -04:00
parent 62d9a99b8c
commit 57fc06ad6b
4 changed files with 51 additions and 6 deletions

View File

@ -7,6 +7,7 @@ from comfy_api.latest._input import (
VideoInput,
CurveInput,
MonotoneCubicCurve,
LinearCurve,
)
__all__ = [
@ -17,4 +18,5 @@ __all__ = [
"VideoInput",
"CurveInput",
"MonotoneCubicCurve",
"LinearCurve",
]

View File

@ -1,4 +1,4 @@
from .basic_types import ImageInput, AudioInput, MaskInput, LatentInput, CurveInput, MonotoneCubicCurve
from .basic_types import ImageInput, AudioInput, MaskInput, LatentInput, CurveInput, MonotoneCubicCurve, LinearCurve
from .video_types import VideoInput
__all__ = [
@ -9,4 +9,5 @@ __all__ = [
"LatentInput",
"CurveInput",
"MonotoneCubicCurve",
"LinearCurve",
]

View File

@ -170,9 +170,9 @@ class MonotoneCubicCurve(CurveInput):
xs, ys, slopes = self._xs, self._ys, self._slopes
n = len(xs)
if n == 0:
return np.zeros_like(xs_in)
return np.zeros_like(xs_in, dtype=np.float64)
if n == 1:
return np.full_like(xs_in, ys[0])
return np.full_like(xs_in, ys[0], dtype=np.float64)
hi = np.searchsorted(xs, xs_in, side='right').clip(1, n - 1)
lo = hi - 1
@ -195,3 +195,40 @@ class MonotoneCubicCurve(CurveInput):
def __repr__(self) -> str:
return f"MonotoneCubicCurve(points={self._points})"
class LinearCurve(CurveInput):
"""Piecewise linear interpolation over control points.
Mirrors the frontend ``createLinearInterpolator`` in
``ComfyUI_frontend/src/components/curve/curveUtils.ts``.
"""
def __init__(self, control_points: list[CurvePoint]):
sorted_pts = sorted(control_points, key=lambda p: p[0])
self._points = [(float(x), float(y)) for x, y in sorted_pts]
self._xs = np.array([p[0] for p in self._points], dtype=np.float64)
self._ys = np.array([p[1] for p in self._points], dtype=np.float64)
@property
def points(self) -> list[CurvePoint]:
return list(self._points)
def interp(self, x: float) -> float:
xs, ys = self._xs, self._ys
n = len(xs)
if n == 0:
return 0.0
if n == 1:
return float(ys[0])
return float(np.interp(x, xs, ys))
def interp_array(self, xs_in: np.ndarray) -> np.ndarray:
if len(self._xs) == 0:
return np.zeros_like(xs_in, dtype=np.float64)
if len(self._xs) == 1:
return np.full_like(xs_in, self._ys[0], dtype=np.float64)
return np.interp(xs_in, self._xs, self._ys)
def __repr__(self) -> str:
return f"LinearCurve(points={self._points})"

View File

@ -2039,7 +2039,7 @@ class CurveEditor:
def INPUT_TYPES(s):
return {
"required": {
"curve": ("CURVE", {"default": [[0, 0], [1, 1]]}),
"curve": ("CURVE", {"default": {"points": [[0, 0], [1, 1]], "interpolation": "monotone_cubic"}}),
}
}
@ -2049,10 +2049,15 @@ class CurveEditor:
CATEGORY = "utils"
def execute(self, curve):
from comfy_api.input import CurveInput, MonotoneCubicCurve
from comfy_api.input import CurveInput, MonotoneCubicCurve, LinearCurve
if isinstance(curve, CurveInput):
return (curve,)
return (MonotoneCubicCurve([(float(x), float(y)) for x, y in curve]),)
raw_points = curve["points"] if isinstance(curve, dict) else curve
points = [(float(x), float(y)) for x, y in raw_points]
interpolation = curve.get("interpolation", "monotone_cubic") if isinstance(curve, dict) else "monotone_cubic"
if interpolation == "linear":
return (LinearCurve(points),)
return (MonotoneCubicCurve(points),)
NODE_CLASS_MAPPINGS = {