From 8cd842a41a55ab3d8f558a2e3e198beba7da58a1 Mon Sep 17 00:00:00 2001 From: Hamilton Kibbe Date: Thu, 21 Jan 2016 03:57:44 -0500 Subject: Manually mere rendering changes --- gerber/excellon.py | 94 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 40 deletions(-) (limited to 'gerber/excellon.py') 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 -- cgit