refactor sockets
This commit is contained in:
parent
29f7b71be1
commit
2bfc1ef781
14 changed files with 213 additions and 191 deletions
|
|
@ -34,16 +34,29 @@ class SliceIntrinsics:
|
|||
|
||||
class InputNode(SliceNode):
|
||||
input_type: str = ""
|
||||
socket_type: str = ""
|
||||
|
||||
def __init_subclass__(cls, **kwargs):
|
||||
super().__init_subclass__(**kwargs)
|
||||
if "bl_label" not in cls.__dict__: cls.bl_label = cls.input_type
|
||||
|
||||
def init(self, context) -> None:
|
||||
self.add_output(f"SLICESOCK_{self.bl_label}")
|
||||
stype = self.socket_type or (f"NodeSocket{self.bl_label}" if not self.bl_label.startswith("NodeSocket") else self.bl_label)
|
||||
self.add_output(stype)
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
assert layout
|
||||
if self.outputs:
|
||||
sock = self.outputs[0]
|
||||
if hasattr(sock, "default_value"):
|
||||
layout.prop(sock, "default_value", text="")
|
||||
elif hasattr(sock, "value"):
|
||||
layout.prop(sock, "value", text="")
|
||||
|
||||
def evaluate_output(self, socket_name: str, **_kwargs):
|
||||
return self.outputs.get(socket_name).value
|
||||
out = self.outputs.get(socket_name) or (self.outputs[0] if self.outputs else None)
|
||||
if out is None: return None
|
||||
return getattr(out, "value", getattr(out, "default_value", None))
|
||||
|
||||
class MathNode(SliceNode):
|
||||
bl_label = "Float Math"
|
||||
|
|
@ -72,12 +85,13 @@ class MathNode(SliceNode):
|
|||
|
||||
math_type: TypeAlias = float
|
||||
socket_label: str = "Float"
|
||||
socket_type: str = "NodeSocketFloat"
|
||||
|
||||
def init(self, context):
|
||||
self.add_output(f"SLICESOCK_{self.socket_label}Ro", "Value")
|
||||
self.add_output(self.socket_type, "Value")
|
||||
|
||||
self.add_input(f"SLICESOCK_{self.socket_label}", "Value")
|
||||
self.add_input(f"SLICESOCK_{self.socket_label}", "Value")
|
||||
self.add_input(self.socket_type, "Value")
|
||||
self.add_input(self.socket_type, "Value")
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
assert layout
|
||||
|
|
|
|||
|
|
@ -63,9 +63,9 @@ class SLICENODE_AssignMetadata(SliceNode):
|
|||
bl_label = "Assign Metadata"
|
||||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_String", "Name")
|
||||
self.add_input("SLICESOCK_String", "Filament Type")
|
||||
self.add_input("SLICESOCK_String", "Printer Model")
|
||||
self.add_input("NodeSocketString", "Name")
|
||||
self.add_input("NodeSocketString", "Filament Type")
|
||||
self.add_input("NodeSocketString", "Printer Model")
|
||||
self.add_output("SLICESOCK_GcodeRo", "Gcode")
|
||||
|
||||
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
|
||||
|
|
@ -87,8 +87,8 @@ class SLICENODE_GcodeRegexReplace(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Gcode", "Gcode")
|
||||
self.add_input("SLICESOCK_String", "Find")
|
||||
self.add_input("SLICESOCK_String", "Replace")
|
||||
self.add_input("NodeSocketString", "Find")
|
||||
self.add_input("NodeSocketString", "Replace")
|
||||
self.add_output("SLICESOCK_GcodeRo", "Gcode")
|
||||
|
||||
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
|
||||
|
|
|
|||
|
|
@ -10,27 +10,33 @@ from .base import InputNode, SliceNode, SliceIntrinsics
|
|||
|
||||
@register_class
|
||||
class SLICENODE_InputString(InputNode):
|
||||
input_type = "String"
|
||||
bl_label = "String"
|
||||
socket_type = "NodeSocketString"
|
||||
|
||||
@register_class
|
||||
class SLICENODE_InputFloat(InputNode):
|
||||
input_type = "Float"
|
||||
bl_label = "Float"
|
||||
socket_type = "NodeSocketFloat"
|
||||
|
||||
@register_class
|
||||
class SLICENODE_InputInt(InputNode):
|
||||
input_type = "Int"
|
||||
bl_label = "Integer"
|
||||
socket_type = "NodeSocketInt"
|
||||
|
||||
@register_class
|
||||
class SLICENODE_InputVectorRotation(InputNode):
|
||||
input_type = "VectorRotation"
|
||||
bl_label = "Vector Rotation"
|
||||
socket_type = "NodeSocketRotation"
|
||||
|
||||
@register_class
|
||||
class SLICENODE_InputVector(InputNode):
|
||||
input_type = "Vector"
|
||||
bl_label = "Vector"
|
||||
socket_type = "NodeSocketVector"
|
||||
|
||||
@register_class
|
||||
class SLICENODE_InputObject(InputNode):
|
||||
input_type = "Object"
|
||||
bl_label = "Object"
|
||||
socket_type = "NodeSocketObject"
|
||||
bl_icon = "OBJECT_DATA"
|
||||
|
||||
@register_class
|
||||
|
|
@ -70,7 +76,7 @@ class SLICENODE_CollectionObjects(SliceNode):
|
|||
# Add new outputs
|
||||
for name in expected_names:
|
||||
if name not in self.outputs:
|
||||
self.add_output("SLICESOCK_ObjectRo", name, identifier=name)
|
||||
self.add_output("NodeSocketObject", name, identifier=name)
|
||||
|
||||
def evaluate_output(self, socket_name: str, **kwargs) -> Any:
|
||||
if self.collection and socket_name in bpy.data.objects:
|
||||
|
|
@ -82,8 +88,8 @@ class SLICENODE_WipeTower(SliceNode):
|
|||
bl_label = "Wipe Tower"
|
||||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Float", "X Position").value = 170.0
|
||||
self.add_input("SLICESOCK_Float", "Y Position").value = 140.0
|
||||
self.add_input("NodeSocketFloat", "X Position").value = 170.0
|
||||
self.add_input("NodeSocketFloat", "Y Position").value = 140.0
|
||||
self.add_output("SLICESOCK_SettingsRo", "Settings")
|
||||
|
||||
def evaluate_output(self, socket_name: str, **_kwargs) -> Any:
|
||||
|
|
@ -108,9 +114,9 @@ class SLICENODE_OffsetObject(SliceNode):
|
|||
bl_label = "Offset Object"
|
||||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Float", "X Offset").value = 0.0
|
||||
self.add_input("SLICESOCK_Float", "Y Offset").value = 0.0
|
||||
self.add_input("SLICESOCK_Float", "Z Offset").value = 0.0
|
||||
self.add_input("NodeSocketFloat", "X Offset").value = 0.0
|
||||
self.add_input("NodeSocketFloat", "Y Offset").value = 0.0
|
||||
self.add_input("NodeSocketFloat", "Z Offset").value = 0.0
|
||||
self.add_output("SLICESOCK_SettingsRo", "Settings")
|
||||
|
||||
def evaluate_output(self, socket_name: str, **_kwargs) -> Any:
|
||||
|
|
@ -250,11 +256,11 @@ class SLICENODE_InputPrinter(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_output("SLICESOCK_Printer")
|
||||
self.add_input("SLICESOCK_String", "Host").value = "localhost"
|
||||
self.add_input("SLICESOCK_Int", "Port").value = 80
|
||||
self.add_input("SLICESOCK_String", "Prefix")
|
||||
self.add_input("SLICESOCK_String", "Username")
|
||||
self.add_input("SLICESOCK_String", "Password")
|
||||
self.add_input("NodeSocketString", "Host").value = "localhost"
|
||||
self.add_input("NodeSocketInt", "Port").value = 80
|
||||
self.add_input("NodeSocketString", "Prefix")
|
||||
self.add_input("NodeSocketString", "Username")
|
||||
self.add_input("NodeSocketString", "Password")
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, "printer_label") # pyright: ignore[reportOptionalMemberAccess]
|
||||
|
|
@ -280,14 +286,14 @@ class SLICENODE_InputIntrinsics(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_output("SLICESOCK_Intrinsics")
|
||||
self.add_input("SLICESOCK_Float", "Bed X").value = 250.0
|
||||
self.add_input("SLICESOCK_Float", "Bed Y").value = 210.0
|
||||
self.add_input("SLICESOCK_Float", "Feedrate").value = 1200.0
|
||||
self.add_input("SLICESOCK_Float", "Travel Feedrate").value = 2400.0
|
||||
self.add_input("SLICESOCK_Float", "Extrusion Rate").value = 0.035
|
||||
self.add_input("SLICESOCK_Float", "Retraction").value = 0.0
|
||||
self.add_input("SLICESOCK_Float", "Retraction Feedrate").value = 0.0
|
||||
self.add_input("SLICESOCK_Float", "Lift").value = 0.0
|
||||
self.add_input("NodeSocketFloat", "Bed X").value = 250.0
|
||||
self.add_input("NodeSocketFloat", "Bed Y").value = 210.0
|
||||
self.add_input("NodeSocketFloat", "Feedrate").value = 1200.0
|
||||
self.add_input("NodeSocketFloat", "Travel Feedrate").value = 2400.0
|
||||
self.add_input("NodeSocketFloat", "Extrusion Rate").value = 0.035
|
||||
self.add_input("NodeSocketFloat", "Retraction").value = 0.0
|
||||
self.add_input("NodeSocketFloat", "Retraction Feedrate").value = 0.0
|
||||
self.add_input("NodeSocketFloat", "Lift").value = 0.0
|
||||
|
||||
def evaluate_output(self, socket_name: str, **_kwargs) -> SliceIntrinsics:
|
||||
ret_fr = 0.0
|
||||
|
|
|
|||
|
|
@ -7,9 +7,11 @@ class SLICENODE_FloatMath(MathNode):
|
|||
bl_label = "Math"
|
||||
math_type = float
|
||||
socket_label: str = "Float"
|
||||
socket_type: str = "NodeSocketFloat"
|
||||
|
||||
@register_class
|
||||
class SLICENODE_IntMath(MathNode):
|
||||
bl_label = "Integer Math"
|
||||
math_type = int
|
||||
socket_label: str = "Int"
|
||||
socket_type: str = "NodeSocketInt"
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class SLICENODE_GetMesh(SliceNode):
|
|||
include_children: NfBoolProperty(name="Include Children", default=True) # pyright: ignore[reportInvalidTypeForm]
|
||||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Object")
|
||||
self.add_input("NodeSocketObject")
|
||||
self.add_output("SLICESOCK_Mesh")
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
|
|
@ -89,8 +89,8 @@ class SLICENODE_SeparateMesh(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Mesh")
|
||||
self.add_input("SLICESOCK_String", "Attribute")
|
||||
self.add_input("SLICESOCK_Float", "Value")
|
||||
self.add_input("NodeSocketString", "Attribute")
|
||||
self.add_input("NodeSocketFloat", "Value")
|
||||
self.add_output("SLICESOCK_Mesh", "Selection")
|
||||
self.add_output("SLICESOCK_Mesh", "Inverted")
|
||||
|
||||
|
|
@ -172,7 +172,7 @@ class SLICENODE_SeparateMeshByRange(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Mesh")
|
||||
self.add_input("SLICESOCK_String", "Attribute")
|
||||
self.add_input("NodeSocketString", "Attribute")
|
||||
self._update_outputs()
|
||||
|
||||
def update(self):
|
||||
|
|
@ -277,9 +277,9 @@ class SLICENODE_ArrangeMesh(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Mesh", "Slicing Group", display_shape='LIST')
|
||||
self.add_input("SLICESOCK_Float", "Bed X").value = 250.0
|
||||
self.add_input("SLICESOCK_Float", "Bed Y").value = 250.0
|
||||
self.add_input("SLICESOCK_Float", "Spacing").value = 2.0
|
||||
self.add_input("NodeSocketFloat", "Bed X").value = 250.0
|
||||
self.add_input("NodeSocketFloat", "Bed Y").value = 250.0
|
||||
self.add_input("NodeSocketFloat", "Spacing").value = 2.0
|
||||
self.add_output("SLICESOCK_Mesh", "Slicing Group", display_shape='LIST')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
|
|
@ -584,18 +584,16 @@ class SLICENODE_TransformGeometry(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Geometry", "Geometry")
|
||||
self.add_input("SLICESOCK_Vector", "Translation")
|
||||
self.add_input("SLICESOCK_VectorRotation", "Rotation")
|
||||
self.add_input("SLICESOCK_Vector", "Scale").value = (1.0, 1.0, 1.0)
|
||||
self.add_input("NodeSocketVector", "Translation")
|
||||
self.add_input("NodeSocketRotation", "Rotation")
|
||||
self.add_input("NodeSocketVector", "Scale").value = (1.0, 1.0, 1.0)
|
||||
self.add_output("SLICESOCK_Geometry", "Geometry")
|
||||
|
||||
def evaluate_output(self, socket_name: str, **_kwargs) -> Any:
|
||||
if socket_name not in ("Geometry", "Mesh"):
|
||||
if socket_name not in ("Geometry"):
|
||||
return None
|
||||
|
||||
geom_data: Any = self.resolve("Geometry")
|
||||
if geom_data is None:
|
||||
geom_data = self.resolve("Mesh")
|
||||
if geom_data is None:
|
||||
return None
|
||||
|
||||
|
|
@ -623,9 +621,9 @@ class SLICENODE_DropGeometry(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Mesh", "Mesh")
|
||||
self.add_input("SLICESOCK_Float", "Z")
|
||||
self.add_input("NodeSocketFloat", "Z")
|
||||
self.add_output("SLICESOCK_Mesh", "Mesh")
|
||||
self.add_output("SLICESOCK_VectorRo", "Translation")
|
||||
self.add_output("NodeSocketVector", "Translation")
|
||||
|
||||
def evaluate_output(self, socket_name: str, **_kwargs) -> SlicingCollection | SlicingGroup | tuple[float, float, float] | None:
|
||||
if socket_name == "Translation":
|
||||
|
|
@ -754,7 +752,7 @@ class SLICENODE_RenameMesh(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Mesh", "Geometry")
|
||||
self.add_input("SLICESOCK_String", "Name")
|
||||
self.add_input("NodeSocketString", "Name")
|
||||
self.add_output("SLICESOCK_Mesh", "Geometry")
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
|
|
@ -821,7 +819,7 @@ class SLICENODE_AssignPdfProperties(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Mesh", "Geometry")
|
||||
self.add_input("SLICESOCK_Float", "Line Width")
|
||||
self.add_input("NodeSocketFloat", "Line Width")
|
||||
self.add_output("SLICESOCK_Mesh", "Geometry")
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ class SLICENODE_GetPaths(SliceNode):
|
|||
bl_label = "Get Paths"
|
||||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Object")
|
||||
self.add_input("SLICESOCK_String", "Extrusion Multiplier Attribute").value = 'e_mult'
|
||||
self.add_input("SLICESOCK_String", "Feedrate Attribute").value = 'f_rate'
|
||||
self.add_input("NodeSocketObject")
|
||||
self.add_input("NodeSocketString", "Extrusion Multiplier Attribute").value = 'e_mult'
|
||||
self.add_input("NodeSocketString", "Feedrate Attribute").value = 'f_rate'
|
||||
self.add_input("SLICESOCK_Settings", "Extra Attributes")
|
||||
self.add_output("SLICESOCK_Paths")
|
||||
|
||||
|
|
@ -44,9 +44,9 @@ class SLICENODE_SliceShells(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Mesh")
|
||||
self.add_input("SLICESOCK_Float", "Layer Height").value = 0.2
|
||||
self.add_input("SLICESOCK_Float", "First Layer Height").value = 0.2
|
||||
self.add_input("SLICESOCK_VectorRotation", "Rotation")
|
||||
self.add_input("NodeSocketFloat", "Layer Height").value = 0.2
|
||||
self.add_input("NodeSocketFloat", "First Layer Height").value = 0.2
|
||||
self.add_input("NodeSocketRotation", "Rotation")
|
||||
self.add_output("SLICESOCK_Paths")
|
||||
|
||||
def evaluate_output(self, socket_name: str, **_kwargs) -> SlicePaths:
|
||||
|
|
@ -211,8 +211,8 @@ class SLICENODE_BufferCurve(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Paths")
|
||||
self.add_input("SLICESOCK_Float", "Distance").value = 0.0
|
||||
self.add_input("SLICESOCK_VectorRotation", "Rotation")
|
||||
self.add_input("NodeSocketFloat", "Distance").value = 0.0
|
||||
self.add_input("NodeSocketRotation", "Rotation")
|
||||
self.add_output("SLICESOCK_Paths")
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
|
|
@ -254,8 +254,8 @@ class SLICENODE_OffsetCurve(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Paths")
|
||||
self.add_input("SLICESOCK_Float", "Distance").value = 0.0
|
||||
self.add_input("SLICESOCK_VectorRotation", "Rotation")
|
||||
self.add_input("NodeSocketFloat", "Distance").value = 0.0
|
||||
self.add_input("NodeSocketRotation", "Rotation")
|
||||
self.add_output("SLICESOCK_Paths")
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
|
|
@ -283,7 +283,7 @@ class SLICENODE_PathOffset(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Paths", "Paths")
|
||||
self.add_input("SLICESOCK_Vector", "Offset")
|
||||
self.add_input("NodeSocketVector", "Offset")
|
||||
self.add_output("SLICESOCK_Paths", "Paths")
|
||||
|
||||
def evaluate_output(self, socket_name: str, **_kwargs) -> Any:
|
||||
|
|
@ -300,8 +300,8 @@ class SLICENODE_RotatePath(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Paths", "Paths")
|
||||
self.add_input("SLICESOCK_Float", "Angle").value = 0.0
|
||||
self.add_input("SLICESOCK_Vector", "Center")
|
||||
self.add_input("NodeSocketFloat", "Angle").value = 0.0
|
||||
self.add_input("NodeSocketVector", "Center")
|
||||
self.add_output("SLICESOCK_Paths", "Paths")
|
||||
|
||||
def evaluate_output(self, socket_name: str, **_kwargs) -> Any:
|
||||
|
|
@ -330,10 +330,10 @@ class SLICENODE_BufferShellsMultiple(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Paths")
|
||||
self.add_input("SLICESOCK_Float", "Distance").value = 0
|
||||
self.add_input("SLICESOCK_Float", "Width Step").value = 0.4
|
||||
self.add_input("SLICESOCK_Int", "Count").value = 2
|
||||
self.add_input("SLICESOCK_VectorRotation", "Rotation")
|
||||
self.add_input("NodeSocketFloat", "Distance").value = 0
|
||||
self.add_input("NodeSocketFloat", "Width Step").value = 0.4
|
||||
self.add_input("NodeSocketInt", "Count").value = 2
|
||||
self.add_input("NodeSocketRotation", "Rotation")
|
||||
self.add_output("SLICESOCK_Paths")
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
|
|
@ -370,9 +370,9 @@ class SLICENODE_Infill(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Paths")
|
||||
self.add_input("SLICESOCK_Float", "Density").value = 2.0
|
||||
self.add_input("SLICESOCK_Float", "Infill Rotation").value = 0.0
|
||||
self.add_input("SLICESOCK_VectorRotation", "Layer Rotation")
|
||||
self.add_input("NodeSocketFloat", "Density").value = 2.0
|
||||
self.add_input("NodeSocketFloat", "Infill Rotation").value = 0.0
|
||||
self.add_input("NodeSocketRotation", "Layer Rotation")
|
||||
self.add_output("SLICESOCK_Paths")
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
|
|
@ -422,7 +422,7 @@ class SLICENODE_OverhangMask(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Paths")
|
||||
self.add_input("SLICESOCK_Float", "Tolerance").value = 0.05
|
||||
self.add_input("NodeSocketFloat", "Tolerance").value = 0.05
|
||||
self.add_output("SLICESOCK_Paths")
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
|
|
@ -534,7 +534,7 @@ class SLICENODE_SimplifyPaths(SliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self.add_input("SLICESOCK_Paths")
|
||||
self.add_input("SLICESOCK_Float", "Tolerance").value = 0.1
|
||||
self.add_input("NodeSocketFloat", "Tolerance").value = 0.1
|
||||
self.add_output("SLICESOCK_Paths")
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class SLICENODE_GcodeToMesh(ExecSliceNode):
|
|||
|
||||
def init(self, context):
|
||||
self._init_exec()
|
||||
self.add_input("SLICESOCK_String", "Name")
|
||||
self.add_input("NodeSocketString", "Name")
|
||||
self.add_multi_socket_group("SLICESOCK_Gcode", name="Gcode")
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
|
|
@ -242,7 +242,7 @@ class SLICENODE_GcodeToMesh(ExecSliceNode):
|
|||
|
||||
for i, gcode in enumerate(gcodes):
|
||||
if total_parts > 1:
|
||||
mesh_name = f"{base_mesh_name}{i+1:0{num_digits}d}"
|
||||
mesh_name = f"{base_mesh_name}{i:0{num_digits}d}"
|
||||
else:
|
||||
mesh_name = base_mesh_name
|
||||
|
||||
|
|
|
|||
|
|
@ -44,101 +44,18 @@ class ReadonlySocket():
|
|||
def draw(self, context: Any, layout: Any, node: Any, text: str | None):
|
||||
return self._draw_as_ro(context, layout, node, text) # pyright: ignore[reportAttributeAccessIssue]
|
||||
|
||||
class SLICESOCK_ObjectCommon(InputNodeSocket):
|
||||
bl_label = "Object"
|
||||
|
||||
value: NfPointerProperty(
|
||||
name="Object",
|
||||
type=bpy.types.Object,
|
||||
update=notify_tree_changed
|
||||
) # pyright: ignore[reportInvalidTypeForm]
|
||||
bl_color = (0.9, 0.7, 0.2, 1.0)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_ObjectRo(ReadonlySocket, SLICESOCK_ObjectCommon): ...
|
||||
@register_class
|
||||
class SLICESOCK_Object(SLICESOCK_ObjectCommon): ...
|
||||
|
||||
class SLICESOCK_Float_Common(InputNodeSocket):
|
||||
bl_label = "Float"
|
||||
|
||||
value: NfFloatProperty(name="Float", default=0) # pyright: ignore[reportInvalidTypeForm]
|
||||
bl_color = (161/255, 161/255, 161/255, 1.0)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_FloatRo(ReadonlySocket, SLICESOCK_Float_Common): ...
|
||||
@register_class
|
||||
class SLICESOCK_Float(SLICESOCK_Float_Common): ...
|
||||
|
||||
|
||||
class SLICESOCK_Int_Common(InputNodeSocket):
|
||||
bl_label = "Integer"
|
||||
|
||||
value: NfIntProperty(name="Int", default=0) # pyright: ignore[reportInvalidTypeForm]
|
||||
bl_color = (161/255, 161/255, 161/255, 1.0)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_Int(SLICESOCK_Int_Common): ...
|
||||
@register_class
|
||||
class SLICESOCK_IntRo(ReadonlySocket, SLICESOCK_Int_Common): ...
|
||||
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_String(InputNodeSocket):
|
||||
bl_label = "String"
|
||||
|
||||
value: NfStringProperty(name="String", default="") # pyright: ignore[reportInvalidTypeForm]
|
||||
bl_color = (0.4, 0.7, 1.0, 1.0)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_FilePath(InputNodeSocket):
|
||||
bl_label = "Filepath"
|
||||
|
||||
value: NfStringProperty(name="Filepath", default="", subtype='FILE_PATH') # pyright: ignore[reportInvalidTypeForm]
|
||||
bl_color = (0.4, 0.7, 1.0, 1.0)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_DirPath(InputNodeSocket):
|
||||
bl_label = "Filepath"
|
||||
|
||||
value: NfStringProperty(name="Folder", default="", subtype='DIR_PATH') # pyright: ignore[reportInvalidTypeForm]
|
||||
bl_color = (0.4, 0.7, 1.0, 1.0)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_VectorRotation_Common(InputNodeSocket):
|
||||
bl_label = "VectorRotation"
|
||||
|
||||
value: NfFloatVectorProperty(name="Vector", size=3, default=(0.0, 0.0, 0.0), subtype='EULER') # pyright: ignore[reportInvalidTypeForm]
|
||||
bl_color = (166/255, 99/255, 199/255, 1.0)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_VectorRotation(SLICESOCK_VectorRotation_Common): ...
|
||||
@register_class
|
||||
class SLICESOCK_VectorRotationRo(ReadonlySocket, SLICESOCK_VectorRotation_Common): ...
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_Vector_Common(InputNodeSocket):
|
||||
bl_label = "Vector"
|
||||
|
||||
value: NfFloatVectorProperty(name="Vector", size=3, default=(0.0, 0.0, 0.0)) # pyright: ignore[reportInvalidTypeForm]
|
||||
bl_color = (0.39, 0.39, 0.78, 1.0)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_Vector(SLICESOCK_Vector_Common): ...
|
||||
@register_class
|
||||
class SLICESOCK_VectorRo(ReadonlySocket, SLICESOCK_Vector_Common): ...
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_Mesh(LabelNodeSocket):
|
||||
bl_label = "Mesh"
|
||||
default = None
|
||||
bl_color = (0, 214/255, 163/255, 1.0)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_Paths(LabelNodeSocket):
|
||||
bl_label = "Paths"
|
||||
default = SlicePaths()
|
||||
bl_color = (214/255, 0, 120/255, 1.0)
|
||||
# Native Blender socket type aliases
|
||||
SLICESOCK_Object = "NodeSocketObject"
|
||||
SLICESOCK_ObjectRo = "NodeSocketObject"
|
||||
SLICESOCK_Float = "NodeSocketFloat"
|
||||
SLICESOCK_FloatRo = "NodeSocketFloat"
|
||||
SLICESOCK_Int = "NodeSocketInt"
|
||||
SLICESOCK_IntRo = "NodeSocketInt"
|
||||
SLICESOCK_String = "NodeSocketString"
|
||||
SLICESOCK_VectorRotation = "NodeSocketRotation"
|
||||
SLICESOCK_VectorRotationRo = "NodeSocketRotation"
|
||||
SLICESOCK_Vector = "NodeSocketVector"
|
||||
SLICESOCK_VectorRo = "NodeSocketVector"
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_Geometry(LabelNodeSocket):
|
||||
|
|
@ -159,7 +76,7 @@ class SLICESOCK_Geometry(LabelNodeSocket):
|
|||
pass
|
||||
return getattr(from_sock, "bl_color", self.bl_color)
|
||||
|
||||
if self.is_output:
|
||||
if getattr(self, "is_output", False):
|
||||
if node and hasattr(node, "inputs"):
|
||||
sock_name = getattr(self, "name", "")
|
||||
matching_in = (node.inputs.get(sock_name) if sock_name else None) or node.inputs.get("Geometry")
|
||||
|
|
@ -169,6 +86,32 @@ class SLICESOCK_Geometry(LabelNodeSocket):
|
|||
else:
|
||||
return _get_upstream_color(self)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_FilePath(InputNodeSocket):
|
||||
bl_label = "Filepath"
|
||||
|
||||
value: NfStringProperty(name="Filepath", default="", subtype='FILE_PATH') # pyright: ignore[reportInvalidTypeForm]
|
||||
bl_color = (0.4, 0.7, 1.0, 1.0)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_DirPath(InputNodeSocket):
|
||||
bl_label = "Filepath"
|
||||
|
||||
value: NfStringProperty(name="Folder", default="", subtype='DIR_PATH') # pyright: ignore[reportInvalidTypeForm]
|
||||
bl_color = (0.4, 0.7, 1.0, 1.0)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_Mesh(LabelNodeSocket):
|
||||
bl_label = "Mesh"
|
||||
default = None
|
||||
bl_color = (0, 214/255, 163/255, 1.0)
|
||||
|
||||
@register_class
|
||||
class SLICESOCK_Paths(LabelNodeSocket):
|
||||
bl_label = "Paths"
|
||||
default = SlicePaths()
|
||||
bl_color = (214/255, 0, 120/255, 1.0)
|
||||
|
||||
|
||||
|
||||
class SLICESOCK_Gcode_Common(InputNodeSocket):
|
||||
|
|
|
|||
|
|
@ -30,9 +30,11 @@ def get_referenced_objects(node, visited=None):
|
|||
# Check all input sockets for objects
|
||||
for inp in node.inputs:
|
||||
# If it's an object socket, it might have a value if not linked
|
||||
if inp.bl_idname in {"SLICESOCK_Object", "SLICESOCK_ObjectRo"}:
|
||||
if not inp.is_linked and getattr(inp, "value", None):
|
||||
objs.add(inp.value)
|
||||
if inp.bl_idname == "NodeSocketObject":
|
||||
if not inp.is_linked and getattr(inp, "value", getattr(inp, "default_value", None)):
|
||||
val = getattr(inp, "value", getattr(inp, "default_value", None))
|
||||
if isinstance(val, bpy.types.Object):
|
||||
objs.add(val)
|
||||
|
||||
# Always follow links to find more objects upstream
|
||||
if inp.is_linked:
|
||||
|
|
@ -48,9 +50,10 @@ def get_referenced_objects(node, visited=None):
|
|||
# Also check output sockets of the node itself,
|
||||
# as some nodes might "hold" an object (like InputObject)
|
||||
for outp in node.outputs:
|
||||
if outp.bl_idname in {"SLICESOCK_Object", "SLICESOCK_ObjectRo"}:
|
||||
if getattr(outp, "value", None):
|
||||
objs.add(outp.value)
|
||||
if outp.bl_idname == "NodeSocketObject":
|
||||
val = getattr(outp, "value", getattr(outp, "default_value", None))
|
||||
if isinstance(val, bpy.types.Object):
|
||||
objs.add(val)
|
||||
elif node.bl_idname == "SLICENODE_CollectionObjects" and outp.is_linked:
|
||||
obj = bpy.data.objects.get(outp.identifier)
|
||||
if obj:
|
||||
|
|
|
|||
|
|
@ -752,7 +752,7 @@ def segments_to_slice(segments: np.ndarray) -> list[np.ndarray]:
|
|||
open_paths = []
|
||||
for p in linked:
|
||||
path_pts = p[:, :2]
|
||||
if len(path_pts) > 2 and np.allclose(path_pts[0], path_pts[-1]):
|
||||
if len(path_pts) > 3 and np.allclose(path_pts[0], path_pts[-1]):
|
||||
closed_paths.append(p)
|
||||
else:
|
||||
open_paths.append(p)
|
||||
|
|
|
|||
|
|
@ -57,4 +57,5 @@ This file provides a mapping of modules to their primary responsibilities and ke
|
|||
|
||||
- `blender_slice_nodes_generic.py`:
|
||||
- Base classes for NodeSlicer nodes (`SliceNode`) and sockets (`SliceNodeSocket`).
|
||||
- Native Blender socket type mappings (`NodeSocketFloat`, `NodeSocketInt`, `NodeSocketVector`, `NodeSocketRotation`, `NodeSocketString`, `NodeSocketObject`, `NodeSocketGeometry`).
|
||||
- Core evaluation logic (`resolve_input`).
|
||||
|
|
|
|||
12
doc/NODES.md
12
doc/NODES.md
|
|
@ -4,11 +4,13 @@
|
|||
|
||||
| Socket ID | Type | Underlying Data Structure | Purpose |
|
||||
|-----------|------|---------------------------|---------|
|
||||
| `SLICESOCK_Object` | `bpy.types.Object` | Blender RNA Object | Reference to a Blender Object |
|
||||
| `SLICESOCK_Float` | `float` | Python float | Numeric value |
|
||||
| `SLICESOCK_Int` | `int` | Python int | Integer value |
|
||||
| `SLICESOCK_String` | `str` | Python string | Text/Path value |
|
||||
| `SLICESOCK_Vector` | `tuple` | Python tuple (3) | XYZ or Euler rotation value |
|
||||
| `NodeSocketObject` | `bpy.types.Object` | Blender RNA Object | Reference to a Blender Object |
|
||||
| `NodeSocketFloat` | `float` | Python float | Numeric value |
|
||||
| `NodeSocketInt` | `int` | Python int | Integer value |
|
||||
| `NodeSocketString` | `str` | Python string | Text value |
|
||||
| `NodeSocketVector` | `tuple` | Python tuple (3) | XYZ vector value |
|
||||
| `NodeSocketRotation` | `tuple` | Python tuple (3) | Euler rotation value |
|
||||
| `NodeSocketGeometry` | `Geometry` | Geometry Data | Generic geometry reference |
|
||||
| `SLICESOCK_Mesh` | `SlicingObject` | NumPy NDArray (Triangles) | Internal mesh data (Transformed/Scaled) |
|
||||
| `SLICESOCK_Paths` | `SlicePaths` (list) | List of paths (N, 3) + groups | Generic toolpaths or slice boundaries |
|
||||
| `SLICESOCK_Gcode` | `str` | Multi-line string | Generated G-code text |
|
||||
|
|
|
|||
|
|
@ -11,9 +11,47 @@ class NodeException(Exception): ...
|
|||
|
||||
_EvalCache = dict[tuple[int, str, str], Any]
|
||||
|
||||
NATIVE_SOCKET_MAP: dict[str, str] = {}
|
||||
|
||||
NATIVE_SOCKET_LABELS: dict[str, str] = {
|
||||
"NodeSocketFloat": "Float",
|
||||
"NodeSocketInt": "Integer",
|
||||
"NodeSocketVector": "Vector",
|
||||
"NodeSocketRotation": "Rotation",
|
||||
"NodeSocketString": "String",
|
||||
"NodeSocketObject": "Object",
|
||||
}
|
||||
|
||||
if hasattr(bpy.types, "NodeSocket") and not hasattr(bpy.types.NodeSocket, "value"):
|
||||
def _get_socket_value(self):
|
||||
try:
|
||||
return self.default_value
|
||||
except (AttributeError, TypeError):
|
||||
pass
|
||||
return getattr(self, "_value", getattr(self, "default", None))
|
||||
|
||||
def _set_socket_value(self, val):
|
||||
try:
|
||||
self.default_value = val
|
||||
return
|
||||
except (AttributeError, TypeError):
|
||||
pass
|
||||
self._value = val
|
||||
|
||||
try:
|
||||
bpy.types.NodeSocket.value = property(_get_socket_value, _set_socket_value)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
class AutoBlIdName:
|
||||
def __init_subclass__(cls, **kwargs):
|
||||
super().__init_subclass__(**kwargs)
|
||||
if kwargs:
|
||||
try:
|
||||
super().__init_subclass__(**kwargs)
|
||||
except TypeError:
|
||||
super().__init_subclass__()
|
||||
else:
|
||||
super().__init_subclass__()
|
||||
if "bl_idname" not in cls.__dict__:
|
||||
cls.bl_idname = cls.__name__
|
||||
|
||||
|
|
@ -40,7 +78,8 @@ class SliceNode(Node, AutoBlIdName):
|
|||
return resolve_input(inputs.get(fieldname), cache=cache, visited=visited)
|
||||
|
||||
def add_output(self, bl_idname: str, name: str = "", identifier: str = "", hide: bool = False, display_shape: str = ""):
|
||||
eval_name = name or get_label_by_name(bl_idname)
|
||||
bl_idname = NATIVE_SOCKET_MAP.get(bl_idname, bl_idname)
|
||||
eval_name = name or NATIVE_SOCKET_LABELS.get(bl_idname) or get_label_by_name(bl_idname) or bl_idname
|
||||
sock = self.outputs.new(bl_idname, eval_name, identifier=identifier or eval_name)
|
||||
sock.hide = hide
|
||||
if display_shape:
|
||||
|
|
@ -48,7 +87,8 @@ class SliceNode(Node, AutoBlIdName):
|
|||
return sock
|
||||
|
||||
def add_input(self, bl_idname: str, name: str = "", identifier: str = "", hide: bool = False, display_shape: str = ""):
|
||||
eval_name = name or get_label_by_name(bl_idname)
|
||||
bl_idname = NATIVE_SOCKET_MAP.get(bl_idname, bl_idname)
|
||||
eval_name = name or NATIVE_SOCKET_LABELS.get(bl_idname) or get_label_by_name(bl_idname) or bl_idname
|
||||
sock = self.inputs.new(bl_idname, eval_name, identifier=identifier or eval_name)
|
||||
sock.hide = hide
|
||||
if display_shape:
|
||||
|
|
@ -268,6 +308,7 @@ class SLICENODE_Group(bpy.types.NodeCustomGroup, AutoBlIdName):
|
|||
# Add or update sockets
|
||||
sock_indexes = {s.identifier: i for i, s in enumerate(collection)}
|
||||
for ident, name, stype in expected:
|
||||
stype = NATIVE_SOCKET_MAP.get(stype, stype)
|
||||
if ident not in sock_indexes:
|
||||
try:
|
||||
# Explicitly pass identifier to keep it perfectly synced
|
||||
|
|
@ -384,10 +425,19 @@ def resolve_input(
|
|||
visited = getattr(socket.node, "_current_visited", None)
|
||||
|
||||
if not socket.is_linked:
|
||||
val = getattr(socket, "value", None)
|
||||
if val is not None:
|
||||
return val
|
||||
return socket.default
|
||||
try:
|
||||
val = getattr(socket, "default_value", None)
|
||||
if val is not None: return val
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
val = getattr(socket, "value", None)
|
||||
if val is not None: return val
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return getattr(socket, "default", None)
|
||||
|
||||
assert socket.is_linked
|
||||
assert socket.links
|
||||
|
|
|
|||
|
|
@ -63,6 +63,9 @@ sys.modules['bpy'] = mock_bpy
|
|||
sys.modules['bpy.types'] = mock_types
|
||||
sys.modules['bpy.props'] = MagicMock()
|
||||
sys.modules['bpy.utils'] = MagicMock()
|
||||
sys.modules['bpy.utils.previews'] = MagicMock()
|
||||
sys.modules['bpy.app'] = MagicMock()
|
||||
sys.modules['bpy.app.handlers'] = MagicMock()
|
||||
|
||||
from NodeSlicer.infra.blender.blender_slice_nodes_generic import (
|
||||
_resolve_group_output,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue