From 8d5403260b72115cfd9f401289dfd0f894e272ea Mon Sep 17 00:00:00 2001 From: jaseg Date: Sat, 29 Apr 2023 11:28:38 +0200 Subject: Fix aperture macro rotation issue and add missing data files --- gerbonara/aperture_macros/expression.py | 2 +- gerbonara/aperture_macros/parse.py | 4 ++-- gerbonara/aperture_macros/primitive.py | 18 +++++++++++++++--- gerbonara/apertures.py | 4 ++-- gerbonara/cad/data/center-pad-spikes.kicad_mod | 16 ++++++++++++++++ gerbonara/cad/data/pad-between-spiked.kicad_mod | 24 ++++++++++++++++++++++++ gerbonara/cad/data/tht-0.8.kicad_mod | 16 ++++++++++++++++ gerbonara/cad/protoboard.py | 1 + 8 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 gerbonara/cad/data/center-pad-spikes.kicad_mod create mode 100644 gerbonara/cad/data/pad-between-spiked.kicad_mod create mode 100644 gerbonara/cad/data/tht-0.8.kicad_mod (limited to 'gerbonara') diff --git a/gerbonara/aperture_macros/expression.py b/gerbonara/aperture_macros/expression.py index 63f1e42..44abf51 100644 --- a/gerbonara/aperture_macros/expression.py +++ b/gerbonara/aperture_macros/expression.py @@ -123,7 +123,7 @@ class UnitExpression(Expression): raise ValueError('Unit mismatch: Can only add/subtract UnitExpression from UnitExpression, not scalar.') def __sub__(self, other): - return (self + (-other)).optimize() + return (self + (-other)).optimized() def __rsub__(self, other): # see __radd__ above diff --git a/gerbonara/aperture_macros/parse.py b/gerbonara/aperture_macros/parse.py index 72703ae..b8970ff 100644 --- a/gerbonara/aperture_macros/parse.py +++ b/gerbonara/aperture_macros/parse.py @@ -55,9 +55,9 @@ class ApertureMacro: comments: tuple = () def __post_init__(self): - if self.name is None: + if self.name is None or re.match(r'GNX[0-9A-F]{16}', self.name): # We can't use field(default_factory=...) here because that factory doesn't get a reference to the instance. - object.__setattr__(self, 'name', f'gn_{hash(self):x}') + object.__setattr__(self, 'name', f'GNX{hash(self)&0xffffffffffffffff:016X}') @classmethod def parse_macro(cls, name, body, unit): diff --git a/gerbonara/aperture_macros/primitive.py b/gerbonara/aperture_macros/primitive.py index 5700743..356da9f 100644 --- a/gerbonara/aperture_macros/primitive.py +++ b/gerbonara/aperture_macros/primitive.py @@ -13,7 +13,7 @@ from .expression import Expression, UnitExpression, ConstantExpression, expr from .. import graphic_primitives as gp from .. import graphic_objects as go -from ..utils import rotate_point, LengthUnit +from ..utils import rotate_point, LengthUnit, MM def point_distance(a, b): @@ -277,8 +277,20 @@ class Outline(Primitive): return f'' def to_gerber(self, unit=None): - coords = ','.join(coord.to_gerber(unit) for coord in self.coords) - return f'{self.code},{self.exposure.to_gerber()},{len(self.coords)-1},{coords},{self.rotation.to_gerber()}' + # Calculate out rotation since at least gerbv mis-renders Outlines with rotation other than zero. + rotation = self.rotation.optimized() + coords = self.coords + if isinstance(rotation, ConstantExpression): + rotation = math.radians(rotation.value) + # This will work even with variables in x and y, we just need to pass in cx and cy as UnitExpressions + unit_zero = UnitExpression(expr(0), MM) + coords = [ rotate_point(x, y, -rotation, cx=unit_zero, cy=unit_zero) for x, y in self.points ] + coords = [ e for point in coords for e in point ] + + rotation = ConstantExpression(0) + + coords = ','.join(coord.to_gerber(unit) for coord in coords) + return f'{self.code},{self.exposure.to_gerber()},{len(self.coords)-1},{coords},{rotation.to_gerber()}' def to_graphic_primitives(self, offset, rotation, variable_binding={}, unit=None, polarity_dark=True): with self.Calculator(self, variable_binding, unit) as calc: diff --git a/gerbonara/apertures.py b/gerbonara/apertures.py index 512b4dd..d901765 100644 --- a/gerbonara/apertures.py +++ b/gerbonara/apertures.py @@ -421,13 +421,13 @@ class ApertureMacroInstance(Aperture): return replace(self, macro=self.macro.dilated(offset, unit)) @lru_cache() - def rotated(self, angle=0): + def rotated(self, angle=0.0): if math.isclose(angle % (2*math.pi), 0): return self else: return self.to_macro(angle) - def to_macro(self, rotation=0): + def to_macro(self, rotation=0.0): return replace(self, macro=self.macro.rotated(rotation)) def scaled(self, scale): diff --git a/gerbonara/cad/data/center-pad-spikes.kicad_mod b/gerbonara/cad/data/center-pad-spikes.kicad_mod new file mode 100644 index 0000000..e996861 --- /dev/null +++ b/gerbonara/cad/data/center-pad-spikes.kicad_mod @@ -0,0 +1,16 @@ +(module center-pad-spikes (layer F.Cu) (tedit 5B6B1C50) + (fp_text reference REF** (at 0 -1.4) (layer F.SilkS) hide + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text value center-pad (at 0.1 -2.7) (layer F.Fab) hide + (effects (font (size 1 1) (thickness 0.15))) + ) + (pad 1 smd custom (at -0.06 -0.085) (size 0.47 0.52) (layers *.Cu *.Mask) + (options (clearance outline) (anchor rect)) + (primitives + (gr_poly (pts + (xy -0.585 0.085) (xy 0.06 -0.56) (xy 0.357 -0.263) (xy 0.583 -0.263) (xy 0.235 0.085) + (xy 0.582 0.432) (xy 0.407 0.432) (xy 0.407 0.607) (xy 0.06 0.26) (xy -0.288 0.608) + (xy -0.288 0.382)) (width 0.001)) + )) +) diff --git a/gerbonara/cad/data/pad-between-spiked.kicad_mod b/gerbonara/cad/data/pad-between-spiked.kicad_mod new file mode 100644 index 0000000..205101e --- /dev/null +++ b/gerbonara/cad/data/pad-between-spiked.kicad_mod @@ -0,0 +1,24 @@ +(module pad-between-spiked (layer F.Cu) (tedit 5B6B1D89) + (descr "Through hole pin header") + (tags "pin header") + (fp_text reference REF** (at 0 -5.1) (layer F.SilkS) hide + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text value pad-between (at 0 -3.1) (layer F.Fab) hide + (effects (font (size 1 1) (thickness 0.15))) + ) + (pad 1 smd custom (at 0 -0.06) (size 0.7 0.85) (layers *.Cu *.Mask) + (options (clearance outline) (anchor rect)) + (primitives + (gr_poly (pts + (xy -0.55 -0.44) (xy -0.325 -0.44) (xy 0 -0.765) (xy 0.325 -0.44) (xy 0.55 -0.44) + (xy 0.35 -0.24) (xy 0.35 0.36) (xy 0.55 0.56) (xy 0.338 0.56) (xy 0.338 0.763) + (xy 0 0.425) (xy -0.01 0.425) (xy -0.348 0.763) (xy -0.348 0.56) (xy -0.55 0.56) + (xy -0.35 0.36) (xy -0.35 -0.24)) (width 0.001)) + )) + (model Pin_Headers.3dshapes/Pin_Header_Straight_1x01.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 90)) + ) +) diff --git a/gerbonara/cad/data/tht-0.8.kicad_mod b/gerbonara/cad/data/tht-0.8.kicad_mod new file mode 100644 index 0000000..3092f23 --- /dev/null +++ b/gerbonara/cad/data/tht-0.8.kicad_mod @@ -0,0 +1,16 @@ +(module tht-0.8 (layer F.Cu) (tedit 58D96FE6) + (descr "Through hole pin header") + (tags "pin header") + (fp_text reference REF** (at 0 -5.1) (layer F.SilkS) hide + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text value tht-0.8 (at 0 -3.1) (layer F.Fab) hide + (effects (font (size 1 1) (thickness 0.15))) + ) + (pad 1 thru_hole circle (at 0 0) (size 1.4 1.4) (drill 0.8) (layers *.Cu *.Mask)) + (model Pin_Headers.3dshapes/Pin_Header_Straight_1x01.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 90)) + ) +) diff --git a/gerbonara/cad/protoboard.py b/gerbonara/cad/protoboard.py index 741d8a9..02cbb65 100644 --- a/gerbonara/cad/protoboard.py +++ b/gerbonara/cad/protoboard.py @@ -550,6 +550,7 @@ def _demo(): #pattern = PatternProtoArea(2.54, obj=THTPad.circle(0, 0, 0.9, 1.8, paste=False)) #pattern = PatternProtoArea(2.54, obj=PoweredProto()) pb = ProtoBoard(50, 50, pattern1, mounting_hole_dia=3.2, mounting_hole_offset=5) + #pb = ProtoBoard(10, 10, pattern1) print(pb.pretty_svg()) pb.layer_stack().save_to_directory('/tmp/testdir') -- cgit