diff options
Diffstat (limited to 'gerber/am_statements.py')
-rw-r--r-- | gerber/am_statements.py | 152 |
1 files changed, 69 insertions, 83 deletions
diff --git a/gerber/am_statements.py b/gerber/am_statements.py index 726df2f..31c0ae4 100644 --- a/gerber/am_statements.py +++ b/gerber/am_statements.py @@ -20,8 +20,6 @@ from math import asin import math from .primitives import * -from .primitives import Circle, Line, Outline, Polygon, Rectangle -from .utils import validate_coordinates, inch, metric from .utils import validate_coordinates, inch, metric, rotate_point @@ -75,7 +73,7 @@ class AMPrimitive(object): def to_metric(self): raise NotImplementedError('Subclass must implement `to-metric`') - + @property def _level_polarity(self): if self.exposure == 'off': @@ -190,9 +188,9 @@ class AMCirclePrimitive(AMPrimitive): diameter = float(modifiers[2]) position = (float(modifiers[3]), float(modifiers[4])) return cls(code, exposure, diameter, position) - + @classmethod - def from_primitive(cls, primitive): + def from_primitive(cls, primitive): return cls(1, 'on', primitive.diameter, primitive.position) def __init__(self, code, exposure, diameter, position): @@ -262,11 +260,11 @@ class AMVectorLinePrimitive(AMPrimitive): ------ ValueError, TypeError """ - + @classmethod def from_primitive(cls, primitive): return cls(2, 'on', primitive.aperture.width, primitive.start, primitive.end, 0) - + @classmethod def from_gerber(cls, primitive): modifiers = primitive.strip(' *').split(',') @@ -310,27 +308,27 @@ class AMVectorLinePrimitive(AMPrimitive): endy=self.end[1], rotation=self.rotation) return fmtstr.format(**data) - + def to_primitive(self, units): """ Convert this to a primitive. We use the Outline to represent this (instead of Line) because the behaviour of the end caps is different for aperture macros compared to Lines when rotated. """ - + # Use a line to generate our vertices easily line = Line(self.start, self.end, Rectangle(None, self.width, self.width)) vertices = line.vertices - + aperture = Circle((0, 0), 0) - + lines = [] prev_point = rotate_point(vertices[-1], self.rotation, (0, 0)) for point in vertices: cur_point = rotate_point(point, self.rotation, (0, 0)) - + lines.append(Line(prev_point, cur_point, aperture)) - + return Outline(lines, units=units, level_polarity=self._level_polarity) @@ -372,19 +370,19 @@ class AMOutlinePrimitive(AMPrimitive): ------ ValueError, TypeError """ - + @classmethod def from_primitive(cls, primitive): - + start_point = (round(primitive.primitives[0].start[0], 6), round(primitive.primitives[0].start[1], 6)) points = [] for prim in primitive.primitives: points.append((round(prim.end[0], 6), round(prim.end[1], 6))) - + rotation = 0.0 - + return cls(4, 'on', start_point, points, rotation) - + @classmethod def from_gerber(cls, primitive): modifiers = primitive.strip(' *').split(",") @@ -432,27 +430,26 @@ class AMOutlinePrimitive(AMPrimitive): points=",\n".join(["%.6g,%.6g" % point for point in self.points]), rotation=str(self.rotation) ) - # TODO I removed a closing asterix - not sure if this works for items with multiple statements - return "{code},{exposure},{n_points},{start_point},{points},\n{rotation}*".format(**data) - + return "{code},{exposure},{n_points},{start_point},{points},{rotation}*".format(**data) + def to_primitive(self, units): """ Convert this to a drawable primitive. This uses the Outline instead of Line primitive to handle differences in end caps when rotated. """ - + lines = [] prev_point = rotate_point(self.start_point, self.rotation) for point in self.points: cur_point = rotate_point(point, self.rotation) - + lines.append(Line(prev_point, cur_point, Circle((0,0), 0))) - + prev_point = cur_point - + if lines[0].start != lines[-1].end: raise ValueError('Outline must be closed') - + return Outline(lines, units=units, level_polarity=self._level_polarity) @@ -495,11 +492,11 @@ class AMPolygonPrimitive(AMPrimitive): ------ ValueError, TypeError """ - + @classmethod def from_primitive(cls, primitive): return cls(5, 'on', primitive.sides, primitive.position, primitive.diameter, primitive.rotation) - + @classmethod def from_gerber(cls, primitive): modifiers = primitive.strip(' *').split(",") @@ -548,7 +545,7 @@ class AMPolygonPrimitive(AMPrimitive): ) fmt = "{code},{exposure},{vertices},{position},{diameter},{rotation}*" return fmt.format(**data) - + def to_primitive(self, units): return Polygon(self.position, self.vertices, self.diameter / 2.0, 0, rotation=math.radians(self.rotation), units=units, level_polarity=self._level_polarity) @@ -647,6 +644,7 @@ class AMMoirePrimitive(AMPrimitive): self.crosshair_thickness = metric(self.crosshair_thickness) self.crosshair_length = metric(self.crosshair_length) + def to_gerber(self, settings=None): data = dict( code=self.code, @@ -663,7 +661,8 @@ class AMMoirePrimitive(AMPrimitive): return fmt.format(**data) def to_primitive(self, units): - raise NotImplementedError() + #raise NotImplementedError() + return None class AMThermalPrimitive(AMPrimitive): @@ -743,77 +742,77 @@ class AMThermalPrimitive(AMPrimitive): data = dict( code=self.code, position="%.4g,%.4g" % self.position, - outer_diameter = self.outer_diameter, - inner_diameter = self.inner_diameter, - gap = self.gap, - rotation = self.rotation + outer_diameter=self.outer_diameter, + inner_diameter=self.inner_diameter, + gap=self.gap, + rotation=self.rotation ) fmt = "{code},{position},{outer_diameter},{inner_diameter},{gap},{rotation}*" return fmt.format(**data) - + def _approximate_arc_cw(self, start_angle, end_angle, radius, center): """ Get an arc as a series of points - + Parameters ---------- start_angle : The start angle in radians end_angle : The end angle in radians radius`: Radius of the arc center : The center point of the arc (x, y) tuple - + Returns ------- array of point tuples """ - + # The total sweep sweep_angle = end_angle - start_angle num_steps = 10 - + angle_step = sweep_angle / num_steps - + radius = radius center = center - + points = [] - + for i in range(num_steps + 1): current_angle = start_angle + (angle_step * i) - + nextx = (center[0] + math.cos(current_angle) * radius) nexty = (center[1] + math.sin(current_angle) * radius) - + points.append((nextx, nexty)) - + return points def to_primitive(self, units): - + # We start with calculating the top right section, then duplicate it - + inner_radius = self.inner_diameter / 2.0 outer_radius = self.outer_diameter / 2.0 - + # Calculate the start angle relative to the horizontal axis inner_offset_angle = asin(self.gap / 2.0 / inner_radius) outer_offset_angle = asin(self.gap / 2.0 / outer_radius) - + rotation_rad = math.radians(self.rotation) inner_start_angle = inner_offset_angle + rotation_rad inner_end_angle = math.pi / 2 - inner_offset_angle + rotation_rad - + outer_start_angle = outer_offset_angle + rotation_rad outer_end_angle = math.pi / 2 - outer_offset_angle + rotation_rad - + outlines = [] aperture = Circle((0, 0), 0) - + points = (self._approximate_arc_cw(inner_start_angle, inner_end_angle, inner_radius, self.position) + list(reversed(self._approximate_arc_cw(outer_start_angle, outer_end_angle, outer_radius, self.position)))) # Add in the last point since outlines should be closed points.append(points[0]) - + # There are four outlines at rotated sections for rotation in [0, 90.0, 180.0, 270.0]: @@ -821,11 +820,11 @@ class AMThermalPrimitive(AMPrimitive): prev_point = rotate_point(points[0], rotation, self.position) for point in points[1:]: cur_point = rotate_point(point, rotation, self.position) - + lines.append(Line(prev_point, cur_point, aperture)) - + prev_point = cur_point - + outlines.append(Outline(lines, units=units, level_polarity=self._level_polarity)) return outlines @@ -869,7 +868,7 @@ class AMCenterLinePrimitive(AMPrimitive): ------ ValueError, TypeError """ - + @classmethod def from_primitive(cls, primitive): width = primitive.width @@ -912,9 +911,9 @@ class AMCenterLinePrimitive(AMPrimitive): def to_gerber(self, settings=None): data = dict( code=self.code, - exposure='1' if self.exposure == 'on' else '0', - width=self.width, - height=self.height, + exposure = '1' if self.exposure == 'on' else '0', + width = self.width, + height = self.height, center="%.4g,%.4g" % self.center, rotation=self.rotation ) @@ -922,27 +921,27 @@ class AMCenterLinePrimitive(AMPrimitive): return fmt.format(**data) def to_primitive(self, units): - + x = self.center[0] y = self.center[1] half_width = self.width / 2.0 half_height = self.height / 2.0 - + points = [] points.append((x - half_width, y + half_height)) points.append((x - half_width, y - half_height)) points.append((x + half_width, y - half_height)) points.append((x + half_width, y + half_height)) - + aperture = Circle((0, 0), 0) - + lines = [] prev_point = rotate_point(points[3], self.rotation, self.center) for point in points: cur_point = rotate_point(point, self.rotation, self.center) - + lines.append(Line(prev_point, cur_point, aperture)) - + return Outline(lines, units=units, level_polarity=self._level_polarity) @@ -998,7 +997,7 @@ class AMLowerLeftLinePrimitive(AMPrimitive): def __init__(self, code, exposure, width, height, lower_left, rotation): if code != 22: raise ValueError('LowerLeftLinePrimitive code is 22') - super(AMLowerLeftLinePrimitive, self).__init__(code, exposure) + super (AMLowerLeftLinePrimitive, self).__init__(code, exposure) self.width = width self.height = height validate_coordinates(lower_left) @@ -1015,21 +1014,12 @@ class AMLowerLeftLinePrimitive(AMPrimitive): self.width = metric(self.width) self.height = metric(self.height) - def to_primitive(self, units): - # TODO I think I have merged this wrong - # Offset the primitive from macro position - position = tuple([pos + offset for pos, offset in - zip(self.lower_left, (self.width/2, self.height/2))]) - # Return a renderable primitive - return Rectangle(position, self.width, self.height, - level_polarity=self._level_polarity, units=units) - def to_gerber(self, settings=None): data = dict( code=self.code, - exposure='1' if self.exposure == 'on' else '0', - width=self.width, - height=self.height, + exposure = '1' if self.exposure == 'on' else '0', + width = self.width, + height = self.height, lower_left="%.4g,%.4g" % self.lower_left, rotation=self.rotation ) @@ -1038,7 +1028,6 @@ class AMLowerLeftLinePrimitive(AMPrimitive): class AMUnsupportPrimitive(AMPrimitive): - @classmethod def from_gerber(cls, primitive): return cls(primitive) @@ -1055,6 +1044,3 @@ class AMUnsupportPrimitive(AMPrimitive): def to_gerber(self, settings=None): return self.primitive - - def to_primitive(self, units): - return None
\ No newline at end of file |