diff options
author | jaseg <git@jaseg.de> | 2022-01-30 20:11:38 +0100 |
---|---|---|
committer | jaseg <git@jaseg.de> | 2022-01-30 20:11:38 +0100 |
commit | c3ca4f95bd59f69d45e582a4149327f57a360760 (patch) | |
tree | 5f43c61a261698e2f671b5238a7aa9a71a0f6d23 /gerbonara/gerber/aperture_macros/parse.py | |
parent | 259a56186820923c78a5688f59bd8249cf958b5f (diff) | |
download | gerbonara-c3ca4f95bd59f69d45e582a4149327f57a360760.tar.gz gerbonara-c3ca4f95bd59f69d45e582a4149327f57a360760.tar.bz2 gerbonara-c3ca4f95bd59f69d45e582a4149327f57a360760.zip |
Rename gerbonara/gerber package to just gerbonara
Diffstat (limited to 'gerbonara/gerber/aperture_macros/parse.py')
-rw-r--r-- | gerbonara/gerber/aperture_macros/parse.py | 181 |
1 files changed, 0 insertions, 181 deletions
diff --git a/gerbonara/gerber/aperture_macros/parse.py b/gerbonara/gerber/aperture_macros/parse.py deleted file mode 100644 index 0fa936f..0000000 --- a/gerbonara/gerber/aperture_macros/parse.py +++ /dev/null @@ -1,181 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Copyright 2021 Jan Götte <gerbonara@jaseg.de> - -import operator -import re -import ast -import copy -import math - -from . import primitive as ap -from .expression import * -from ..utils import MM - -def rad_to_deg(x): - return (x / math.pi) * 180 - -def _map_expression(node): - if isinstance(node, ast.Num): - return ConstantExpression(node.n) - - elif isinstance(node, ast.BinOp): - op_map = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul, ast.Div: operator.truediv} - return OperatorExpression(op_map[type(node.op)], _map_expression(node.left), _map_expression(node.right)) - - elif isinstance(node, ast.UnaryOp): - if type(node.op) == ast.UAdd: - return _map_expression(node.operand) - else: - return OperatorExpression(operator.sub, ConstantExpression(0), _map_expression(node.operand)) - - elif isinstance(node, ast.Name): - return VariableExpression(int(node.id[3:])) # node.id has format var[0-9]+ - - else: - raise SyntaxError('Invalid aperture macro expression') - -def _parse_expression(expr): - expr = expr.lower().replace('x', '*') - expr = re.sub(r'\$([0-9]+)', r'var\1', expr) - try: - parsed = ast.parse(expr, mode='eval').body - except SyntaxError as e: - raise SyntaxError('Invalid aperture macro expression') from e - return _map_expression(parsed) - -class ApertureMacro: - def __init__(self, name=None, primitives=None, variables=None): - self._name = name - self.comments = [] - self.variables = variables or {} - self.primitives = primitives or [] - - @classmethod - def parse_macro(cls, name, body, unit): - macro = cls(name) - - blocks = re.sub(r'\s', '', body).split('*') - for block in blocks: - if not (block := block.strip()): # empty block - continue - - if block[0:1] == '0 ': # comment - macro.comments.append(Comment(block[2:])) - - if block[0] == '$': # variable definition - name, expr = block.partition('=') - number = int(name[1:]) - if number in macro.variables: - raise SyntaxError(f'Re-definition of aperture macro variable {number} inside macro') - macro.variables[number] = _parse_expression(expr) - - else: # primitive - primitive, *args = block.split(',') - args = [ _parse_expression(arg) for arg in args ] - primitive = ap.PRIMITIVE_CLASSES[int(primitive)](unit=unit, args=args) - macro.primitives.append(primitive) - - return macro - - @property - def name(self): - if self._name is not None: - return self._name - else: - return f'gn_{hash(self)}' - - @name.setter - def name(self, name): - self._name = name - - def __str__(self): - return f'<Aperture macro {self.name}, variables {str(self.variables)}, primitives {self.primitives}>' - - def __repr__(self): - return str(self) - - def __eq__(self, other): - return hasattr(other, 'to_gerber') and self.to_gerber() == other.to_gerber() - - def __hash__(self): - return hash(self.to_gerber()) - - def dilated(self, offset, unit=MM): - dup = copy.deepcopy(self) - new_primitives = [] - for primitive in dup.primitives: - try: - if primitive.exposure.calculate(): - primitive.dilate(offset, unit) - new_primitives.append(primitive) - except IndexError: - warnings.warn('Cannot dilate aperture macro primitive with exposure value computed from macro variable.') - pass - dup.primitives = new_primitives - return dup - - def to_gerber(self, unit=None): - comments = [ c.to_gerber() for c in self.comments ] - variable_defs = [ f'${var.to_gerber(unit)}={expr}' for var, expr in self.variables.items() ] - primitive_defs = [ prim.to_gerber(unit) for prim in self.primitives ] - return '*\n'.join(comments + variable_defs + primitive_defs) - - def to_graphic_primitives(self, offset, rotation, parameters : [float], unit=None, polarity_dark=True): - variables = dict(self.variables) - for number, value in enumerate(parameters, start=1): - if number in variables: - raise SyntaxError(f'Re-definition of aperture macro variable {i} through parameter {value}') - variables[number] = value - - for primitive in self.primitives: - yield from primitive.to_graphic_primitives(offset, rotation, variables, unit, polarity_dark) - - def rotated(self, angle): - dup = copy.deepcopy(self) - for primitive in dup.primitives: - # aperture macro primitives use degree counter-clockwise, our API uses radians clockwise - primitive.rotation -= rad_to_deg(angle) - return dup - - -cons, var = ConstantExpression, VariableExpression -deg_per_rad = 180 / math.pi - -class GenericMacros: - - _generic_hole = lambda n: [ - ap.Circle('mm', [0, var(n), 0, 0]), - ap.CenterLine('mm', [0, var(n), var(n+1), 0, 0, var(n+2) * -deg_per_rad])] - - # NOTE: All generic macros have rotation values specified in **clockwise radians** like the rest of the user-facing - # API. - circle = ApertureMacro('GNC', [ - ap.Circle('mm', [1, var(1), 0, 0, var(4) * -deg_per_rad]), - *_generic_hole(2)]) - - rect = ApertureMacro('GNR', [ - ap.CenterLine('mm', [1, var(1), var(2), 0, 0, var(5) * -deg_per_rad]), - *_generic_hole(3) ]) - - # w must be larger than h - obround = ApertureMacro('GNO', [ - ap.CenterLine('mm', [1, var(1), var(2), 0, 0, var(5) * -deg_per_rad]), - ap.Circle('mm', [1, var(2), +var(1)/2, 0, var(5) * -deg_per_rad]), - ap.Circle('mm', [1, var(2), -var(1)/2, 0, var(5) * -deg_per_rad]), - *_generic_hole(3) ]) - - polygon = ApertureMacro('GNP', [ - ap.Polygon('mm', [1, var(2), 0, 0, var(1), var(3) * -deg_per_rad]), - ap.Circle('mm', [0, var(4), 0, 0])]) - - -if __name__ == '__main__': - import sys - #for line in sys.stdin: - #expr = _parse_expression(line.strip()) - #print(expr, '->', expr.optimized()) - - for primitive in parse_macro(sys.stdin.read(), 'mm'): - print(primitive) |