This commit is contained in:
Nicolas Predella 2026-05-21 11:28:29 +03:00
parent db343e8396
commit c9dbf0eb1d

View file

@ -4,7 +4,6 @@ import subprocess
import tempfile
import shlex
import shutil
from math import floor
from pathlib import Path
from typing import Any, TypeAlias
import bpy
@ -19,11 +18,8 @@ from ..slice import Pather, slice_at_range, SlicePaths
from ...infra.blender.blender_mesh_capture import SlicingCollection, SlicingObject, capture_mesh_edges, SlicingGroup
from ...infra.blender.blender_bridge import get_all_children
from ...infra.blender.blender_slice_nodes_generic import SliceNode, resolve_input
from ...infra.prusaslicer_profiles import ConfigWriter
from ...infra.prusaslicer_profiles.cache import LocalCache
from ...infra.prusaslicer_profiles.models import Profile
from ...infra.networking.airtable_backend import AirtableRecord
from ...infra._3mf_writer._3mf import prepare_3mf
class SliceIntrinsics:
bed_x: float
@ -348,8 +344,9 @@ class SLICENODE_GetPaths(SliceNode):
self.add_output("SLICESOCK_Paths")
def evaluate_output(self, socket_name: str, **_kwargs) -> SlicePaths:
obj: Any = resolve_input(self.inputs.get("Object"))
obj: Any = self.resolve("Object")
from ...infra.blender.blender_mesh_capture import capture_mesh_edges
so: list[np.ndarray] = capture_mesh_edges(obj)
return SlicePaths(so)
@ -366,8 +363,8 @@ class SLICENODE_SliceShells(SliceNode):
def evaluate_output(self, socket_name: str, **_kwargs) -> SlicePaths:
if socket_name != "Paths": return SlicePaths()
slicing_collection: SlicingCollection | None = resolve_input(self.inputs.get("Mesh"))
layer_height: float = resolve_input(self.inputs.get("Layer Height"))
slicing_collection: SlicingCollection | None = self.resolve("Mesh")
layer_height: float = self.resolve("Layer Height")
if not slicing_collection: return SlicePaths()
@ -378,6 +375,7 @@ class SLICENODE_SliceShells(SliceNode):
merged_object.mesh = np.concatenate([merged_object.mesh, obj.mesh], axis=0)
min = merged_object.mesh[:,0:3,2:3].min()
from math import floor
min = floor(min / layer_height) * layer_height
max = merged_object.mesh[:,0:3,2:3].max()
@ -415,9 +413,9 @@ class SLICENODE_BufferShells(SliceNode):
def evaluate_output(self, socket_name: str, **_kwargs) -> SlicePaths:
if socket_name != "Paths": return SlicePaths()
paths: SlicePaths = resolve_input(self.inputs.get("Paths"))
distance: float = resolve_input(self.inputs.get("Distance")) or 0.0
rotation: Any = resolve_input(self.inputs.get("Rotation")) or (0.0, 0.0, 0.0)
paths: SlicePaths = self.resolve("Paths")
distance: float = self.resolve("Distance") or 0.0
rotation: Any = self.resolve("Rotation") or (0.0, 0.0, 0.0)
if not paths: return SlicePaths()
@ -470,11 +468,11 @@ class SLICENODE_BufferShellsMultiple(SliceNode):
def evaluate_output(self, socket_name: str, **_kwargs) -> SlicePaths:
if socket_name != "Paths": return SlicePaths()
paths: SlicePaths = resolve_input(self.inputs.get("Paths"))
base_distance: float = resolve_input(self.inputs.get("Distance")) or 0.0
width_step: float = resolve_input(self.inputs.get("Width Step")) or 0.0
count: int = resolve_input(self.inputs.get("Count")) or 1
rotation: Any = resolve_input(self.inputs.get("Rotation")) or (0.0, 0.0, 0.0)
paths: SlicePaths = self.resolve("Paths")
base_distance: float = self.resolve("Distance") or 0.0
width_step: float = self.resolve("Width Step") or 0.0
count: int = self.resolve("Count") or 1
rotation: Any = self.resolve("Rotation") or (0.0, 0.0, 0.0)
if not paths: return SlicePaths()
@ -547,10 +545,10 @@ class SLICENODE_Infill(SliceNode):
def evaluate_output(self, socket_name: str, **_kwargs) -> SlicePaths:
if socket_name != "Paths": return SlicePaths()
paths: SlicePaths = resolve_input(self.inputs.get("Paths"))
density: float = resolve_input(self.inputs.get("Density")) or 2.0
infill_rotation: float = resolve_input(self.inputs.get("Infill Rotation")) or 0.0
rotation: Any = resolve_input(self.inputs.get("Layer Rotation")) or (0.0, 0.0, 0.0)
paths: SlicePaths = self.resolve("Paths")
density: float = self.resolve("Density") or 2.0
infill_rotation: float = self.resolve("Infill Rotation") or 0.0
rotation: Any = self.resolve("Layer Rotation") or (0.0, 0.0, 0.0)
if not paths: return SlicePaths()
@ -596,8 +594,8 @@ class SLICENODE_PathsToGcode(SliceNode):
layout.prop(self, "use_header")
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
paths: list[np.ndarray] = resolve_input(self.inputs.get("Paths"))
intrinsics: SliceIntrinsics | None = resolve_input(self.inputs.get("Intrinsics"))
paths: list[np.ndarray] = self.resolve("Paths")
intrinsics: SliceIntrinsics | None = self.resolve("Intrinsics")
pather: Pather = Pather(paths)
if intrinsics:
@ -874,7 +872,7 @@ class SLICENODE_LoadGcode(SliceNode):
self.add_output("SLICESOCK_GcodeRo")
def evaluate_output(self, socket_name: str, **_kwargs) -> str:
path = resolve_input(self.inputs.get("Filepath"))
path = self.resolve("Filepath")
if not path: return ""
abs_path = bpy.path.abspath(path)
if os.path.exists(abs_path):
@ -978,7 +976,7 @@ class SLICENODE_GcodeToFile(ExecSliceNode):
gcodes: list[str] = [gc for gc in self.resolve_multi_input('Gcode') if gc]
folder: str = resolve_input(self.inputs.get("Folder"))
folder: str = self.resolve("Folder")
if not gcodes:
if operator: operator.report({'ERROR'}, "No Gcode to save")
return 'error'
@ -1034,7 +1032,7 @@ class SLICENODE_GcodeToTextBlock(ExecSliceNode):
layout.prop(self, "text_block_name")
def evaluate(self, operator=None):
gcode: str = resolve_input(self.inputs.get("Gcode"))
gcode: str = self.resolve("Gcode")
if not gcode:
return 'ok'
@ -1075,8 +1073,8 @@ class SLICENODE_StartPrint(ExecSliceNode):
import tempfile
from pathlib import Path
gcode: str = resolve_input(self.inputs.get("Gcode"))
config: PrinterConfig | None = resolve_input(self.inputs.get("Printer"))
gcode: str = self.resolve("Gcode")
config: PrinterConfig | None = self.resolve("Printer")
if not gcode:
if operator: operator.report({'ERROR'}, "No Gcode to send")
@ -1327,10 +1325,10 @@ class SLICENODE_PrusaslicerSlice(SliceNode):
def evaluate(self, operator=None):
self.gcode_result = ""
mesh_data: SlicingCollection | SlicingGroup = resolve_input(self.inputs.get("Mesh"))
mesh_data: SlicingCollection | SlicingGroup = self.resolve("Mesh")
conf_data = resolve_input(self.inputs.get("Config"))
overrides = resolve_input(self.inputs.get("Overrides"))
conf_data = self.resolve("Config")
overrides = self.resolve("Overrides")
if not mesh_data:
if operator: operator.report({'ERROR'}, "No Mesh data connected")
@ -1376,6 +1374,7 @@ class SLICENODE_PrusaslicerSlice(SliceNode):
writer_overrides = {k: {'value': v} for k, v in overrides.items()}
# Generate the ConfigWriter
from ...infra.prusaslicer_profiles import ConfigWriter
conf_writer: ConfigWriter = cache.generate_conf_writer(
printer_id,
filament_ids,
@ -1391,6 +1390,7 @@ class SLICENODE_PrusaslicerSlice(SliceNode):
output_path = temp_dir / f"tmp.3mf"
try:
from ...infra._3mf_writer._3mf import prepare_3mf
prepare_3mf(output_path, slicing_group, conf_writer, z_gcodes=[])
# Actual slicing
@ -1630,5 +1630,5 @@ class SLICENODE_Test(ExecSliceNode):
self.add_input("SLICESOCK_Gcode")
def evaluate(self, operator=None):
_ = resolve_input(self.inputs.get("Gcode"))
_ = self.resolve("Gcode")
return 'ok'