diff options
Diffstat (limited to 'gerber/render/excellon_backend.py')
-rw-r--r-- | gerber/render/excellon_backend.py | 130 |
1 files changed, 119 insertions, 11 deletions
diff --git a/gerber/render/excellon_backend.py b/gerber/render/excellon_backend.py index bec8367..b2c213f 100644 --- a/gerber/render/excellon_backend.py +++ b/gerber/render/excellon_backend.py @@ -1,31 +1,62 @@ 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.end = [EndOfProgramStmt()] + self.start = [HeaderBeginStmt()] + # Current tool and position self.handled_tools = set() self.cur_tool = None - self.pos = (None, None) + self.drill_mode = ExcellonContext.MODE_DRILL + self.drill_down = False + self._pos = (None, None) self.settings = settings - self._start_header(settings) + self._start_header() + self._start_comments() - def _start_header(self, settings): - pass + def _start_header(self): + """Create the header from the settings""" + + self.header.append(UnitStmt.from_settings(self.settings)) + + def _start_comments(self): + + # 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.comments + self.header + 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 @@ -61,15 +92,92 @@ class ExcellonContext(GerberContext): def _render_drill(self, drill, color): - if not drill in self.handled_tools: - self.tool_def.append(drill.tool) + 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) + self.header.append(ExcellonTool.from_tool(tool)) - if drill.tool != self.cur_tool: - self.body.append(ToolSelectionStmt(drill.tool.number)) + if tool != self.cur_tool: + self.body.append(ToolSelectionStmt(tool.number)) + self.cur_tool = tool point = self._simplify_point(drill.position) self._pos = drill.position - self.body.append(CoordinateStmt.from_point()) + 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 + + # 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 |