55 lines
1.6 KiB
Python
55 lines
1.6 KiB
Python
from __future__ import annotations
|
|
|
|
import numpy as np
|
|
|
|
from backend.node_registry import register_node
|
|
from backend.data_types import DataField
|
|
|
|
|
|
@register_node(display_name="Gradient")
|
|
class Gradient:
|
|
@classmethod
|
|
def INPUT_TYPES(cls):
|
|
return {
|
|
"required": {
|
|
"field": ("DATA_FIELD",),
|
|
"component": (["magnitude", "x", "y", "azimuth"],),
|
|
}
|
|
}
|
|
|
|
OUTPUTS = (
|
|
('DATA_FIELD', 'gradient'),
|
|
)
|
|
FUNCTION = "process"
|
|
|
|
DESCRIPTION = (
|
|
"Compute the spatial gradient using a Sobel operator. "
|
|
"'x'/'y' give the physical gradient components (z_unit/xy_unit); "
|
|
"'magnitude' gives sqrt(gx²+gy²); "
|
|
"'azimuth' gives the local slope direction in radians via atan2(gy, gx). "
|
|
)
|
|
|
|
KEYWORDS = ("sobel", "slope", "derivative", "azimuth")
|
|
|
|
def process(self, field: DataField, component: str) -> tuple:
|
|
from backend.nodes.surface_common import physical_sobel_gradient, slope_unit
|
|
|
|
gx, gy = physical_sobel_gradient(field)
|
|
|
|
if component == "magnitude":
|
|
result = np.hypot(gx, gy)
|
|
out_unit_z = slope_unit(field)
|
|
elif component == "x":
|
|
result = gx
|
|
out_unit_z = slope_unit(field)
|
|
elif component == "y":
|
|
result = gy
|
|
out_unit_z = slope_unit(field)
|
|
elif component == "azimuth":
|
|
result = np.arctan2(gy, gx)
|
|
out_unit_z = "rad"
|
|
else:
|
|
raise ValueError(f"Unknown gradient component: {component!r}")
|
|
|
|
return (field.replace(data=result, si_unit_z=out_unit_z),)
|