summaryrefslogtreecommitdiff
path: root/gerber/excellon.py
diff options
context:
space:
mode:
authorPaulo Henrique Silva <ph.silva@gmail.com>2015-01-14 14:33:00 -0200
committerPaulo Henrique Silva <ph.silva@gmail.com>2015-01-14 14:33:00 -0200
commit137c73f3e42281de67bde8f1c0b16938f5b8aeeb (patch)
tree1c3140276d1f1b0cd16aec36d89cac183bf059d6 /gerber/excellon.py
parentac89a3c36505bebff68305eb8e315482cba860fd (diff)
downloadgerbonara-137c73f3e42281de67bde8f1c0b16938f5b8aeeb.tar.gz
gerbonara-137c73f3e42281de67bde8f1c0b16938f5b8aeeb.tar.bz2
gerbonara-137c73f3e42281de67bde8f1c0b16938f5b8aeeb.zip
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.
Diffstat (limited to 'gerber/excellon.py')
-rwxr-xr-xgerber/excellon.py51
1 files changed, 32 insertions, 19 deletions
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 <ham@hamiltonkib.be>
-
+
# 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: