nodeslicer/core/nodeslicer/nodes/path/seam_placement.py
2026-10-15 14:13:39 +03:00

58 lines
2.1 KiB
Python

from typing import Any
from ...bpy_ns_types import NfEnumProperty, NfBoolProperty, notify_tree_changed
from .....registry import register_class
from ..base import SliceNode, SlicePaths
@register_class
class SLICENODE_SeamPlacement(SliceNode):
bl_label = "Seam Placement"
list_socket_mapping = [("Paths", "Paths")]
mode: str = NfEnumProperty(
name="Mode",
items=[
('CLOSEST', "Closest to Seam", "Reposition seam to intersection nearest to existing seam"),
('FIRST', "First Intersection", "Reposition seam to first intersection along path traversal"),
('CENTROID', "Mesh Centroid", "Reposition seam to intersection nearest to mesh center"),
],
default='CLOSEST',
update=notify_tree_changed
)
acquire_transforms: bool = NfBoolProperty(
name="Acquire Transforms",
description="Apply transforms from paths metadata to the cutting mesh so they line up as in the viewport",
default=True,
update=notify_tree_changed
)
def init(self, context):
self.add_input("SLICESOCK_Paths")
self.add_input("SLICESOCK_Mesh")
self.add_input("NodeSocketFloat", "Seam Staggering").value = 0.0
self.add_output("SLICESOCK_Paths")
def draw_buttons(self, context, layout):
assert layout
layout.prop(self, "mode", text="")
layout.prop(self, "acquire_transforms")
def evaluate_output(self, socket_name: str, **_kwargs) -> Any:
acquire_t = bool(getattr(self, "acquire_transforms", True))
def _place(p: Any, m_in: Any, stg: Any) -> SlicePaths:
if not p:
return SlicePaths()
s_val = float(stg if stg is not None else 0.0)
if not m_in and abs(s_val) < 1e-6:
return p
return p.place_seams(m_in, mode=self.mode.lower(), acquire_transforms=acquire_t, stagger_mm=s_val)
return self.eval_multivalue(
_place,
main_socket="Paths",
secondary_sockets=["Mesh", "Seam Staggering"],
socket_name=socket_name,
default=SlicePaths(),
)