177 lines
5.9 KiB
Python
177 lines
5.9 KiB
Python
from __future__ import annotations
|
|
from typing import Any
|
|
import bpy
|
|
import os
|
|
import numpy as np
|
|
|
|
from ..bpy_ns_types import NfStringProperty, notify_tree_changed, NfEnumProperty, NfPointerProperty
|
|
from ....registry import register_class
|
|
from .base import InputNode, SliceNode, SliceIntrinsics
|
|
|
|
@register_class
|
|
class SLICENODE_InputString(InputNode):
|
|
bl_label = "String"
|
|
socket_type = "NodeSocketString"
|
|
|
|
@register_class
|
|
class SLICENODE_InputFloat(InputNode):
|
|
bl_label = "Float"
|
|
socket_type = "NodeSocketFloat"
|
|
|
|
@register_class
|
|
class SLICENODE_InputInt(InputNode):
|
|
bl_label = "Integer"
|
|
socket_type = "NodeSocketInt"
|
|
|
|
@register_class
|
|
class SLICENODE_InputVectorRotation(InputNode):
|
|
bl_label = "Vector Rotation"
|
|
socket_type = "NodeSocketRotation"
|
|
|
|
@register_class
|
|
class SLICENODE_InputVector(InputNode):
|
|
bl_label = "Vector"
|
|
socket_type = "NodeSocketVector"
|
|
|
|
@register_class
|
|
class SLICENODE_InputObject(InputNode):
|
|
bl_label = "Object"
|
|
socket_type = "NodeSocketObject"
|
|
bl_icon = "OBJECT_DATA"
|
|
|
|
@register_class
|
|
class SLICENODE_CollectionObjects(SliceNode):
|
|
bl_label = "Collection Objects"
|
|
|
|
collection: bpy.types.Collection | None = NfPointerProperty(
|
|
name="Collection",
|
|
type=bpy.types.Collection,
|
|
update=notify_tree_changed
|
|
)
|
|
|
|
def init(self, context):
|
|
self._update_outputs()
|
|
|
|
def update(self):
|
|
super().update()
|
|
self._update_outputs()
|
|
|
|
def draw_buttons(self, context, layout):
|
|
assert layout
|
|
layout.prop(self, "collection", text="")
|
|
|
|
def _update_outputs(self):
|
|
col = getattr(self, "collection", None)
|
|
if not col or not hasattr(col, "objects"):
|
|
self.outputs.clear()
|
|
return
|
|
|
|
objs = [obj for obj in col.objects if getattr(obj, "type", "") == 'MESH']
|
|
expected_names = sorted([obj.name for obj in objs])
|
|
|
|
# Remove outputs that are no longer in the collection
|
|
to_remove = [o for o in self.outputs if o.name not in expected_names]
|
|
for o in to_remove:
|
|
self.outputs.remove(o)
|
|
|
|
# Add new outputs
|
|
for name in expected_names:
|
|
if name not in self.outputs:
|
|
self.add_output("NodeSocketObject", name, identifier=name)
|
|
|
|
# Re-order to match sorted alphabetical order
|
|
if hasattr(self.outputs, "find") and hasattr(self.outputs, "move"):
|
|
for i, name in enumerate(expected_names):
|
|
current_index = self.outputs.find(name)
|
|
if current_index != -1 and current_index != i:
|
|
self.outputs.move(current_index, i)
|
|
|
|
def evaluate_output(self, socket_name: str, **kwargs) -> Any:
|
|
if self.collection and socket_name in bpy.data.objects:
|
|
return bpy.data.objects[socket_name]
|
|
return None
|
|
|
|
@register_class
|
|
class SLICENODE_InputSettings(InputNode):
|
|
input_type = "Settings"
|
|
bl_icon = "OBJECT_DATA"
|
|
|
|
@register_class
|
|
class SLICENODE_InputPrinter(SliceNode):
|
|
bl_label = "Printer"
|
|
bl_icon = "OUTPUT"
|
|
|
|
def update_label(self, context):
|
|
self.label = self.printer_label
|
|
notify_tree_changed(self, context)
|
|
|
|
printer_label: str = NfStringProperty(name="Label", default="Printer", update=update_label)
|
|
|
|
host_type: str = NfEnumProperty(
|
|
name="Type",
|
|
items=[
|
|
('PRUSALINK', "PrusaLink", "PrusaLink API"),
|
|
('CREALITY', "Creality", "Creality Cloud API"),
|
|
('MOONRAKER', "Moonraker", "Moonraker (Klipper) API"),
|
|
],
|
|
default='PRUSALINK'
|
|
)
|
|
|
|
def init(self, context):
|
|
self.add_output("SLICESOCK_Printer")
|
|
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]
|
|
layout.prop(self, "host_type") # pyright: ignore[reportOptionalMemberAccess]
|
|
|
|
def evaluate_output(self, socket_name: str, **_kwargs) -> Any:
|
|
from ....infra.networking.printer_backends import PrinterConfig
|
|
return PrinterConfig(
|
|
host=self.resolve("Host"),
|
|
port=self.resolve("Port"),
|
|
prefix=self.resolve("Prefix"),
|
|
label=self.printer_label,
|
|
username=self.resolve("Username"),
|
|
password=self.resolve("Password"),
|
|
host_type=self.host_type
|
|
)
|
|
|
|
|
|
@register_class
|
|
class SLICENODE_InputIntrinsics(SliceNode):
|
|
|
|
bl_label = "Printer Intrinsics"
|
|
|
|
def init(self, context):
|
|
self.add_output("SLICESOCK_Intrinsics")
|
|
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
|
|
try:
|
|
ret_fr = self.resolve("Retraction Feedrate") or 0.0
|
|
except Exception:
|
|
ret_fr = 0.0
|
|
|
|
return SliceIntrinsics(
|
|
bed_x=self.resolve("Bed X"),
|
|
bed_y=self.resolve("Bed Y"),
|
|
feedrate=self.resolve("Feedrate"),
|
|
travel_feedrate=self.resolve("Travel Feedrate"),
|
|
extrusion_rate=self.resolve("Extrusion Rate"),
|
|
retraction=self.resolve("Retraction"),
|
|
lift=self.resolve("Lift"),
|
|
retraction_feedrate=ret_fr
|
|
)
|