From 3fb26e6940b5ae752308d8a33f2608d266795153 Mon Sep 17 00:00:00 2001 From: jaseg Date: Wed, 29 Dec 2021 19:58:20 +0100 Subject: Basic round-trip works --- gerbonara/gerber/aperture_macros/expression.py | 15 ++++---- gerbonara/gerber/aperture_macros/parse.py | 51 +++++++++++++------------- gerbonara/gerber/aperture_macros/primitive.py | 11 ++++-- 3 files changed, 40 insertions(+), 37 deletions(-) (limited to 'gerbonara/gerber/aperture_macros') diff --git a/gerbonara/gerber/aperture_macros/expression.py b/gerbonara/gerber/aperture_macros/expression.py index ddd8d53..73a2a36 100644 --- a/gerbonara/gerber/aperture_macros/expression.py +++ b/gerbonara/gerber/aperture_macros/expression.py @@ -8,15 +8,14 @@ import re import ast +MILLIMETERS_PER_INCH = 25.4 + + def expr(obj): return obj if isinstance(obj, Expression) else ConstantExpression(obj) -class Expression(object): - @property - def value(self): - return self - +class Expression: def optimized(self, variable_binding={}): return self @@ -79,17 +78,17 @@ class UnitExpression(Expression): return f'<{self._expr.to_gerber()} {self.unit}>' def converted(self, unit): - if unit is None or self.unit == unit: + if self.unit is None or unit is None or self.unit == unit: return self._expr elif unit == 'mm': return self._expr * MILLIMETERS_PER_INCH elif unit == 'inch': - return self._expr / MILLIMETERS_PER_INCH) + return self._expr / MILLIMETERS_PER_INCH else: - raise ValueError('invalid unit, must be "inch" or "mm".') + raise ValueError(f'invalid unit {unit}, must be "inch" or "mm".') class ConstantExpression(Expression): diff --git a/gerbonara/gerber/aperture_macros/parse.py b/gerbonara/gerber/aperture_macros/parse.py index 2f578ee..35cb6c2 100644 --- a/gerbonara/gerber/aperture_macros/parse.py +++ b/gerbonara/gerber/aperture_macros/parse.py @@ -9,10 +9,8 @@ import ast import copy import math -import primitive as ap -from expression import * - -from .. import apertures +from . import primitive as ap +from .expression import * def rad_to_deg(x): return (x / math.pi) * 180 @@ -54,10 +52,10 @@ class ApertureMacro: self.primitives = primitives or [] @classmethod - def parse_macro(cls, name, macro, unit): + def parse_macro(cls, name, body, unit): macro = cls(name) - blocks = re.sub(r'\s', '', macro).split('*') + blocks = re.sub(r'\s', '', body).split('*') for block in blocks: if not (block := block.strip()): # empty block continue @@ -74,14 +72,14 @@ class ApertureMacro: else: # primitive primitive, *args = block.split(',') - args = [_parse_expression(arg) for arg in args] - primitive = ap.PRIMITIVE_CLASSES[int(primitive)](unit=unit, args=args + args = [ _parse_expression(arg) for arg in args ] + primitive = ap.PRIMITIVE_CLASSES[int(primitive)](unit=unit, args=args) macro.primitives.append(primitive) @property def name(self): - if self.name is not None: - return self.name + if self._name is not None: + return self._name else: return f'gn_{hash(self)}' @@ -120,31 +118,34 @@ class ApertureMacro: return copy +cons, var = ConstantExpression, VariableExpression +deg_per_rad = 180 / math.pi + class GenericMacros: - deg_per_rad = 180 / math.pi - cons, var = VariableExpression + _generic_hole = lambda n: [ - ap.Circle(exposure=0, diameter=var(n), x=0, y=0), - ap.Rectangle(exposure=0, w=var(n), h=var(n+1), x=0, y=0, rotation=var(n+2) * deg_per_rad)] + ap.Circle(None, [0, var(n), 0, 0]), + ap.CenterLine(None, [0, var(n), var(n+1), 0, 0, var(n+2) * deg_per_rad])] - circle = ApertureMacro([ - ap.Circle(exposure=1, diameter=var(1), x=0, y=0, rotation=var(4) * deg_per_rad), + # Initialize all these with "None" units so they inherit file units, and do not convert their arguments. + circle = ApertureMacro('GNC', [ + ap.Circle(None, [1, var(1), 0, 0, var(4) * deg_per_rad]), *_generic_hole(2)]) - rect = ApertureMacro([ - ap.Rectangle(exposure=1, w=var(1), h=var(2), x=0, y=0, rotation=var(5) * deg_per_rad), + rect = ApertureMacro('GNR', [ + ap.CenterLine(None, [1, var(1), var(2), 0, 0, var(5) * deg_per_rad]), *_generic_hole(3) ]) # w must be larger than h - obround = ApertureMacro([ - ap.Rectangle(exposure=1, w=var(1), h=var(2), x=0, y=0, rotation=var(5) * deg_per_rad), - ap.Circle(exposure=1, diameter=var(2), x=+var(1)/2, y=0, rotation=var(5) * deg_per_rad), - ap.Circle(exposure=1, diameter=var(2), x=-var(1)/2, y=0, rotation=var(5) * deg_per_rad), + obround = ApertureMacro('GNO', [ + ap.CenterLine(None, [1, var(1), var(2), 0, 0, var(5) * deg_per_rad]), + ap.Circle(None, [1, var(2), +var(1)/2, 0, var(5) * deg_per_rad]), + ap.Circle(None, [1, var(2), -var(1)/2, 0, var(5) * deg_per_rad]), *_generic_hole(3) ]) - polygon = ApertureMacro([ - ap.Polygon(exposure=1, n_vertices=var(2), x=0, y=0, diameter=var(1), rotation=var(3) * deg_per_rad), - pa.Circle(exposure=0, diameter=var(4), x=0, y=0)]) + polygon = ApertureMacro('GNP', [ + ap.Polygon(None, [1, var(2), 0, 0, var(1), var(3) * deg_per_rad]), + ap.Circle(None, [0, var(4), 0, 0])]) if __name__ == '__main__': diff --git a/gerbonara/gerber/aperture_macros/primitive.py b/gerbonara/gerber/aperture_macros/primitive.py index aeb38c4..4d3e597 100644 --- a/gerbonara/gerber/aperture_macros/primitive.py +++ b/gerbonara/gerber/aperture_macros/primitive.py @@ -7,9 +7,9 @@ import contextlib import math -from expression import Expression, UnitExpression, ConstantExpression, expr +from .expression import Expression, UnitExpression, ConstantExpression, expr -from .. import graphic_primitivese as gp +from .. import graphic_primitives as gp def point_distance(a, b): @@ -41,7 +41,7 @@ class Primitive: raise ValueError(f'Too few arguments ({len(args)}) for aperture macro primitive {self.code} ({type(self)})') def to_gerber(self, unit=None): - return self.code + ',' + ','.join( + return f'{self.code},' + ','.join( getattr(self, name).to_gerber(unit) for name in type(self).__annotations__) + '*' def __str__(self): @@ -149,6 +149,7 @@ class Polygon(Primitive): class Thermal(Primitive): code = 7 + exposure : Expression # center x/y x : UnitExpression y : UnitExpression @@ -216,6 +217,8 @@ class Outline(Primitive): class Comment: + code = 0 + def __init__(self, comment): self.comment = comment @@ -233,6 +236,6 @@ PRIMITIVE_CLASSES = { Thermal, ]}, # alternative codes - 2: VectorLinePrimitive, + 2: VectorLine, } -- cgit