From 288f49955ecc1a811752aa4b1e713f9954e3033b Mon Sep 17 00:00:00 2001 From: Garret Fick Date: Sun, 27 Mar 2016 14:24:11 +0800 Subject: Actually fix the rout rendering to be correct --- gerber/render/excellon_backend.py | 98 +++++++++++++++++++++++++++++++++++---- 1 file changed, 89 insertions(+), 9 deletions(-) (limited to 'gerber/render') diff --git a/gerber/render/excellon_backend.py b/gerber/render/excellon_backend.py index eb79f1b..b2c213f 100644 --- a/gerber/render/excellon_backend.py +++ b/gerber/render/excellon_backend.py @@ -1,21 +1,29 @@ from .render import GerberContext +from ..excellon import DrillSlot from ..excellon_statements import * class ExcellonContext(GerberContext): + MODE_DRILL = 1 + MODE_SLOT =2 + def __init__(self, settings): GerberContext.__init__(self) + + # Statements that we write self.comments = [] self.header = [] self.tool_def = [] self.body_start = [RewindStopStmt()] self.body = [] self.start = [HeaderBeginStmt()] - self.end = [EndOfProgramStmt()] + # Current tool and position self.handled_tools = set() self.cur_tool = None + self.drill_mode = ExcellonContext.MODE_DRILL + self.drill_down = False self._pos = (None, None) self.settings = settings @@ -33,9 +41,22 @@ class ExcellonContext(GerberContext): # Write the digits used - this isn't valid Excellon statement, so we write as a comment self.comments.append(CommentStmt('FILE_FORMAT=%d:%d' % (self.settings.format[0], self.settings.format[1]))) + def _get_end(self): + """How we end depends on our mode""" + + end = [] + + if self.drill_down: + end.append(RetractWithClampingStmt()) + end.append(RetractWithoutClampingStmt()) + + end.append(EndOfProgramStmt()) + + return end + @property def statements(self): - return self.start + self.comments + self.header + self.body_start + self.body + self.end + return self.start + self.comments + self.header + self.body_start + self.body + self._get_end() def set_bounds(self, bounds): pass @@ -71,6 +92,9 @@ class ExcellonContext(GerberContext): def _render_drill(self, drill, color): + if self.drill_mode != ExcellonContext.MODE_DRILL: + self._start_drill_mode() + tool = drill.hit.tool if not tool in self.handled_tools: self.handled_tools.add(tool) @@ -84,20 +108,76 @@ class ExcellonContext(GerberContext): self._pos = drill.position self.body.append(CoordinateStmt.from_point(point)) + def _start_drill_mode(self): + """ + If we are not in drill mode, then end the ROUT so we can do basic drilling + """ + + if self.drill_mode == ExcellonContext.MODE_SLOT: + + # Make sure we are retracted before changing modes + last_cmd = self.body[-1] + if self.drill_down: + self.body.append(RetractWithClampingStmt()) + self.body.append(RetractWithoutClampingStmt()) + self.drill_down = False + + # Switch to drill mode + self.body.append(DrillModeStmt()) + self.drill_mode = ExcellonContext.MODE_DRILL + + else: + raise ValueError('Should be in slot mode') + def _render_slot(self, slot, color): + # Set the tool first, before we might go into drill mode tool = slot.hit.tool if not tool in self.handled_tools: self.handled_tools.add(tool) self.header.append(ExcellonTool.from_tool(tool)) - - if tool != self.cur_tool: - self.body.append(ToolSelectionStmt(tool.number)) - self.cur_tool = tool - # Slots don't use simplified points - self._pos = slot.end - self.body.append(SlotStmt.from_points(slot.start, slot.end)) + if tool != self.cur_tool: + self.body.append(ToolSelectionStmt(tool.number)) + self.cur_tool = tool + + # Two types of drilling - normal drill and slots + if slot.hit.slot_type == DrillSlot.TYPE_ROUT: + + # For ROUT, setting the mode is part of the actual command. + + # Are we in the right position? + if slot.start != self._pos: + if self.drill_down: + # We need to move into the right position, so retract + self.body.append(RetractWithClampingStmt()) + self.drill_down = False + + # Move to the right spot + point = self._simplify_point(slot.start) + self._pos = slot.start + self.body.append(CoordinateStmt.from_point(point, mode="ROUT")) + + # Now we are in the right spot, so drill down + if not self.drill_down: + self.body.append(ZAxisRoutPositionStmt()) + self.drill_down = True + + # Do a linear move from our current position to the end position + point = self._simplify_point(slot.end) + self._pos = slot.end + self.body.append(CoordinateStmt.from_point(point, mode="LINEAR")) + + self.drill_down = ExcellonContext.MODE_SLOT + + else: + # This is a G85 slot, so do this in normally drilling mode + if self.drill_mode != ExcellonContext.MODE_DRILL: + self._start_drill_mode() + + # Slots don't use simplified points + self._pos = slot.end + self.body.append(SlotStmt.from_points(slot.start, slot.end)) def _render_inverted_layer(self): pass -- cgit