From 572486aa25711a432ff08ff8fad8ad91670661b7 Mon Sep 17 00:00:00 2001 From: jaseg Date: Thu, 6 Jul 2023 22:42:39 +0200 Subject: kicad: Fix layers attribute handling and improve rotation API --- gerbonara/cad/kicad/base_types.py | 1 - gerbonara/cad/kicad/footprints.py | 17 +++++++++++++++-- gerbonara/cad/kicad/pcb.py | 4 ++++ gerbonara/cad/kicad/primitives.py | 27 ++++++++++++++++++++++++++- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/gerbonara/cad/kicad/base_types.py b/gerbonara/cad/kicad/base_types.py index fafb802..2a6f196 100644 --- a/gerbonara/cad/kicad/base_types.py +++ b/gerbonara/cad/kicad/base_types.py @@ -202,7 +202,6 @@ class TextEffect: hide: Flag() = False justify: OmitDefault(Justify) = field(default_factory=Justify) - @sexp_type('tstamp') class Timestamp: value: str = field(default_factory=uuid.uuid4) diff --git a/gerbonara/cad/kicad/footprints.py b/gerbonara/cad/kicad/footprints.py index 9772b55..aedf9b8 100644 --- a/gerbonara/cad/kicad/footprints.py +++ b/gerbonara/cad/kicad/footprints.py @@ -389,6 +389,12 @@ class Pad: _: SEXP_END = None footprint: object = None + def __after_parse__(self, parent=None): + self.layers = unfuck_layers(self.layers) + + def __before_sexp__(self): + self.layers = fuck_layers(self.layers) + def find_connected(self, **filters): """ Find footprints connected to the same net as this pad """ return self.footprint.board.find_footprints(net=self.net.name, **filters) @@ -677,12 +683,19 @@ class Footprint: x, y = self.at.x-cx, self.at.y-cy self.at.x = math.cos(angle)*x - math.sin(angle)*y + cx self.at.y = math.sin(angle)*x + math.cos(angle)*y + cy - - self.at.rotation -= math.degrees(angle) + self.at.rotation -= math.degrees(angle) for pad in self.pads: pad.at.rotation -= math.degrees(angle) + def set_rotation(self, angle): + old_deg = self.at.rotation + new_deg = self.at.rotation = -math.degrees(angle) + delta = new_deg - old_deg + + for pad in self.pads: + pad.at.rotation += delta + def objects(self, text=False, pads=True): return chain( (self.texts if text else []), diff --git a/gerbonara/cad/kicad/pcb.py b/gerbonara/cad/kicad/pcb.py index 2b28655..9ab00b3 100644 --- a/gerbonara/cad/kicad/pcb.py +++ b/gerbonara/cad/kicad/pcb.py @@ -251,6 +251,10 @@ class Board: def __before_sexp__(self): self.properties = [Property(key, value) for key, value in self.properties.items()] + def unfill_zones(self): + for zone in self.zones: + zone.unfill() + def find_pads(self, net=None): for fp in self.footprints: for pad in fp.pads: diff --git a/gerbonara/cad/kicad/primitives.py b/gerbonara/cad/kicad/primitives.py index 40cb22c..6e9f41d 100644 --- a/gerbonara/cad/kicad/primitives.py +++ b/gerbonara/cad/kicad/primitives.py @@ -1,10 +1,24 @@ import enum +import re from .sexp import * from .base_types import * +def unfuck_layers(layers): + if layers and layers[0] == 'F&B.Cu': + return ['F.Cu', 'B.Cu', *layers[1:]] + else: + return layers + +def fuck_layers(layers): + if layers and 'F.Cu' in layers and 'B.Cu' in layers and not any(re.match(r'^In[0-9]+\.Cu$', l) for l in layers): + return ['F&B.Cu', *(l for l in layers if l not in ('F.Cu', 'B.Cu'))] + else: + return layers + + @sexp_type('hatch') class Hatch: style: AtomChoice(Atom.none, Atom.edge, Atom.full) = Atom.edge @@ -81,12 +95,23 @@ class Zone: connect_pads: PadConnection = field(default_factory=PadConnection) min_thickness: Named(float) = 0.254 filled_areas_thickness: Named(YesNoAtom()) = True - keepout: ZoneKeepout = field(default_factory=ZoneKeepout) + keepout: ZoneKeepout = None fill: ZoneFill = field(default_factory=ZoneFill) polygon: ZonePolygon = field(default_factory=ZonePolygon) fill_polygons: List(FillPolygon) = field(default_factory=list) fill_segments: List(FillSegment) = field(default_factory=list) + def __after_parse__(self, parent=None): + self.layers = unfuck_layers(self.layers) + + def __before_sexp__(self): + self.layers = fuck_layers(self.layers) + + def unfill(self): + self.fill.yes = False + self.fill_polygons = [] + self.fill_segments = [] + @sexp_type('polygon') class RenderCachePolygon: -- cgit