143 lines
4.9 KiB
Python
143 lines
4.9 KiB
Python
from __future__ import annotations
|
|
import math
|
|
from typing import Any
|
|
|
|
|
|
def parse_gcode_preview_geometry(
|
|
gcode: str,
|
|
scale_factor: float = 0.001,
|
|
scale_length: float = 1.0,
|
|
show_e_0: bool = False,
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Parses G-code text and extracts vertices, edges, and e_rates for mesh preview generation.
|
|
Returns a dict with:
|
|
vertices: list[tuple[float, float, float]]
|
|
edges: list[tuple[int, int]]
|
|
e_rates: list[float]
|
|
default_layer_height: float
|
|
prep_translation: list[float]
|
|
prep_rotation: list[float]
|
|
prep_scale: list[float]
|
|
"""
|
|
vertices: list[tuple[float, float, float]] = []
|
|
edges: list[tuple[int, int]] = []
|
|
e_rates: list[float] = []
|
|
|
|
last_x, last_y, last_z = 0.0, 0.0, 0.0
|
|
last_e = 0.0
|
|
|
|
offset_x, offset_y = 0.0, 0.0
|
|
custom_default_extrusion_rate = 0.0
|
|
default_layer_height = 0.2
|
|
default_layer_width = 0.4
|
|
|
|
last_v_idx = -1
|
|
last_p2 = None
|
|
|
|
prep_translation = [0.0, 0.0, 0.0]
|
|
prep_rotation = [0.0, 0.0, 0.0]
|
|
prep_scale = [1.0, 1.0, 1.0]
|
|
|
|
for line in gcode.splitlines():
|
|
# Parse metadata from comments
|
|
if ';' in line:
|
|
comment = line.split(';', 1)[1].strip()
|
|
if comment.startswith("OFFSET_X="):
|
|
try: offset_x = float(comment.split('=')[1])
|
|
except ValueError: pass
|
|
elif comment.startswith("OFFSET_Y="):
|
|
try: offset_y = float(comment.split('=')[1])
|
|
except ValueError: pass
|
|
elif comment.startswith("DEFAULT_EXTRUSION_RATE="):
|
|
try: custom_default_extrusion_rate = float(comment.split('=')[1])
|
|
except ValueError: pass
|
|
elif comment.startswith("DEFAULT_LAYER_HEIGHT="):
|
|
try: default_layer_height = float(comment.split('=')[1])
|
|
except ValueError: pass
|
|
elif comment.startswith("DEFAULT_LAYER_WIDTH="):
|
|
try: default_layer_width = float(comment.split('=')[1])
|
|
except ValueError: pass
|
|
elif comment.startswith("PREPARATION_TOTAL_TRANSLATION="):
|
|
try:
|
|
vals = [float(v) for v in comment.split('=')[1].split(',')]
|
|
if len(vals) >= 3: prep_translation = vals[:3]
|
|
except ValueError: pass
|
|
elif comment.startswith("PREPARATION_TOTAL_ROTATION="):
|
|
try:
|
|
vals = [float(v) for v in comment.split('=')[1].split(',')]
|
|
if len(vals) >= 3: prep_rotation = vals[:3]
|
|
except ValueError: pass
|
|
elif comment.startswith("PREPARATION_TOTAL_SCALE="):
|
|
try:
|
|
vals = [float(v) for v in comment.split('=')[1].split(',')]
|
|
if len(vals) >= 3: prep_scale = vals[:3]
|
|
except ValueError: pass
|
|
|
|
line_no_comment = line.split(';')[0].strip()
|
|
if not line_no_comment: continue
|
|
|
|
parts = line_no_comment.split()
|
|
if not parts: continue
|
|
cmd = parts[0].upper()
|
|
|
|
params = {}
|
|
for p in parts[1:]:
|
|
if len(p) < 2: continue
|
|
try:
|
|
val = float(p[1:])
|
|
if p[0].upper() in 'XYZ':
|
|
val *= scale_factor
|
|
params[p[0].upper()] = val
|
|
except ValueError: continue
|
|
|
|
new_x = params.get('X', last_x)
|
|
new_y = params.get('Y', last_y)
|
|
new_z = params.get('Z', last_z)
|
|
new_e = params.get('E', last_e)
|
|
|
|
show = False
|
|
if show_e_0: show = True
|
|
if cmd == 'G1' and new_e > 0: show = True
|
|
|
|
if show:
|
|
ox, oy = offset_x * scale_factor, offset_y * scale_factor
|
|
p1 = (last_x - ox, last_y - oy, last_z)
|
|
p2 = (new_x - ox, new_y - oy, new_z)
|
|
|
|
seg_len_mm = math.dist(p1, p2) * (1000.0 * scale_length)
|
|
if seg_len_mm > 0 and custom_default_extrusion_rate > 0:
|
|
e_rate = (new_e / seg_len_mm) / custom_default_extrusion_rate
|
|
else:
|
|
e_rate = 1.0
|
|
|
|
if last_v_idx != -1 and p1 == last_p2:
|
|
v2_idx = len(vertices)
|
|
vertices.append(p2)
|
|
edges.append((last_v_idx, v2_idx))
|
|
last_v_idx = v2_idx
|
|
else:
|
|
v1_idx = len(vertices)
|
|
v2_idx = v1_idx + 1
|
|
vertices.extend([p1, p2])
|
|
edges.append((v1_idx, v2_idx))
|
|
last_v_idx = v2_idx
|
|
|
|
e_rates.append(e_rate)
|
|
last_p2 = p2
|
|
else:
|
|
last_v_idx = -1
|
|
last_p2 = None
|
|
|
|
last_x, last_y, last_z = new_x, new_y, new_z
|
|
last_e = new_e
|
|
|
|
return {
|
|
"vertices": vertices,
|
|
"edges": edges,
|
|
"e_rates": e_rates,
|
|
"default_layer_height": default_layer_height,
|
|
"prep_translation": prep_translation,
|
|
"prep_rotation": prep_rotation,
|
|
"prep_scale": prep_scale,
|
|
}
|