nodeslicer/core/functions/gcode_functions.py
2026-10-15 14:13:39 +03:00

120 lines
3.8 KiB
Python

from __future__ import annotations
import os
import re
from typing import Any
import bpy
from ..slice import Pather
from ...infra.blender.list_utils import flatten_list, is_list_data
def paths_to_gcode(p: Any, intr: Any, use_header: bool = True) -> str:
if not p:
return ""
pather: Pather = Pather(p)
if hasattr(p, "layer_height"):
pather.layer_height = getattr(p, "layer_height")
if hasattr(p, "first_layer_height"):
pather.first_layer_height = getattr(p, "first_layer_height")
if intr:
pather.bed_center_x = intr.bed_x / 2.0
pather.bed_center_y = intr.bed_y / 2.0
pather.feedrate = intr.feedrate
pather.travel_feedrate = intr.travel_feedrate
pather.extrusion_rate = intr.extrusion_rate
pather.retraction = intr.retraction
pather.retraction_feedrate = getattr(intr, "retraction_feedrate", 0.0)
pather.lift = intr.lift
return pather.to_gcode(include_header=use_header)
def format_gcode_metadata(name: Any, filament_type: Any, printer_model: Any) -> str:
lines = []
if name:
lines.append(f'; objects_info = {{"objects": [{{"name": "{name}", "polygon": []}}]}}')
if filament_type:
lines.append(f'; filament_type = {filament_type}')
if printer_model:
lines.append(f'; printer_model = {printer_model}')
return '\n'.join(lines)
def regex_replace_gcode(gc: Any, find_pattern: Any, replace_pattern: Any, node_name: str = "") -> str:
gc_str = str(gc or "")
f_str = str(find_pattern or "")
r_str = str(replace_pattern or "")
if not f_str or not gc_str:
return gc_str
try:
def subst(match):
if match.group(1):
return '$'
elif match.group(2):
return '\\g<' + match.group(2) + '>'
elif match.group(3):
return '\\g<' + match.group(3) + '>'
return match.group(0)
rep = re.sub(r'(\$\$)|(?:\$\{([^}]+)\})|(?:\$([a-zA-Z0-9_]+))', subst, r_str)
return re.sub(f_str, rep, gc_str)
except Exception as e:
if node_name:
print(f"Regex error in node {node_name}: {e}")
return gc_str
def format_gcode_command(command: str, parameters: str = "") -> str:
cmd = command
params = parameters.strip()
if params:
if cmd == 'T':
return f"{cmd}{params}"
return f"{cmd} {params}"
return cmd
def join_gcode_inputs(raw_inputs: list[Any]) -> Any:
has_list = any(is_list_data(inp) for inp in raw_inputs)
if not has_list:
flattened = flatten_list(raw_inputs)
gcode_input: list[str] = [str(gc) for gc in flattened if gc]
return "\n".join(gcode_input)
# There is at least one list input
list_lengths = [len(inp) for inp in raw_inputs if is_list_data(inp)]
if len(set(list_lengths)) > 1:
raise ValueError(
f"Join Gcode: all input lists must have the same length, got lengths {list_lengths}"
)
n_elements = list_lengths[0] if list_lengths else 0
result: list[str] = []
for i in range(n_elements):
row_parts: list[str] = []
for inp in raw_inputs:
if is_list_data(inp):
val = inp[i]
else:
val = inp
if is_list_data(val):
val_str = "\n".join(str(s) for s in flatten_list(val) if s)
if val_str:
row_parts.append(val_str)
elif val:
row_parts.append(str(val))
result.append("\n".join(row_parts))
return result
def load_gcode_file(path: str) -> str:
if not path:
return ""
abs_path = bpy.path.abspath(path)
if os.path.exists(abs_path):
with open(abs_path, 'r', encoding='utf-8') as f:
return f.read()
return ""