66 lines
1.9 KiB
Python
66 lines
1.9 KiB
Python
"""DXF output generator — AC1015+ DXF from PostProcessResult using ezdxf."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import io
|
|
|
|
import ezdxf
|
|
|
|
from pipeline.postprocess import PathInfo, PostProcessResult
|
|
|
|
|
|
def _add_path_to_msp(
|
|
msp: ezdxf.layouts.BaseLayout,
|
|
path: PathInfo,
|
|
layer: str = "0",
|
|
) -> None:
|
|
"""Add a single PathInfo as an LWPOLYLINE entity to the modelspace.
|
|
|
|
Closed paths get the LWPOLYLINE close flag set.
|
|
Islands are placed on a separate "ISLANDS" layer for downstream CAM tools.
|
|
"""
|
|
coords = path.simplified_coords
|
|
if len(coords) < 2:
|
|
return
|
|
|
|
target_layer = "ISLANDS" if path.is_island else layer
|
|
|
|
# LWPOLYLINE uses (x, y[, start_width, end_width, bulge]) tuples
|
|
points = [(x, y) for x, y in coords]
|
|
|
|
# Remove duplicate close point if the polyline close flag handles it
|
|
if path.is_closed and len(points) > 1 and points[0] == points[-1]:
|
|
points = points[:-1]
|
|
|
|
msp.add_lwpolyline(
|
|
points,
|
|
dxfattribs={"layer": target_layer},
|
|
close=path.is_closed,
|
|
)
|
|
|
|
|
|
def generate_dxf(result: PostProcessResult) -> bytes:
|
|
"""Generate an AC1015 (AutoCAD R2000) DXF file from post-processed path data.
|
|
|
|
Creates LWPOLYLINE entities from simplified coordinate data. Islands (holes)
|
|
are placed on an "ISLANDS" layer; outer contours on the default "0" layer.
|
|
|
|
Args:
|
|
result: PostProcessResult from the post-processing pipeline.
|
|
|
|
Returns:
|
|
DXF file content as bytes.
|
|
"""
|
|
doc = ezdxf.new(dxfversion="R2000") # AC1015
|
|
msp = doc.modelspace()
|
|
|
|
# Create ISLANDS layer for hole/island paths
|
|
doc.layers.add("ISLANDS", color=1) # color 1 = red in AutoCAD
|
|
|
|
for path in result.paths:
|
|
_add_path_to_msp(msp, path)
|
|
|
|
# Write to string buffer, then encode to bytes
|
|
stream = io.StringIO()
|
|
doc.write(stream)
|
|
return stream.getvalue().encode("utf-8")
|