angle node working nicely

This commit is contained in:
2026-03-27 22:51:29 -07:00
parent 3752e1c733
commit ab71688e01
6 changed files with 66 additions and 61 deletions

View File

@@ -504,7 +504,17 @@ def _render_overlay_text(
@lru_cache(maxsize=1)
def _overlay_font_candidates() -> tuple[str, ...]:
candidates: list[str] = []
candidates: list[str] = [
"/System/Library/Fonts/HelveticaNeue.ttc",
"/System/Library/Fonts/Helvetica.ttc",
"/System/Library/Fonts/Supplemental/Arial.ttf",
"/System/Library/Fonts/Supplemental/Helvetica.ttc",
"/System/Library/Fonts/Supplemental/Times New Roman.ttf",
"/Library/Fonts/Arial.ttf",
"/Library/Fonts/Helvetica.ttc",
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/truetype/liberation2/LiberationSans-Regular.ttf",
]
try:
import PIL
@@ -517,16 +527,6 @@ def _overlay_font_candidates() -> tuple[str, ...]:
except Exception:
pass
candidates.extend([
"/System/Library/Fonts/Supplemental/Arial.ttf",
"/System/Library/Fonts/Supplemental/Helvetica.ttc",
"/System/Library/Fonts/Supplemental/Times New Roman.ttf",
"/Library/Fonts/Arial.ttf",
"/Library/Fonts/Helvetica.ttc",
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/truetype/liberation2/LiberationSans-Regular.ttf",
])
unique: list[str] = []
for candidate in candidates:
if candidate not in unique and Path(candidate).exists():
@@ -891,7 +891,7 @@ def _angle_label_base_position(spec: dict[str, Any]) -> tuple[float, float]:
)
def _sanitize_angle_overlay_thickness(value: Any, default: float = 1.35) -> float:
def _sanitize_angle_overlay_stroke_width(value: Any, default: float = 1.35) -> float:
try:
numeric = float(value)
except (TypeError, ValueError):
@@ -983,14 +983,14 @@ def _apply_angle_measure_overlay(image: np.ndarray, field: DataField | None, spe
label_dy = float(spec.get("label_dy", 0.0) or 0.0)
angle_deg = float(spec.get("angle_deg", 0.0) or 0.0)
color_hex = _sanitize_angle_overlay_color(spec.get("color", "#ff0000"))
line_thickness = _sanitize_angle_overlay_thickness(spec.get("line_thickness", 1.35))
stroke_width = _sanitize_angle_overlay_stroke_width(spec.get("stroke_width", spec.get("line_thickness", 1.35)))
base_rgb = _hex_to_rgb(color_hex)
arc_rgb = _mix_rgb(base_rgb, (255, 255, 255), 0.42)
badge_text_rgb = _mix_rgb(base_rgb, (255, 255, 255), 0.72)
badge_border_rgb = _mix_rgb(base_rgb, (255, 255, 255), 0.32)
line_width = max(1, int(round(longest_dim * line_thickness / 100.0)))
arc_width = max(1, int(round(longest_dim * max(0.85, line_thickness * 0.78) / 100.0)))
line_width = max(1, int(round(longest_dim * stroke_width / 100.0)))
arc_width = line_width
line_color = (*base_rgb, 255)
arc_color = (*arc_rgb, 242)
@@ -1034,6 +1034,7 @@ def _apply_angle_measure_overlay(image: np.ndarray, field: DataField | None, spe
label_text,
max(10, int(round(longest_dim / 26.0))),
badge_text_rgb,
font_spec={"family": "Helvetica Neue"},
)
bg_pad_x = max(5, int(round(text_image.size[0] * 0.16)))

View File

@@ -16,12 +16,14 @@ from backend.execution_context import emit_overlay, emit_table
from backend.node_registry import register_node
from backend.nodes.helpers import _normalize_markup_color
ANGLE_DEFAULT_COLOR = "#ff9800"
def _clamp01(value: float) -> float:
return float(np.clip(value, 0.0, 1.0))
def _sanitize_line_thickness(value: float | None, default: float = 1.35) -> float:
def _sanitize_stroke_width(value: float | None, default: float = 1.35) -> float:
try:
numeric = float(value)
except (TypeError, ValueError):
@@ -56,7 +58,7 @@ def _angle_overlay_spec(
angle_deg: float,
label_dx: float,
label_dy: float,
line_thickness: float,
stroke_width: float,
color: str,
) -> dict[str, float | str]:
return {
@@ -70,7 +72,7 @@ def _angle_overlay_spec(
"angle_deg": float(angle_deg),
"label_dx": float(label_dx),
"label_dy": float(label_dy),
"line_thickness": float(line_thickness),
"stroke_width": float(stroke_width),
"color": str(color),
}
@@ -84,14 +86,13 @@ class AngleMeasure:
return {
"required": {
"input": ("ANNOTATION_SOURCE", {"label": "Input"}),
"color": ("STRING", {"default": "#ff0000", "color_picker": True}),
"line_thickness": ("FLOAT", {
"color": ("STRING", {"default": ANGLE_DEFAULT_COLOR, "color_picker": True}),
"stroke_width": ("FLOAT", {
"default": 1.35,
"min": 0.35,
"max": 6.0,
"step": 0.05,
"label": "line thickness",
"hide_when_input_connected": "line_thickness_input",
"label": "stroke width",
}),
"x1": ("FLOAT", {"default": 0.22, "min": 0.0, "max": 1.0, "step": 0.01, "hidden": True}),
"y1": ("FLOAT", {"default": 0.72, "min": 0.0, "max": 1.0, "step": 0.01, "hidden": True}),
@@ -103,7 +104,8 @@ class AngleMeasure:
"label_dy": ("FLOAT", {"default": 0.0, "min": -1.0, "max": 1.0, "step": 0.01, "hidden": True}),
},
"optional": {
"line_thickness_input": ("FLOAT", {"label": "line thickness"}),
"line_thickness": ("FLOAT", {"hidden": True}),
"line_thickness_input": ("FLOAT", {"hidden": True}),
},
}
@@ -114,15 +116,15 @@ class AngleMeasure:
DESCRIPTION = (
"Measure the included angle between two draggable line segments over a DATA_FIELD or IMAGE. "
"Drag either endpoint to change that arm, drag the middle joint to move the whole widget, "
"drag the angle label to reposition it, choose the overlay color, and adjust line thickness "
"with the widget or a FLOAT input."
"drag the angle label to reposition it, choose the overlay color, and adjust stroke width "
"with the widget or its FLOAT socket."
)
def process(
self,
input,
color: str,
line_thickness: float,
stroke_width: float,
x1: float,
y1: float,
xm: float,
@@ -131,6 +133,7 @@ class AngleMeasure:
y2: float,
label_dx: float,
label_dy: float,
line_thickness: float | None = None,
line_thickness_input: float | None = None,
) -> tuple:
x1 = _clamp01(x1)
@@ -141,9 +144,10 @@ class AngleMeasure:
y2 = _clamp01(y2)
label_dx = float(np.clip(label_dx, -1.0, 1.0))
label_dy = float(np.clip(label_dy, -1.0, 1.0))
resolved_color = _normalize_markup_color(color, default="#ff0000")
resolved_line_thickness = _sanitize_line_thickness(
line_thickness_input if line_thickness_input is not None else line_thickness,
resolved_color = _normalize_markup_color(color, default=ANGLE_DEFAULT_COLOR)
legacy_stroke_width = line_thickness_input if line_thickness_input is not None else line_thickness
resolved_stroke_width = _sanitize_stroke_width(
legacy_stroke_width if legacy_stroke_width is not None else stroke_width,
)
if isinstance(input, DataField):
@@ -177,7 +181,7 @@ class AngleMeasure:
angle_deg=angle_deg,
label_dx=label_dx,
label_dy=label_dy,
line_thickness=resolved_line_thickness,
stroke_width=resolved_stroke_width,
color=resolved_color,
)
table = MeasureTable([