From 5aa184757e4fb5c2fc141c41aed2fccc0c96ce7e Mon Sep 17 00:00:00 2001 From: jaseg Date: Sat, 6 Nov 2021 22:00:14 +0100 Subject: Make unit test not crash on import --- gerbonara/gerber/am_eval.py | 109 ------ gerbonara/gerber/am_read.py | 4 +- gerbonara/gerber/am_statements.py | 3 +- gerbonara/gerber/gerber_statements.py | 25 +- gerbonara/gerber/panelize/__init__.py | 1 - gerbonara/gerber/panelize/am_expression.py | 219 ----------- gerbonara/gerber/panelize/am_primitive.py | 399 --------------------- gerbonara/gerber/panelize/common.py | 36 -- .../gerber/tests/panelize/test_am_expression.py | 4 +- 9 files changed, 8 insertions(+), 792 deletions(-) delete mode 100644 gerbonara/gerber/am_eval.py delete mode 100644 gerbonara/gerber/panelize/am_expression.py delete mode 100644 gerbonara/gerber/panelize/am_primitive.py delete mode 100644 gerbonara/gerber/panelize/common.py diff --git a/gerbonara/gerber/am_eval.py b/gerbonara/gerber/am_eval.py deleted file mode 100644 index 3a7e1ed..0000000 --- a/gerbonara/gerber/am_eval.py +++ /dev/null @@ -1,109 +0,0 @@ -#! /usr/bin/env python -# -*- coding: utf-8 -*- - -# copyright 2014 Hamilton Kibbe -# copyright 2014 Paulo Henrique Silva -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at - -# http://www.apache.org/licenses/LICENSE-2.0 - -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -""" This module provides RS-274-X AM macro evaluation. -""" - - -class OpCode: - PUSH = 1 - LOAD = 2 - STORE = 3 - ADD = 4 - SUB = 5 - MUL = 6 - DIV = 7 - PRIM = 8 - - @staticmethod - def str(opcode): - if opcode == OpCode.PUSH: - return "OPCODE_PUSH" - elif opcode == OpCode.LOAD: - return "OPCODE_LOAD" - elif opcode == OpCode.STORE: - return "OPCODE_STORE" - elif opcode == OpCode.ADD: - return "OPCODE_ADD" - elif opcode == OpCode.SUB: - return "OPCODE_SUB" - elif opcode == OpCode.MUL: - return "OPCODE_MUL" - elif opcode == OpCode.DIV: - return "OPCODE_DIV" - elif opcode == OpCode.PRIM: - return "OPCODE_PRIM" - else: - return "UNKNOWN" - - -def eval_macro(instructions, parameters={}): - - if not isinstance(parameters, type({})): - p = {} - for i, val in enumerate(parameters): - p[i + 1] = val - - parameters = p - - stack = [] - - def pop(): - return stack.pop() - - def push(op): - stack.append(op) - - def top(): - return stack[-1] - - def empty(): - return len(stack) == 0 - - for opcode, argument in instructions: - if opcode == OpCode.PUSH: - push(argument) - - elif opcode == OpCode.LOAD: - push(parameters.get(argument, 0)) - - elif opcode == OpCode.STORE: - parameters[argument] = pop() - - elif opcode == OpCode.ADD: - op1 = pop() - op2 = pop() - push(op2 + op1) - - elif opcode == OpCode.SUB: - op1 = pop() - op2 = pop() - push(op2 - op2) - - elif opcode == OpCode.MUL: - op1 = pop() - op2 = pop() - push(op2 * op1) - - elif opcode == OpCode.DIV: - op1 = pop() - op2 = pop() - push(op2 / op1) - - elif opcode == OpCode.PRIM: - yield "%d,%s" % (argument, ",".join([str(x) for x in stack])) - stack = [] diff --git a/gerbonara/gerber/am_read.py b/gerbonara/gerber/am_read.py index 475caad..906aaa9 100644 --- a/gerbonara/gerber/am_read.py +++ b/gerbonara/gerber/am_read.py @@ -18,11 +18,11 @@ """ This module provides RS-274-X AM macro modifiers parsing. """ -from .am_eval import OpCode, eval_macro +from .am_opcode import OpCode +from .am_primitive import eval_macro import string - class Token: ADD = "+" SUB = "-" diff --git a/gerbonara/gerber/am_statements.py b/gerbonara/gerber/am_statements.py index 803a123..61ddf42 100644 --- a/gerbonara/gerber/am_statements.py +++ b/gerbonara/gerber/am_statements.py @@ -21,6 +21,7 @@ import math from .primitives import * from .utils import validate_coordinates, inch, metric, rotate_point +from .am_expression import AMConstantExpression @@ -57,7 +58,7 @@ class AMPrimitive(object): """ def __init__(self, code, exposure=None, rotation=AMConstantExpression(0)): - VALID_CODES = (0, 1, 2, 4, 5, 6, 7, 20, 21, 22, 9999) + VALID_CODES = (0, 1, 2, 4, 5, 7, 20, 21, 22, 9999) if not isinstance(code, int): raise TypeError('Aperture Macro Primitive code must be an integer') elif code not in VALID_CODES: diff --git a/gerbonara/gerber/gerber_statements.py b/gerbonara/gerber/gerber_statements.py index 22766f8..9296d1b 100644 --- a/gerbonara/gerber/gerber_statements.py +++ b/gerbonara/gerber/gerber_statements.py @@ -25,7 +25,7 @@ from .utils import (parse_gerber_value, write_gerber_value, decimal_string, from .am_statements import * from .am_read import read_macro -from .am_eval import eval_macro +from .am_primitive import eval_macro from .primitives import AMGroup @@ -418,32 +418,11 @@ class AMParamStmt(ParamStmt): self.name = name self.macro = macro self.units = units - self.primitives = list(AMParamStmt._parse_primitives(self.instructions)) + self.primitives = list(eval_macro(self.instructions)) def read(self, macro): return read_macro(macro) - @classmethod - def _parse_primitives(kls, instructions): - classes = { - 0: AMCommentPrimitive, - 1: AMCirclePrimitive, - 2: AMVectorLinePrimitive, - 20: AMVectorLinePrimitive, - 21: AMCenterLinePrimitive, - 4: AMOutlinePrimitive, - 5: AMPolygonPrimitive, - 6: AMMoirePrimitive, - 7: AMThermalPrimitive, - } - - for code, modifiers in eval_macro(instructions): - if code < 0: - yield AMVariableDef(-code, modifiers[0]) - else: - primitive = classes[code] - yield primitive.from_modifiers(code, modifiers) - @classmethod def circle(cls, name, units): return cls('AM', name, '1,1,$1,0,0,0*1,0,$2,0,0,0', units) diff --git a/gerbonara/gerber/panelize/__init__.py b/gerbonara/gerber/panelize/__init__.py index 645b632..7185aea 100644 --- a/gerbonara/gerber/panelize/__init__.py +++ b/gerbonara/gerber/panelize/__init__.py @@ -3,6 +3,5 @@ # Copyright 2019 Hiroshi Murayama -from .common import read, loads # , rectangle from .composition import GerberComposition, DrillComposition # from .dxf import DxfFile diff --git a/gerbonara/gerber/panelize/am_expression.py b/gerbonara/gerber/panelize/am_expression.py deleted file mode 100644 index a0a4114..0000000 --- a/gerbonara/gerber/panelize/am_expression.py +++ /dev/null @@ -1,219 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Copyright 2019 Hiroshi Murayama - -import operator - -from ..utils import * -from ..am_eval import OpCode -from ..am_statements import * - -class AMExpression(object): - CONSTANT = 1 - VARIABLE = 2 - OPERATOR = 3 - - def __init__(self, kind): - self.kind = kind - - @property - def value(self): - return self - - def optimize(self): - return self - - def to_inch(self): - return AMOperatorExpression.div(self, MILLIMETERS_PER_INCH) - - def to_metric(self): - return AMOperatorExpression.mul(self, MILLIMETERS_PER_INCH) - - #def to_gerber(self, settings=None): - # pass - - #def to_instructions(self): - # pass - -class AMConstantExpression(AMExpression): - def __init__(self, value): - super(AMConstantExpression, self).__init__(AMExpression.CONSTANT) - self._value = value - - @property - def value(self): - return self._value - - def __float__(self): - return float(self._value) - - @staticmethod - def _amex_val(other): - return float(other) if isinstance(other, AMConstantExpression) else other - - def __eq__(self, val): - return self._value == AMConstantExpression._amex_val(val) - - def __ne__(self, val): - return self._value != AMConstantExpression._amex_val(val) - - def __lt__(self, val): - return self._value < AMConstantExpression._amex_val(val) - - def __gt__(self, val): - return self._value > AMConstantExpression._amex_val(val) - - def __le__(self, val): - return self._value <= AMConstantExpression._amex_val(val) - - def __ge__(self, val): - return self._value >= AMConstantExpression._amex_val(val) - - def to_gerber(self, settings=None): - if isinstance(self._value, str): - return self._value - return f'{self.value:.6f}'.rstrip('0').rstrip('.') - - def to_instructions(self): - return [(OpCode.PUSH, self._value)] - -class AMVariableExpression(AMExpression): - def __init__(self, number): - super(AMVariableExpression, self).__init__(AMExpression.VARIABLE) - self.number = number - - def to_gerber(self, settings=None): - return f'${self.number}' - - def to_instructions(self): - return (OpCode.LOAD, self.number) - -class AMOperatorExpression(AMExpression): - def __init__(self, op, lvalue, rvalue): - super(AMOperatorExpression, self).__init__(AMExpression.OPERATOR) - self.op = op - self.lvalue = AMConstantExpression(lvalue) if isinstance(lvalue, (int, float)) else lvalue - self.rvalue = AMConstantExpression(rvalue) if isinstance(rvalue, (int, float)) else rvalue - - @classmethod - def add(kls, lvalue, rvalue): - return kls(operator.add, lvalue, rvalue) - - @classmethod - def sub(kls, lvalue, rvalue): - return kls(operator.sub, lvalue, rvalue) - - @classmethod - def mul(kls, lvalue, rvalue): - return kls(operator.mul, lvalue, rvalue) - - @classmethod - def div(kls, lvalue, rvalue): - return kls(operator.truediv, lvalue, rvalue) - - def optimize(self): - l = self.lvalue = self.lvalue.optimize() - r = self.rvalue = self.rvalue.optimize() - - if isinstance(l, AMConstantExpression) and isinstance(r, AMConstantExpression): - return AMConstantExpression(self.op(float(r), float(l))) - - elif self.op == operator.ADD: - if r == 0: - return l - elif l == 0: - return r - - elif self.op == operator.SUB: - if r == 0: - return l - elif l == 0 and isinstance(r, AMConstantExpression): - return AMConstantExpression(-float(r)) - - elif self.op == operator.MUL: - if r == 1: - return l - elif l == 1: - return r - elif l == 0 or r == 0: - return AMConstantExpression(0) - - elif self.op == operator.TRUEDIV: - if r == 1: - return self.lvalue - elif l == 0: - return AMConstantExpression(0) - - return self - - def to_gerber(self, settings=None): - lval = self.lvalue.to_gerber(settings) - rval = self.rvalue.to_gerber(settings)) - op = {AMOperatorExpression.ADD: '+', - AMOperatorExpression.SUB: '-', - AMOperatorExpression.MUL: 'x', - AMOperatorExpression.DIV: '/'} [self.op] - return '(' + lval + op + rval + ')' - - def to_instructions(self): - for i in self.lvalue.to_instructions(): - yield i - - for i in self.rvalue.to_instructions(): - yield i - - op = {AMOperatorExpression.ADD: OpCode.ADD, - AMOperatorExpression.SUB: OpCode.SUB, - AMOperatorExpression.MUL: OpCode.MUL, - AMOperatorExpression.DIV: OpCode.DIV} [self.op] - yield (op, None) - -def eval_macro(instructions): - stack = [] - - def pop(): - return stack.pop() - - def push(op): - stack.append(op) - - def top(): - return stack[-1] - - def empty(): - return len(stack) == 0 - - for opcode, argument in instructions: - if opcode == OpCode.PUSH: - push(AMConstantExpression(argument)) - - elif opcode == OpCode.LOAD: - push(AMVariableExpression(argument)) - - elif opcode == OpCode.STORE: - yield (-argument, [pop()]) - - elif opcode == OpCode.ADD: - op1 = pop() - op2 = pop() - push(AMOperatorExpression(AMOperatorExpression.ADD, op2, op1)) - - elif opcode == OpCode.SUB: - op1 = pop() - op2 = pop() - push(AMOperatorExpression(AMOperatorExpression.SUB, op2, op1)) - - elif opcode == OpCode.MUL: - op1 = pop() - op2 = pop() - push(AMOperatorExpression(AMOperatorExpression.MUL, op2, op1)) - - elif opcode == OpCode.DIV: - op1 = pop() - op2 = pop() - push(AMOperatorExpression(AMOperatorExpression.DIV, op2, op1)) - - elif opcode == OpCode.PRIM: - yield (argument, stack) - stack = [] diff --git a/gerbonara/gerber/panelize/am_primitive.py b/gerbonara/gerber/panelize/am_primitive.py deleted file mode 100644 index 5d8458b..0000000 --- a/gerbonara/gerber/panelize/am_primitive.py +++ /dev/null @@ -1,399 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Copyright 2019 Hiroshi Murayama - -from ..utils import * -from ..am_statements import * -from ..am_eval import OpCode - -from .am_expression import eval_macro, AMConstantExpression, AMOperatorExpression - -class AMCommentPrimitiveDef(AMPrimitiveDef): - @classmethod - def from_modifiers(cls, code, modifiers): - return cls(code, modifiers[0]) - - def __init__(self, code, comment): - super(AMCommentPrimitiveDef, self).__init__(code) - self.comment = comment - -class AMCirclePrimitiveDef(AMPrimitiveDef): - @classmethod - def from_modifiers(cls, code, modifiers): - exposure = 'on' if modifiers[0].value == 1 else 'off' - diameter = modifiers[1] - center_x = modifiers[2] - center_y = modifiers[3] - rotation = modifiers[4] if len(modifiers)>4 else AMConstantExpression(float(0)) - return cls(code, exposure, diameter, center_x, center_y, rotation) - - def __init__(self, code, exposure, diameter, center_x, center_y, rotation): - super(AMCirclePrimitiveDef, self).__init__(code, exposure, rotation) - self.diameter = diameter - self.center_x = center_x - self.center_y = center_y - - def to_inch(self): - self.diameter = self.diameter.to_inch().optimize() - self.center_x = self.center_x.to_inch().optimize() - self.center_y = self.center_y.to_inch().optimize() - - def to_metric(self): - self.diameter = self.diameter.to_metric().optimize() - self.center_x = self.center_x.to_metric().optimize() - self.center_y = self.center_y.to_metric().optimize() - - def to_gerber(self, settings=None): - data = dict(code = self.code, - exposure = 1 if self.exposure == 'on' else 0, - diameter = self.diameter.to_gerber(settings), - x = self.center_x.to_gerber(settings), - y = self.center_y.to_gerber(settings), - rotation = self.rotation.to_gerber(settings)) - return '{code},{exposure},{diameter},{x},{y},{rotation}*'.format(**data) - - def to_instructions(self): - yield (OpCode.PUSH, 1 if self.exposure == 'on' else 0) - for modifier in [self.diameter, self.center_x, self.center_y, self.rotation]: - for i in modifier.to_instructions(): - yield i - yield (OpCode.PRIM, self.code) - -class AMVectorLinePrimitiveDef(AMPrimitiveDef): - @classmethod - def from_modifiers(cls, code, modifiers): - code = code - exposure = 'on' if modifiers[0].value == 1 else 'off' - width = modifiers[1] - start_x = modifiers[2] - start_y = modifiers[3] - end_x = modifiers[4] - end_y = modifiers[5] - rotation = modifiers[6] - return cls(code, exposure, width, start_x, start_y, end_x, end_y, rotation) - - def __init__(self, code, exposure, width, start_x, start_y, end_x, end_y, rotation): - super(AMVectorLinePrimitiveDef, self).__init__(code, exposure, rotation) - self.width = width - self.start_x = start_x - self.start_y = start_y - self.end_x = end_x - self.end_y = end_y - - def to_inch(self): - self.width = self.width.to_inch().optimize() - self.start_x = self.start_x.to_inch().optimize() - self.start_y = self.start_y.to_inch().optimize() - self.end_x = self.end_x.to_inch().optimize() - self.end_y = self.end_y.to_inch().optimize() - - def to_metric(self): - self.width = self.width.to_metric().optimize() - self.start_x = self.start_x.to_metric().optimize() - self.start_y = self.start_y.to_metric().optimize() - self.end_x = self.end_x.to_metric().optimize() - self.end_y = self.end_y.to_metric().optimize() - - def to_gerber(self, settings=None): - data = dict(code = self.code, - exposure = 1 if self.exposure == 'on' else 0, - width = self.width.to_gerber(settings), - start_x = self.start_x.to_gerber(settings), - start_y = self.start_y.to_gerber(settings), - end_x = self.end_x.to_gerber(settings), - end_y = self.end_y.to_gerber(settings), - rotation = self.rotation.to_gerber(settings)) - return '{code},{exposure},{width},{start_x},{start_y},{end_x},{end_y},{rotation}*'.format(**data) - - def to_instructions(self): - yield (OpCode.PUSH, 1 if self.exposure == 'on' else 0) - modifiers = [self.width, self.start_x, self.start_y, self.end_x, self.end_y, self.rotation] - for modifier in modifiers: - for i in modifier.to_instructions(): - yield i - yield (OpCode.PRIM, self.code) - -class AMCenterLinePrimitiveDef(AMPrimitiveDef): - @classmethod - def from_modifiers(cls, code, modifiers): - code = code - exposure = 'on' if modifiers[0].value == 1 else 'off' - width = modifiers[1] - height = modifiers[2] - x = modifiers[3] - y = modifiers[4] - rotation = modifiers[5] - return cls(code, exposure, width, height, x, y, rotation) - - def __init__(self, code, exposure, width, height, x, y, rotation): - super(AMCenterLinePrimitiveDef, self).__init__(code, exposure, rotation) - self.width = width - self.height = height - self.x = x - self.y = y - - def to_inch(self): - self.width = self.width.to_inch().optimize() - self.height = self.height.to_inch().optimize() - self.x = self.x.to_inch().optimize() - self.y = self.y.to_inch().optimize() - - def to_metric(self): - self.width = self.width.to_metric().optimize() - self.height = self.height.to_metric().optimize() - self.x = self.x.to_metric().optimize() - self.y = self.y.to_metric().optimize() - - def to_gerber(self, settings=None): - data = dict(code = self.code, - exposure = 1 if self.exposure == 'on' else 0, - width = self.width.to_gerber(settings), - height = self.height.to_gerber(settings), - x = self.x.to_gerber(settings), - y = self.y.to_gerber(settings), - rotation = self.rotation.to_gerber(settings)) - return '{code},{exposure},{width},{height},{x},{y},{rotation}*'.format(**data) - - def to_instructions(self): - yield (OpCode.PUSH, 1 if self.exposure == 'on' else 0) - modifiers = [self.width, self.height, self.x, self.y, self.rotation] - for modifier in modifiers: - for i in modifier.to_instructions(): - yield i - yield (OpCode.PRIM, self.code) - -class AMOutlinePrimitiveDef(AMPrimitiveDef): - @classmethod - def from_modifiers(cls, code, modifiers): - num_points = int(modifiers[1].value + 1) - code = code - exposure = 'on' if modifiers[0].value == 1 else 'off' - addrs = modifiers[2:num_points * 2 + 2] - rotation = modifiers[2 + num_points * 2] - return cls(code, exposure, addrs, rotation) - - def __init__(self, code, exposure, addrs, rotation): - super(AMOutlinePrimitiveDef, self).__init__(code, exposure, rotation) - self.addrs = addrs - - def to_inch(self): - self.addrs = [i.to_inch().optimize() for i in self.addrs] - - def to_metric(self): - self.addrs = [i.to_metric().optimize() for i in self.addrs] - - def to_gerber(self, settings=None): - def strs(): - yield '%d,%d,%d' % (self.code, - 1 if self.exposure == 'on' else 0, - len(self.addrs) / 2 - 1) - for i in self.addrs: - yield i.to_gerber(settings) - yield self.rotation.to_gerber(settings) - - return '%s*' % ','.join(strs()) - - def to_instructions(self): - yield (OpCode.PUSH, 1 if self.exposure == 'on' else 0) - yield (OpCode.PUSH, int(len(self.addrs) / 2 - 1)) - for modifier in self.addrs: - for i in modifier.to_instructions(): - yield i - for i in self.rotation.to_instructions(): - yield i - yield (OpCode.PRIM, self.code) - -class AMPolygonPrimitiveDef(AMPrimitiveDef): - @classmethod - def from_modifiers(cls, code, modifiers): - code = code - exposure = 'on' if modifiers[0].value == 1 else 'off' - vertices = modifiers[1] - x = modifiers[2] - y = modifiers[3] - diameter = modifiers[4] - rotation = modifiers[5] - return cls(code, exposure, vertices, x, y, diameter, rotation) - - def __init__(self, code, exposure, vertices, x, y, diameter, rotation): - super(AMPolygonPrimitiveDef, self).__init__(code, exposure, rotation) - self.vertices = vertices - self.x = x - self.y = y - self.diameter = diameter - - def to_inch(self): - self.x = self.x.to_inch().optimize() - self.y = self.y.to_inch().optimize() - self.diameter = self.diameter.to_inch().optimize() - - def to_metric(self): - self.x = self.x.to_metric().optimize() - self.y = self.y.to_metric().optimize() - self.diameter = self.diameter.to_metric().optimize() - - def to_gerber(self, settings=None): - data = dict(code = self.code, - exposure = 1 if self.exposure == 'on' else 0, - vertices = self.vertices.to_gerber(settings), - x = self.x.to_gerber(settings), - y = self.y.to_gerber(settings), - diameter = self.diameter.to_gerber(settings), - rotation = self.rotation.to_gerber(settings)) - return '{code},{exposure},{vertices},{x},{y},{diameter},{rotation}*'.format(**data) - - def to_instructions(self): - yield (OpCode.PUSH, 1 if self.exposure == 'on' else 0) - modifiers = [self.vertices, self.x, self.y, self.diameter, self.rotation] - for modifier in modifiers: - for i in modifier.to_instructions(): - yield i - yield (OpCode.PRIM, self.code) - -class AMMoirePrimitiveDef(AMPrimitiveDef): - @classmethod - def from_modifiers(cls, code, modifiers): - code = code - exposure = 'on' - x = modifiers[0] - y = modifiers[1] - diameter = modifiers[2] - ring_thickness = modifiers[3] - gap = modifiers[4] - max_rings = modifiers[5] - crosshair_thickness = modifiers[6] - crosshair_length = modifiers[7] - rotation = modifiers[8] - return cls(code, exposure, x, y, diameter, ring_thickness, gap, - max_rings, crosshair_thickness, crosshair_length, rotation) - - def __init__(self, code, exposure, x, y, diameter, ring_thickness, gap, max_rings, crosshair_thickness, crosshair_length, rotation): - super(AMMoirePrimitiveDef, self).__init__(code, exposure, rotation) - self.x = x - self.y = y - self.diameter = diameter - self.ring_thickness = ring_thickness - self.gap = gap - self.max_rings = max_rings - self.crosshair_thickness = crosshair_thickness - self.crosshair_length = crosshair_length - - def to_inch(self): - self.x = self.x.to_inch().optimize() - self.y = self.y.to_inch().optimize() - self.diameter = self.diameter.to_inch().optimize() - self.ring_thickness = self.ring_thickness.to_inch().optimize() - self.gap = self.gap.to_inch().optimize() - self.crosshair_thickness = self.crosshair_thickness.to_inch().optimize() - self.crosshair_length = self.crosshair_length.to_inch().optimize() - - def to_metric(self): - self.x = self.x.to_metric().optimize() - self.y = self.y.to_metric().optimize() - self.diameter = self.diameter.to_metric().optimize() - self.ring_thickness = self.ring_thickness.to_metric().optimize() - self.gap = self.gap.to_metric().optimize() - self.crosshair_thickness = self.crosshair_thickness.to_metric().optimize() - self.crosshair_length = self.crosshair_length.to_metric().optimize() - - def to_gerber(self, settings=None): - data = dict(code = self.code, - x = self.x.to_gerber(settings), - y = self.y.to_gerber(settings), - diameter = self.diameter.to_gerber(settings), - ring_thickness = self.ring_thickness.to_gerber(settings), - gap = self.gap.to_gerber(settings), - max_rings = self.max_rings.to_gerber(settings), - crosshair_thickness = self.crosshair_thickness.to_gerber(settings), - crosshair_length = self.crosshair_length.to_gerber(settings), - rotation = self.rotation.to_gerber(settings)) - return '{code},{x},{y},{diameter},{ring_thickness},{gap},{max_rings},'\ - '{crosshair_thickness},{crosshair_length},{rotation}*'.format(**data) - - def to_instructions(self): - modifiers = [self.x, self.y, self.diameter, - self.ring_thickness, self.gap, self.max_rings, - self.crosshair_thickness, self.crosshair_length, - self.rotation] - for modifier in modifiers: - for i in modifier.to_instructions(): - yield i - yield (OpCode.PRIM, self.code) - -class AMThermalPrimitiveDef(AMPrimitiveDef): - @classmethod - def from_modifiers(cls, code, modifiers): - code = code - exposure = 'on' - x = modifiers[0] - y = modifiers[1] - outer_diameter = modifiers[2] - inner_diameter = modifiers[3] - gap = modifiers[4] - rotation = modifiers[5] - return cls(code, exposure, x, y, outer_diameter, inner_diameter, gap, rotation) - - def __init__(self, code, exposure, x, y, outer_diameter, inner_diameter, gap, rotation): - super(AMThermalPrimitiveDef, self).__init__(code, exposure, rotation) - self.x = x - self.y = y - self.outer_diameter = outer_diameter - self.inner_diameter = inner_diameter - self.gap = gap - - def to_inch(self): - self.x = self.x.to_inch().optimize() - self.y = self.y.to_inch().optimize() - self.outer_diameter = self.outer_diameter.to_inch().optimize() - self.inner_diameter = self.inner_diameter.to_inch().optimize() - self.gap = self.gap.to_inch().optimize() - - def to_metric(self): - self.x = self.x.to_metric().optimize() - self.y = self.y.to_metric().optimize() - self.outer_diameter = self.outer_diameter.to_metric().optimize() - self.inner_diameter = self.inner_diameter.to_metric().optimize() - self.gap = self.gap.to_metric().optimize() - - def to_gerber(self, settings=None): - data = dict(code = self.code, - x = self.x.to_gerber(settings), - y = self.y.to_gerber(settings), - outer_diameter = self.outer_diameter.to_gerber(settings), - inner_diameter = self.inner_diameter.to_gerber(settings), - gap = self.gap.to_gerber(settings), - rotation = self.rotation.to_gerber(settings)) - return '{code},{x},{y},{outer_diameter},{inner_diameter},'\ - '{gap},{rotation}*'.format(**data) - - def to_instructions(self): - modifiers = [self.x, self.y, self.outer_diameter, - self.inner_diameter, self.gap, self.rotation] - for modifier in modifiers: - for i in modifier.to_instructions(): - yield i - yield (OpCode.PRIM, self.code) - -class AMVariableDef(object): - def __init__(self, number, value): - self.number = number - self.value = value - - def to_inch(self): - return self - - def to_metric(self): - return self - - def to_gerber(self, settings=None): - return '$%d=%s*' % (self.number, self.value.to_gerber(settings)) - - def to_instructions(self): - for i in self.value.to_instructions(): - yield i - yield (OpCode.STORE, self.number) - - def rotate(self, angle, center=None): - pass - diff --git a/gerbonara/gerber/panelize/common.py b/gerbonara/gerber/panelize/common.py deleted file mode 100644 index aa3ba0e..0000000 --- a/gerbonara/gerber/panelize/common.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -# Copyright 2019 Hiroshi Murayama - -import os -from ..common import loads as loads_org -from ..exceptions import ParseError -from ..utils import detect_file_format -from .. import rs274x -from .. import ipc356 - -from . import excellon - -def read(filename, format=None): - with open(filename, 'r') as f: - data = f.read() - return loads(data, filename, format=format) - - -def loads(data, filename=None, format=None): - # if os.path.splitext(filename if filename else '')[1].lower() == '.dxf': - # return dxf.loads(data, filename) - - fmt = detect_file_format(data) - if fmt == 'excellon': - return excellon.loads(data, filename=filename, format=format) - elif fmt == 'ipc_d_356': - return ipc356.loads(data, filename=filename) - else: - raise ParseError('Unable to detect file format') - - -# def rectangle(width, height, left=0, bottom=0, units='metric', draw_mode=None, filename=None): -# return dxf.DxfFile.rectangle( -# width, height, left, bottom, units, draw_mode, filename) diff --git a/gerbonara/gerber/tests/panelize/test_am_expression.py b/gerbonara/gerber/tests/panelize/test_am_expression.py index bed04a6..45758b7 100644 --- a/gerbonara/gerber/tests/panelize/test_am_expression.py +++ b/gerbonara/gerber/tests/panelize/test_am_expression.py @@ -4,8 +4,8 @@ # Copyright 2019 Hiroshi Murayama import unittest -from ...panelize.am_expression import * -from ...panelize.am_expression import AMOperatorExpression as Op +from ...am_expression import * +from ...am_expression import AMOperatorExpression as Op from ...utils import inch, metric from ...am_read import read_macro -- cgit