diff options
-rw-r--r-- | gerber/cnc.py | 3 | ||||
-rwxr-xr-x | gerber/excellon.py | 96 | ||||
-rw-r--r-- | gerber/excellon_statements.py | 122 | ||||
-rw-r--r-- | gerber/gerber.py | 3 |
4 files changed, 173 insertions, 51 deletions
diff --git a/gerber/cnc.py b/gerber/cnc.py index aaa1a42..d17517a 100644 --- a/gerber/cnc.py +++ b/gerber/cnc.py @@ -92,7 +92,7 @@ class CncFile(object): decimal digits) """ - def __init__(self, settings=None, filename=None): + def __init__(self, statements=None, settings=None, filename=None): if settings is not None: self.notation = settings['notation'] self.units = settings['units'] @@ -103,6 +103,7 @@ class CncFile(object): self.units = 'inch' self.zero_suppression = 'trailing' self.format = (2, 5) + self.statements = statements if statements is not None else [] self.filename = filename @property diff --git a/gerber/excellon.py b/gerber/excellon.py index 6ae182b..45a8e4b 100755 --- a/gerber/excellon.py +++ b/gerber/excellon.py @@ -57,8 +57,8 @@ class ExcellonFile(CncFile): either 'inch' or 'metric'.
"""
- def __init__(self, tools, hits, settings, filename=None):
- super(ExcellonFile, self).__init__(settings, filename)
+ def __init__(self, statements, tools, hits, settings, filename=None):
+ super(ExcellonFile, self).__init__(statements, settings, filename)
self.tools = tools
self.hits = hits
@@ -98,14 +98,20 @@ class ExcellonParser(object): with open(filename, 'r') as f:
for line in f:
self._parse(line)
- return ExcellonFile(self.tools, self.hits, self._settings(), filename)
+ return ExcellonFile(self.statements, self.tools, self.hits, self._settings(), filename)
def dump(self, filename):
if self.ctx is not None:
self.ctx.dump(filename)
def _parse(self, line):
- if 'M48' in line:
+ zs = self._settings()['zero_suppression']
+ fmt = self._settings()['format']
+
+ if line[0] == ';':
+ self.statements.append(CommentStmt.from_excellon(line))
+
+ elif line[:3] == 'M48':
self.statements.append(HeaderBeginStmt())
self.state = 'HEADER'
@@ -114,56 +120,59 @@ class ExcellonParser(object): if self.state == 'HEADER':
self.state = 'DRILL'
- elif 'M95' in line:
+ elif line[:3] == 'M95':
self.statements.append(HeaderEndStmt())
if self.state == 'HEADER':
self.state = 'DRILL'
- elif 'G00' in line:
+ elif line[:3] == 'G00':
self.state = 'ROUT'
- elif 'G05' in line:
+ elif line[:3] == 'G05':
self.state = 'DRILL'
-
- if 'INCH' in line or line.strip() == 'M72':
- self.units = 'inch'
-
- elif 'METRIC' in line or line.strip() == 'M71':
- self.units = 'metric'
-
- if 'LZ' in line:
- self.zeros = 'L'
-
- elif 'TZ' in line:
- self.zeros = 'T'
-
- if 'ICI' in line and 'ON' in line or line.strip() == 'G91':
- self.notation = 'incremental'
-
- if 'ICI' in line and 'OFF' in line or line.strip() == 'G90':
- self.notation = 'incremental'
-
- zs = self._settings()['zero_suppression']
- fmt = self._settings()['format']
+
+ elif ('INCH' in line or 'METRIC' in line) and ('LZ' in line or 'TZ' in line):
+ stmt = UnitStmt.from_excellon(line)
+ self.units = stmt.units
+ self.zero_suppression = stmt.zero_suppression
+ self.statements.append(stmt)
+
+ elif line[:3] == 'M71' or line [:3] == 'M72':
+ stmt = MeasuringModeStmt.from_excellon(line)
+ self.units = stmt.units
+ self.statements.append(stmt)
+
+ elif line[:3] == 'ICI':
+ stmt = IncrementalModeStmt.from_excellon(line)
+ self.notation = 'incremental' if stmt.mode == 'on' else 'absolute'
+ self.statements.append(stmt)
# tool definition
- if line[0] == 'T' and self.state == 'HEADER':
- tool = ExcellonTool.from_line(line, self._settings())
+ elif line[0] == 'T' and self.state == 'HEADER':
+ tool = ExcellonTool.from_excellon(line, self._settings())
self.tools[tool.number] = tool
+ self.statements.append(tool)
elif line[0] == 'T' and self.state != 'HEADER':
- self.active_tool = self.tools[int(line.strip().split('T')[1])]
-
- if line[0] in ['X', 'Y']:
- x = None
- y = None
- if line[0] == 'X':
- splitline = line.strip('X').split('Y')
- x = parse_gerber_value(splitline[0].strip(), fmt, zs)
- if len(splitline) == 2:
- y = parse_gerber_value(splitline[1].strip(), fmt, zs)
- else:
- y = parse_gerber_value(line.strip(' Y'), fmt, zs)
+ stmt = ToolSelectionStmt.from_excellon(line)
+ self.active_tool self.tools[stmt.tool]
+ #self.active_tool = self.tools[int(line.strip().split('T')[1])]
+ self.statements.append(statement)
+
+ elif line[0] in ['X', 'Y']:
+ stmt = CoordinateStmt.from_excellon(line, fmt, zs)
+ x = stmt.x
+ y = stmt.y
+ self.statements.append(stmt)
+ #x = None
+ #y = None
+ #if line[0] == 'X':
+ # splitline = line.strip('X').split('Y')
+ # x = parse_gerber_value(splitline[0].strip(), fmt, zs)
+ # if len(splitline) == 2:
+ # y = parse_gerber_value(splitline[1].strip(), fmt, zs)
+ #else:
+ # y = parse_gerber_value(line.strip(' Y'), fmt, zs)
if self.notation == 'absolute':
if x is not None:
self.pos[0] = x
@@ -180,6 +189,9 @@ class ExcellonParser(object): if self.ctx is not None:
self.ctx.drill(self.pos[0], self.pos[1],
self.active_tool.diameter)
+
+ else:
+ self.statements.append(UnknownStmt.from_excellon(line))
def _settings(self):
return FileSettings(units=self.units, format=self.format,
diff --git a/gerber/excellon_statements.py b/gerber/excellon_statements.py index 4544f08..faadd20 100644 --- a/gerber/excellon_statements.py +++ b/gerber/excellon_statements.py @@ -18,13 +18,21 @@ from .utils import write_gerber_value -__all__ = ['ExcellonTool', 'CommentStmt', 'HeaderBeginStmt', 'HeaderEndStmt', +__all__ = ['ExcellonTool', 'ToolSelectionStatment', 'CoordinateStmt', + 'CommentStmt', 'HeaderBeginStmt', 'HeaderEndStmt', + 'RewindStopStmt', 'EndOfProgramStmt', 'UnitStmt', + 'IncrementalModeStmt', 'VersionStmt', 'FormatStmt', 'LinkToolStmt', + 'MeasuringModeStmt', 'UnknownStmt', ] class ExcellonStatement(object): """ Excellon Statement abstract base class """ + @classmethod + def from_excellon(cls, line): + pass + def to_excellon(self): pass @@ -74,7 +82,7 @@ class ExcellonTool(ExcellonStatement): """ @classmethod - def from_line(cls, line, settings): + def from_excellon(cls, line, settings): """ Create a Tool from an excellon file tool definition line. Parameters @@ -155,7 +163,62 @@ class ExcellonTool(ExcellonStatement): return '<ExcellonTool %d: %0.3f%s dia.>' % (self.number, self.diameter, unit) +class ToolSelectionStatment(ExcellonStatement): + + @classmethod + def from_excellon(cls, line): + line = line.strip()[1:] + compensation_index = None + tool = int(line[:2]) + if len(line) > 2: + compensation_index = int(line[2:]) + return cls(tool, compensation_index) + + def __init__(self, tool, compensation_index=None): + tool = int(tool) + compensation_index = int(compensation_index) if compensation_index else None + self.tool = tool + self.compensation_index = compensation_index + + def to_excellon(self): + stmt = 'T%02d' % self.tool + if self.compensation_index is not None: + stmt += '%02d' % self.compensation_index + return stmt + + +class CoordinateStmt(ExcellonStatement): + + def from_excellon(cls, line, format=(2, 5), zero_suppression='trailing'): + x = None + y = None + if line[0] == 'X': + splitline = line.strip('X').split('Y') + x = parse_gerber_value(splitline[0].strip(), format, zero_suppression) + if len(splitline) == 2: + y = parse_gerber_value(splitline[1].strip(), format, zero_suppression) + else: + y = parse_gerber_value(line.strip(' Y'), format, zero_suppression) + return cls(x, y) + + def __init__(self, x=None, y=None): + self.x = x + self.y = y + + def to_excellon(self): + stmt = '' + if self.x is not None: + stmt.append('X%s' % write_gerber_value(self.x)) + if self.y is not None: + stmt.append('Y%s' % write_gerber_value(self.y)) + return stmt + + class CommentStmt(ExcellonStatement): + + def from_excellon(self, line): + return cls(line.strip().lstrip(';')) + def __init__(self, comment): self.comment = comment @@ -206,6 +269,12 @@ class EndOfProgramStmt(ExcellonStatement): class UnitStmt(ExcellonStatement): + @classmethod + def from_excellon(cls, line): + units = 'inch' if 'INCH' in line else 'metric' + zero_suppression = 'trailing' if 'LZ' in line else 'leading' + return cls(units, zero_suppression) + def __init__(self, units='inch', zero_suppression='trailing'): self.units = units.lower() self.zero_suppression = zero_suppression @@ -217,6 +286,10 @@ class UnitStmt(ExcellonStatement): class IncrementalModeStmt(ExcellonStatement): + @classmethod + def from_excellon(cls, line): + return cls('off') if 'OFF' in line else cls('on') + def __init__(self, mode='off'): if mode.lower() not in ['on', 'off']: raise ValueError('Mode may be "on" or "off") @@ -228,16 +301,33 @@ class IncrementalModeStmt(ExcellonStatement): class VersionStmt(ExcellonStatement): + @classmethod + def from_excellon(cls, line): + version = int(line.split(',')[1]) + return cls(version) + def __init__(self, version=1): - self.version = int(version) + version = int(version) + if version not in [1, 2]: + raise ValueError('Valid versions are 1 or 2' + self.version = version def to_excellon(self): return 'VER,%d' % self.version class FormatStmt(ExcellonStatement): + + @classmethod + def from_excellon(cls, line): + fmt = int(line.split(',')[1]) + return cls(fmt) + def __init__(self, format=1): - self.format = int(format) + format = int(format) + if format not in [1, 2]: + raise ValueError('Valid formats are 1 or 2') + self.format = format def to_excellon(self): return 'FMAT,%d' % self.format @@ -245,6 +335,11 @@ class FormatStmt(ExcellonStatement): class LinkToolStmt(ExcellonStatement): + @classmethod + def from_excellon(cls, line): + linked = [int(tool) for tool in line.strip().split('/')] + return cls(linked) + def __init__(self, linked_tools): self.linked_tools = [int(x) for x in linked_tools] @@ -253,14 +348,29 @@ class LinkToolStmt(ExcellonStatement): class MeasuringModeStmt(ExcellonStatement): - + + @classmethod + def from_excellon(cls, line): + return cls('inch') if 'M72' in line else cls('metric') + def __init__(self, units='inch'): units = units.lower() if units not in ['inch', 'metric']: raise ValueError('units must be "inch" or "metric"') self.units = units - + def to_excellon(self): return 'M72' if self.units == 'inch' else 'M71' +class UnknownStmt(ExcellonStatement): + + @classmethod + def from_excellon(cls, line): + return cls(line) + + def __init__(self, stmt): + self.stmt = stmt + + def to_excellon(self): + return self.stmt diff --git a/gerber/gerber.py b/gerber/gerber.py index 9ad5dc9..0278b0d 100644 --- a/gerber/gerber.py +++ b/gerber/gerber.py @@ -68,8 +68,7 @@ class GerberFile(CncFile): """ def __init__(self, statements, settings, filename=None): - super(GerberFile, self).__init__(settings, filename) - self.statements = statements + super(GerberFile, self).__init__(statements, settings, filename) @property def comments(self): |