From 9febca7da6a730b3b3ca3a54129a9f88e5c44d14 Mon Sep 17 00:00:00 2001 From: opiopan Date: Thu, 21 Mar 2019 22:00:32 +0900 Subject: initial commit --- gerberex/am_primitive.py | 437 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 437 insertions(+) create mode 100644 gerberex/am_primitive.py (limited to 'gerberex/am_primitive.py') diff --git a/gerberex/am_primitive.py b/gerberex/am_primitive.py new file mode 100644 index 0000000..3ce047a --- /dev/null +++ b/gerberex/am_primitive.py @@ -0,0 +1,437 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright 2019 Hiroshi Murayama + +from gerber.utils import * +from gerber.am_statements import * +from gerber.am_eval import OpCode + +from gerberex.am_expression import eval_macro + +class AMPrimitiveDef(AMPrimitive): + def __init__(self, code, exposure=None, rotation=0): + super(AMPrimitiveDef, self).__init__(code, exposure) + self.rotation = rotation + + def to_inch(self): + pass + + def to_metric(self): + pass + + def to_gerber(self, settings=None): + pass + + def to_instructions(self): + pass + +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 + + def to_gerber(self, settings=None): + return '%d %s*' % (self.code, self.comment.to_gerber()) + + def to_instructions(self): + return [(OpCode.PUSH, self.comment), (OpCode.PRIM, self.code)] + +class AMCirclePrimitiveDef(AMPrimitiveDef): + @classmethod + def from_modifiers(cls, code, modifiers): + exposure = 'on' if modifiers[0] == 1 else 'off', + diameter = modifiers[1], + center_x = modifiers[2], + center_y = modifiers[3], + rotation = modifiers[4] + return cls(code, expressions, 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] == 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_x.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_x.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] == 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 = modifiers[1] + 1 + code = code + exposure = 'on' if modifiers[0] == 1 else 'off' + addrs = modifiers[2:num_points * 2] + rotation = modifiers[3 + 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() for i in self.addrs] + + def to_metric(self): + self.addrs = [i.to_metric() 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] == 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_inch().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 to_primitive_defs(instructions): + classes = { + 0: AMCommentPrimitiveDef, + 1: AMCirclePrimitiveDef, + 2: AMVectorLinePrimitiveDef, + 20: AMVectorLinePrimitiveDef, + 21: AMCenterLinePrimitiveDef, + 4: AMOutlinePrimitiveDef, + 5: AMPolygonPrimitiveDef, + 6: AMMoirePrimitiveDef, + 7: AMThermalPrimitiveDef, + } + 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) \ No newline at end of file -- cgit From 690df56bb71020901167605a87ec451081fa18d7 Mon Sep 17 00:00:00 2001 From: opiopan Date: Sat, 23 Mar 2019 21:59:13 +0900 Subject: add rotation fuction --- gerberex/am_primitive.py | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) (limited to 'gerberex/am_primitive.py') diff --git a/gerberex/am_primitive.py b/gerberex/am_primitive.py index 3ce047a..82370f6 100644 --- a/gerberex/am_primitive.py +++ b/gerberex/am_primitive.py @@ -7,13 +7,21 @@ from gerber.utils import * from gerber.am_statements import * from gerber.am_eval import OpCode -from gerberex.am_expression import eval_macro +from gerberex.am_expression import eval_macro, AMConstantExpression, AMOperatorExpression class AMPrimitiveDef(AMPrimitive): - def __init__(self, code, exposure=None, rotation=0): + def __init__(self, code, exposure=None, rotation=None): super(AMPrimitiveDef, self).__init__(code, exposure) + if not rotation: + rotation = AMConstantExpression(0) self.rotation = rotation + def rotate(self, angle, center=None): + self.rotation = AMOperatorExpression(AMOperatorExpression.ADD, + self.rotation, + AMConstantExpression(float(angle))) + self.rotation = self.rotation.optimize() + def to_inch(self): pass @@ -44,12 +52,12 @@ class AMCommentPrimitiveDef(AMPrimitiveDef): class AMCirclePrimitiveDef(AMPrimitiveDef): @classmethod def from_modifiers(cls, code, modifiers): - exposure = 'on' if modifiers[0] == 1 else 'off', - diameter = modifiers[1], - center_x = modifiers[2], - center_y = modifiers[3], + exposure = 'on' if modifiers[0].value == 1 else 'off' + diameter = modifiers[1] + center_x = modifiers[2] + center_y = modifiers[3] rotation = modifiers[4] - return cls(code, expressions, center_x, center_y, rotation) + 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) @@ -87,7 +95,7 @@ class AMVectorLinePrimitiveDef(AMPrimitiveDef): @classmethod def from_modifiers(cls, code, modifiers): code = code - exposure = 'on' if modifiers[0] == 1 else 'off' + exposure = 'on' if modifiers[0].value == 1 else 'off' width = modifiers[1] start_x = modifiers[2] start_y = modifiers[3] @@ -141,7 +149,7 @@ class AMCenterLinePrimitiveDef(AMPrimitiveDef): @classmethod def from_modifiers(cls, code, modifiers): code = code - exposure = 'on' if modifiers[0] == 1 else 'off' + exposure = 'on' if modifiers[0].value == 1 else 'off' width = modifiers[1] height = modifiers[2] x = modifiers[3] @@ -191,7 +199,7 @@ class AMOutlinePrimitiveDef(AMPrimitiveDef): def from_modifiers(cls, code, modifiers): num_points = modifiers[1] + 1 code = code - exposure = 'on' if modifiers[0] == 1 else 'off' + exposure = 'on' if modifiers[0].value == 1 else 'off' addrs = modifiers[2:num_points * 2] rotation = modifiers[3 + num_points * 2] return cls(code, exposure, addrs, rotation) @@ -231,7 +239,7 @@ class AMPolygonPrimitiveDef(AMPrimitiveDef): @classmethod def from_modifiers(cls, code, modifiers): code = code - exposure = 'on' if modifiers[0] == 1 else 'off' + exposure = 'on' if modifiers[0].value == 1 else 'off' vertices = modifiers[1] x = modifiers[2] y = modifiers[3] @@ -417,6 +425,9 @@ class AMVariableDef(object): yield i yield (OpCode.STORE, self.number) + def rotate(self, angle, center=None): + pass + def to_primitive_defs(instructions): classes = { 0: AMCommentPrimitiveDef, @@ -434,4 +445,4 @@ def to_primitive_defs(instructions): yield AMVariableDef(-code, modifiers[0]) else: primitive = classes[code] - yield primitive.from_modifiers(code, modifiers) \ No newline at end of file + yield primitive.from_modifiers(code, modifiers) -- cgit From e3c59e39cf9bc64ce9d76c324b82956a65515f16 Mon Sep 17 00:00:00 2001 From: opiopan Date: Sun, 7 Apr 2019 22:22:33 +0900 Subject: expand test and fix many issues --- gerberex/am_primitive.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'gerberex/am_primitive.py') diff --git a/gerberex/am_primitive.py b/gerberex/am_primitive.py index 82370f6..df55573 100644 --- a/gerberex/am_primitive.py +++ b/gerberex/am_primitive.py @@ -117,14 +117,14 @@ class AMVectorLinePrimitiveDef(AMPrimitiveDef): 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_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_x.to_metric().optimize() + self.end_y = self.end_y.to_metric().optimize() def to_gerber(self, settings=None): data = dict(code = self.code, @@ -197,11 +197,11 @@ class AMCenterLinePrimitiveDef(AMPrimitiveDef): class AMOutlinePrimitiveDef(AMPrimitiveDef): @classmethod def from_modifiers(cls, code, modifiers): - num_points = modifiers[1] + 1 + num_points = int(modifiers[1].value + 1) code = code exposure = 'on' if modifiers[0].value == 1 else 'off' - addrs = modifiers[2:num_points * 2] - rotation = modifiers[3 + num_points * 2] + 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): @@ -209,10 +209,10 @@ class AMOutlinePrimitiveDef(AMPrimitiveDef): self.addrs = addrs def to_inch(self): - self.addrs = [i.to_inch() for i in self.addrs] + self.addrs = [i.to_inch().optimize() for i in self.addrs] def to_metric(self): - self.addrs = [i.to_metric() for i in self.addrs] + self.addrs = [i.to_metric().optimize() for i in self.addrs] def to_gerber(self, settings=None): def strs(): @@ -262,7 +262,7 @@ class AMPolygonPrimitiveDef(AMPrimitiveDef): def to_metric(self): self.x = self.x.to_metric().optimize() self.y = self.y.to_metric().optimize() - self.diameter = self.diameter.to_inch().optimize() + self.diameter = self.diameter.to_metric().optimize() def to_gerber(self, settings=None): data = dict(code = self.code, -- cgit From 415bdbc2e4339d370afcd779344ea66e39ba6b0a Mon Sep 17 00:00:00 2001 From: Marin Mikaƫl <41113988+MarinMikael@users.noreply.github.com> Date: Wed, 24 Jul 2019 01:20:15 +0900 Subject: Update am_primitive.py Fix bug when circle doesn't have any rotation by adding a default 0 degree rotation. --- gerberex/am_primitive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gerberex/am_primitive.py') diff --git a/gerberex/am_primitive.py b/gerberex/am_primitive.py index df55573..a3ad824 100644 --- a/gerberex/am_primitive.py +++ b/gerberex/am_primitive.py @@ -56,7 +56,7 @@ class AMCirclePrimitiveDef(AMPrimitiveDef): diameter = modifiers[1] center_x = modifiers[2] center_y = modifiers[3] - rotation = modifiers[4] + 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): -- cgit