summaryrefslogtreecommitdiff
path: root/gerberex/am_primitive.py
diff options
context:
space:
mode:
authorjaseg <git@jaseg.de>2021-06-06 13:28:42 +0200
committerjaseg <git@jaseg.de>2021-06-06 13:28:42 +0200
commit889ea37d9b66cbfb7a61795c7750b9f4311faa3f (patch)
tree34db36bcdf0501445aaec30c845ed644537e638a /gerberex/am_primitive.py
parent5a5ba2b709f01b2100cd767a25a41737541ad53c (diff)
parent71c371ca680483aa9ef18d2998832460dd43abdf (diff)
downloadgerbonara-889ea37d9b66cbfb7a61795c7750b9f4311faa3f.tar.gz
gerbonara-889ea37d9b66cbfb7a61795c7750b9f4311faa3f.tar.bz2
gerbonara-889ea37d9b66cbfb7a61795c7750b9f4311faa3f.zip
Graft pcb-tools-extension master onto gerbonara main
Diffstat (limited to 'gerberex/am_primitive.py')
-rw-r--r--gerberex/am_primitive.py448
1 files changed, 448 insertions, 0 deletions
diff --git a/gerberex/am_primitive.py b/gerberex/am_primitive.py
new file mode 100644
index 0000000..a3ad824
--- /dev/null
+++ b/gerberex/am_primitive.py
@@ -0,0 +1,448 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# Copyright 2019 Hiroshi Murayama <opiopan@gmail.com>
+
+from gerber.utils import *
+from gerber.am_statements import *
+from gerber.am_eval import OpCode
+
+from gerberex.am_expression import eval_macro, AMConstantExpression, AMOperatorExpression
+
+class AMPrimitiveDef(AMPrimitive):
+ 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
+
+ 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].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
+
+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)