summaryrefslogtreecommitdiff
path: root/gerber/render/excellon_backend.py
diff options
context:
space:
mode:
Diffstat (limited to 'gerber/render/excellon_backend.py')
-rw-r--r--gerber/render/excellon_backend.py130
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