summaryrefslogtreecommitdiff
path: root/gerber/excellon.py
diff options
context:
space:
mode:
Diffstat (limited to 'gerber/excellon.py')
-rwxr-xr-xgerber/excellon.py94
1 files changed, 54 insertions, 40 deletions
diff --git a/gerber/excellon.py b/gerber/excellon.py
index a0bad4f..a5da42a 100755
--- a/gerber/excellon.py
+++ b/gerber/excellon.py
@@ -81,7 +81,7 @@ def loads(data, settings = None, tools = None):
return ExcellonParser(settings, tools).parse_raw(data)
-class DrillHit(object):
+class DrillHit(object):
"""Drill feature that is a single drill hole.
Attributes
@@ -92,6 +92,7 @@ class DrillHit(object):
Center position of the drill.
"""
+
def __init__(self, tool, position):
self.tool = tool
self.position = position
@@ -184,6 +185,7 @@ class ExcellonFile(CamFile):
either 'inch' or 'metric'.
"""
+
def __init__(self, statements, tools, hits, settings, filename=None):
super(ExcellonFile, self).__init__(statements=statements,
settings=settings,
@@ -193,7 +195,9 @@ class ExcellonFile(CamFile):
@property
def primitives(self):
-
+ """
+ Gets the primitives. Note that unlike Gerber, this generates new objects
+ """
primitives = []
for hit in self.hits:
if isinstance(hit, DrillHit):
@@ -203,8 +207,7 @@ class ExcellonFile(CamFile):
else:
raise ValueError('Unknown hit type')
- return primitives
-
+ return primitives
@property
def bounds(self):
@@ -237,7 +240,8 @@ class ExcellonFile(CamFile):
rprt += ' Code Size Hits Path Length\n'
rprt += ' --------------------------------------\n'
for tool in iter(self.tools.values()):
- rprt += toolfmt.format(tool.number, tool.diameter, tool.hit_count, self.path_length(tool.number))
+ rprt += toolfmt.format(tool.number, tool.diameter,
+ tool.hit_count, self.path_length(tool.number))
if filename is not None:
with open(filename, 'w') as f:
f.write(rprt)
@@ -245,13 +249,21 @@ class ExcellonFile(CamFile):
def write(self, filename=None):
filename = filename if filename is not None else self.filename
- with open(filename, 'w') as f:
- self.writes(f)
-
- def writes(self, f):
- # Copy the header verbatim
- for statement in self.statements:
- f.write(statement.to_excellon(self.settings) + '\n')
+ with open(filename, 'w') as f:
+ for statement in self.statements:
+ if not isinstance(statement, ToolSelectionStmt):
+ f.write(statement.to_excellon(self.settings) + '\n')
+ else:
+ break
+
+ # Write out coordinates for drill hits by tool
+ for tool in iter(self.tools.values()):
+ f.write(ToolSelectionStmt(tool.number).to_excellon(self.settings) + '\n')
+ for hit in self.hits:
+ if hit.tool.number == tool.number:
+ f.write(CoordinateStmt(
+ *hit.position).to_excellon(self.settings) + '\n')
+ f.write(EndOfProgramStmt().to_excellon() + '\n')
def to_inch(self):
"""
@@ -265,9 +277,8 @@ class ExcellonFile(CamFile):
tool.to_inch()
for primitive in self.primitives:
primitive.to_inch()
- for hit in self.hits:
- hit.to_inch()
-
+ for hit in self.hits:
+ hit.to_inch()
def to_metric(self):
""" Convert units to metric
@@ -288,8 +299,8 @@ class ExcellonFile(CamFile):
statement.offset(x_offset, y_offset)
for primitive in self.primitives:
primitive.offset(x_offset, y_offset)
- for hit in self. hits:
- hit.offset(x_offset, y_offset)
+ for hit in self. hits:
+ hit.offset(x_offset, y_offset)
def path_length(self, tool_number=None):
""" Return the path length for a given tool
@@ -299,9 +310,11 @@ class ExcellonFile(CamFile):
for hit in self.hits:
tool = hit.tool
num = tool.number
- positions[num] = (0, 0) if positions.get(num) is None else positions[num]
+ positions[num] = (0, 0) if positions.get(
+ num) is None else positions[num]
lengths[num] = 0.0 if lengths.get(num) is None else lengths[num]
- lengths[num] = lengths[num] + math.hypot(*tuple(map(operator.sub, positions[num], hit.position)))
+ lengths[num] = lengths[
+ num] + math.hypot(*tuple(map(operator.sub, positions[num], hit.position)))
positions[num] = hit.position
if tool_number is None:
@@ -310,13 +323,13 @@ class ExcellonFile(CamFile):
return lengths.get(tool_number)
def hit_count(self, tool_number=None):
- counts = {}
- for tool in iter(self.tools.values()):
- counts[tool.number] = tool.hit_count
- if tool_number is None:
- return counts
- else:
- return counts.get(tool_number)
+ counts = {}
+ for tool in iter(self.tools.values()):
+ counts[tool.number] = tool.hit_count
+ if tool_number is None:
+ return counts
+ else:
+ return counts.get(tool_number)
def update_tool(self, tool_number, **kwargs):
""" Change parameters of a tool
@@ -340,7 +353,6 @@ class ExcellonFile(CamFile):
hit.tool = newtool
-
class ExcellonParser(object):
""" Excellon File Parser
@@ -348,8 +360,8 @@ class ExcellonParser(object):
----------
settings : FileSettings or dict-like
Excellon file settings to use when interpreting the excellon file.
- """
- def __init__(self, settings=None, ext_tools=None):
+ """
+ def __init__(self, settings=None, ext_tools=None):
self.notation = 'absolute'
self.units = 'inch'
self.zeros = 'leading'
@@ -371,7 +383,6 @@ class ExcellonParser(object):
self.notation = settings.notation
self.format = settings.format
-
@property
def coordinates(self):
return [(stmt.x, stmt.y) for stmt in self.statements if isinstance(stmt, CoordinateStmt)]
@@ -421,7 +432,8 @@ class ExcellonParser(object):
# 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(":")])
+ detected_format = tuple(
+ [int(x) for x in comment_stmt.comment.split('=')[1].split(":")])
if detected_format:
self.format = detected_format
@@ -553,7 +565,7 @@ class ExcellonParser(object):
self.format = stmt.format
self.statements.append(stmt)
- elif line[:3] == 'M71' or line [:3] == 'M72':
+ elif line[:3] == 'M71' or line[:3] == 'M72':
stmt = MeasuringModeStmt.from_excellon(line)
self.units = stmt.units
self.statements.append(stmt)
@@ -603,20 +615,22 @@ class ExcellonParser(object):
self.statements.append(stmt)
# T0 is used as END marker, just ignore
- if stmt.tool != 0:
+ if stmt.tool != 0:
tool = self._get_tool(stmt.tool)
if not tool:
- # FIXME: for weird files with no tools defined, original calc from gerbv
+ # FIXME: for weird files with no tools defined, original calc from gerbv
if self._settings().units == "inch":
- diameter = (16 + 8 * stmt.tool) / 1000.0;
+ diameter = (16 + 8 * stmt.tool) / 1000.0
else:
- diameter = metric((16 + 8 * stmt.tool) / 1000.0);
+ diameter = metric((16 + 8 * stmt.tool) / 1000.0)
- tool = ExcellonTool(self._settings(), number=stmt.tool, diameter=diameter)
+ tool = ExcellonTool(
+ self._settings(), number=stmt.tool, diameter=diameter)
self.tools[tool.number] = tool
- # FIXME: need to add this tool definition inside header to make sure it is properly written
+ # FIXME: need to add this tool definition inside header to
+ # make sure it is properly written
for i, s in enumerate(self.statements):
if isinstance(s, ToolSelectionStmt) or isinstance(s, ExcellonTool):
self.statements.insert(i, tool)
@@ -787,7 +801,7 @@ def detect_excellon_format(data=None, filename=None):
and 'FILE_FORMAT' in stmt.comment]
detected_format = (tuple([int(val) for val in
- format_comment[0].split('=')[1].split(':')])
+ format_comment[0].split('=')[1].split(':')])
if len(format_comment) == 1 else None)
detected_zeros = zero_statements[0] if len(zero_statements) == 1 else None
@@ -852,6 +866,6 @@ def _layer_size_score(size, hole_count, hole_area):
hole_percentage = hole_area / board_area
hole_score = (hole_percentage - 0.25) ** 2
- size_score = (board_area - 8) **2
+ size_score = (board_area - 8) ** 2
return hole_score * size_score
\ No newline at end of file