From c8bf837a4b5dcc6242b7dac383f09e9390deca35 Mon Sep 17 00:00:00 2001 From: jaseg Date: Sun, 30 Jan 2022 15:07:55 +0100 Subject: Fix some more testcases * Fix Excellon export among others --- gerbonara/gerber/ipc356.py | 64 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 12 deletions(-) (limited to 'gerbonara/gerber/ipc356.py') diff --git a/gerbonara/gerber/ipc356.py b/gerbonara/gerber/ipc356.py index 043f2ab..dc3773b 100644 --- a/gerbonara/gerber/ipc356.py +++ b/gerbonara/gerber/ipc356.py @@ -25,12 +25,12 @@ from dataclasses import dataclass, KW_ONLY from pathlib import Path from .cam import CamFile, FileSettings -from .utils import MM, Inch, LengthUnit +from .utils import MM, Inch, LengthUnit, rotate_point class Netlist(CamFile): def __init__(self, test_records=None, conductors=None, outlines=None, comments=None, adjacency=None, - params=None, import_settings=None, original_path=None): + params=None, import_settings=None, original_path=None, generator_hints=None): super().__init__(original_path=original_path, layer_name='netlist', import_settings=import_settings) self.test_records = test_records or [] self.conductors = conductors or [] @@ -38,10 +38,14 @@ class Netlist(CamFile): self.comments = comments or [] self.adjacency = adjacency or {} self.params = params or {} + self.generator_hints = generator_hints or [] def merge(self, other, our_prefix=None, their_prefix=None): ''' Merge other netlist into this netlist. The respective net names are prefixed with the given prefixes (default: None). Garbles other. ''' + if other is None: + return + if not isinstance(other, Netlist): raise TypeError(f'Can only merge Netlist with other Netlist, not {type(other)}') @@ -80,12 +84,14 @@ class Netlist(CamFile): self.adjacency = new_adjacency def offset(self, dx=0, dy=0, unit=MM): - # FIXME - pass + for obj in self.objects: + obj.offset(dx, dy, unit) def rotate(self, angle:'radian', center=(0,0), unit=MM): - # FIXME - pass + cx, cy = center + + for obj in self.objects: + obj.rotate(angle, cx, cy, unit) @property def objects(self): @@ -232,7 +238,7 @@ class NetlistParser(object): self.adjacency = {} self.outlines = [] self.eof = False - self.generator = None + self.generator_hints = [] def warn(self, msg, kls=SyntaxWarning): warnings.warn(f'{self.filename}:{self.start_line}: {msg}', kls) @@ -264,7 +270,8 @@ class NetlistParser(object): raise SyntaxError(f'Error parsing {self.filename}:{lineno}: {e}') from e return Netlist(self.test_records, self.conductors, self.outlines, self.comments, self.adjacency, - params=self.params, import_settings=self.settings, original_path=path) + params=self.params, import_settings=self.settings, original_path=path, + generator_hints=self.generator_hints) def _parse_line(self, line): if not line: @@ -278,7 +285,7 @@ class NetlistParser(object): # +-- sic! # v if 'Ouptut' in line and 'Allegro' in line: - self.generator = 'allegro' + self.generator_hints.append('allegro') elif 'Ouptut' not in line and 'Allegro' in line: self.warn('This seems to be a file generated by a newer allegro version. Please raise an issue on our ' @@ -286,13 +293,13 @@ class NetlistParser(object): 'so we can improve Gerbonara!') elif 'EAGLE' in line and 'CadSoft' in line: - self.generator = 'eagle' + self.generator_hints.append('eagle') if line.strip().startswith('NNAME'): name, *value = line.strip().split() value = ' '.join(value) self.warn('File contains non-standard Allegro-style net name alias definitions in comments.') - if self.generator == 'allegro': + if 'allegro' in self.generator_hints: # it's amazing how allegro always seems to have found a way to do the same thing everyone else is # doing just in a different, slightly more messed up, completely incompatible way. self.net_names[name] = value[5:] # strip NNAME because Allegro @@ -328,7 +335,7 @@ class NetlistParser(object): raise SyntaxError(f'Unsupported IPC-356 netlist unit specification "{line}"') elif name.startswith('NNAME'): - if self.generator == 'allegro': + if 'allegro' in self.generator_hints: self.net_names[name] = value[5:] else: @@ -406,6 +413,19 @@ class TestRecord: y = self.unit.format(self.y) return f'' + def rotate(self, angle, cx=0, cy=0, unit=None): + cx = self.unit(cx, unit) + cy = self.unit(cy, unit) + + self.angle += angle + self.x, self.y = rotate_point(self.x, self.y, angle, center=(cx, cy)) + + def offset(self, dx=0, dy=0, unit=None): + dx = self.unit(dx, unit) + dy = self.unit(dy, unit) + self.x += dx + self.y += dy + @classmethod def parse(kls, line, settings, net_name_map={}): obj = kls() @@ -552,6 +572,16 @@ class Outline: def __str__(self): return f'' + def rotate(self, angle, cx=0, cy=0, unit=None): + cx = self.unit(cx, unit) + cy = self.unit(cy, unit) + self.outline = [ rotate_point(x, y, angle, center=(cx, cy)) for x, y in self.outline ] + + def offset(self, dx=0, dy=0, unit=None): + dx = self.unit(dx, unit) + dy = self.unit(dy, unit) + self.outline = [ (x+dx, y+dy) for x, y in self.outline ] + @dataclass class Conductor: @@ -588,3 +618,13 @@ class Conductor: def __str__(self): return f'' + def rotate(self, angle, cx=0, cy=0, unit=None): + cx = self.unit(cx, unit) + cy = self.unit(cy, unit) + self.coords = [ rotate_point(x, y, angle, center=(cx, cy)) for x, y in self.coords ] + + def offset(self, dx=0, dy=0, unit=None): + dx = self.unit(dx, unit) + dy = self.unit(dy, unit) + self.coords = [ (x+dx, y+dy) for x, y in self.coords ] + -- cgit