120 lines
3.8 KiB
Python
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 ""
|