From 137c73f3e42281de67bde8f1c0b16938f5b8aeeb Mon Sep 17 00:00:00 2001 From: Paulo Henrique Silva Date: Wed, 14 Jan 2015 14:33:00 -0200 Subject: Many additions to Excellon parsing/creation. CAUTION: the original code used zero_suppression flags in the opposite sense as Gerber functions. This patch changes it to behave just like Gerber code. * Add metric/inch conversion support * Add settings context variable to to_gerber just like Gerber code. * Add some missing Excellon values. Tests are not entirely updated. --- gerber/excellon.py | 51 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 19 deletions(-) (limited to 'gerber/excellon.py') diff --git a/gerber/excellon.py b/gerber/excellon.py index 9d09576..ee38367 100755 --- a/gerber/excellon.py +++ b/gerber/excellon.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # Copyright 2014 Hamilton Kibbe - + # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -13,8 +13,8 @@ # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and -# limitations under the License. - +# limitations under the License. + """ Excellon File module ==================== @@ -28,6 +28,7 @@ from .excellon_statements import * from .cam import CamFile, FileSettings from .primitives import Drill import math +import re def read(filename): """ Read data from filename and return an ExcellonFile @@ -42,10 +43,7 @@ def read(filename): An ExcellonFile created from the specified file. """ - detected_settings = detect_excellon_format(filename) - settings = FileSettings(**detected_settings) - zeros = '' - return ExcellonParser(settings).parse(filename) + return ExcellonParser(None).parse(filename) class ExcellonFile(CamFile): @@ -104,7 +102,7 @@ class ExcellonFile(CamFile): def write(self, filename): with open(filename, 'w') as f: for statement in self.statements: - f.write(statement.to_excellon() + '\n') + f.write(statement.to_excellon(self.settings) + '\n') class ExcellonParser(object): @@ -118,14 +116,14 @@ class ExcellonParser(object): def __init__(self, settings=None): self.notation = 'absolute' self.units = 'inch' - self.zero_suppression = 'trailing' - self.format = (2, 5) + self.zero_suppression = 'leading' + self.format = (2, 4) self.state = 'INIT' self.statements = [] self.tools = {} self.hits = [] self.active_tool = None - self.pos = [0., 0.] + self.pos = [0., 0.] if settings is not None: self.units = settings.units self.zero_suppression = settings.zero_suppression @@ -166,11 +164,19 @@ class ExcellonParser(object): self._settings(), filename) def _parse(self, line): - #line = line.strip() - zs = self._settings().zero_suppression - fmt = self._settings().format + # skip empty lines + if not line.strip(): + return + if line[0] == ';': - self.statements.append(CommentStmt.from_excellon(line)) + comment_stmt = CommentStmt.from_excellon(line) + self.statements.append(comment_stmt) + + # get format from altium comment + if "FILE_FORMAT" in comment_stmt.comment: + detected_format = tuple([int(x) for x in comment_stmt.comment.split('=')[1].split(":")]) + if detected_format: + self.format = detected_format elif line[:3] == 'M48': self.statements.append(HeaderBeginStmt()) @@ -191,9 +197,11 @@ class ExcellonParser(object): self.statements.append(stmt) elif line[:3] == 'G00': + self.statements.append(RouteModeStmt()) self.state = 'ROUT' elif line[:3] == 'G05': + self.statements.append(DrillModeStmt()) self.state = 'DRILL' elif (('INCH' in line or 'METRIC' in line) and @@ -221,6 +229,9 @@ class ExcellonParser(object): stmt = FormatStmt.from_excellon(line) self.statements.append(stmt) + elif line[:4] == 'G90': + self.statements.append(AbsoluteModeStmt()) + elif line[0] == 'T' and self.state == 'HEADER': tool = ExcellonTool.from_excellon(line, self._settings()) self.tools[tool.number] = tool @@ -228,14 +239,16 @@ class ExcellonParser(object): elif line[0] == 'T' and self.state != 'HEADER': stmt = ToolSelectionStmt.from_excellon(line) - self.active_tool = self.tools[stmt.tool] + # T0 is used as END marker, just ignore + if stmt.tool != 0: + self.active_tool = self.tools[stmt.tool] self.statements.append(stmt) elif line[0] in ['X', 'Y']: - stmt = CoordinateStmt.from_excellon(line, fmt, zs) + stmt = CoordinateStmt.from_excellon(line, self._settings()) x = stmt.x y = stmt.y - self.statements.append(stmt) + self.statements.append(stmt) if self.notation == 'absolute': if x is not None: self.pos[0] = x @@ -246,7 +259,7 @@ class ExcellonParser(object): self.pos[0] += x if y is not None: self.pos[1] += y - if self.state == 'DRILL': + if self.state == 'DRILL': self.hits.append((self.active_tool, tuple(self.pos))) self.active_tool._hit() else: -- cgit