summaryrefslogtreecommitdiff
path: root/gerber
diff options
context:
space:
mode:
authorGarret Fick <garret@ficksworkshop.com>2016-02-27 18:18:04 +0800
committerGarret Fick <garret@ficksworkshop.com>2016-02-27 18:18:04 +0800
commit223a010831f0d9dae4bd6d2e626a603a78eb0b1d (patch)
treef8e341156d652990b79f182df65c321549222e74 /gerber
parent29c0d82bf53907030d11df9eb09471b716a0be2e (diff)
downloadgerbonara-223a010831f0d9dae4bd6d2e626a603a78eb0b1d.tar.gz
gerbonara-223a010831f0d9dae4bd6d2e626a603a78eb0b1d.tar.bz2
gerbonara-223a010831f0d9dae4bd6d2e626a603a78eb0b1d.zip
Fix critical issue with rotatin points (when the angle is zero the y would be flipped). Render AM with outline to gerber
Diffstat (limited to 'gerber')
-rw-r--r--gerber/am_statements.py24
-rw-r--r--gerber/cam.py1
-rw-r--r--gerber/gerber_statements.py4
-rw-r--r--gerber/primitives.py2
-rw-r--r--gerber/render/rs274x_backend.py61
-rw-r--r--gerber/utils.py11
6 files changed, 89 insertions, 14 deletions
diff --git a/gerber/am_statements.py b/gerber/am_statements.py
index 2bca6e6..05ebd9d 100644
--- a/gerber/am_statements.py
+++ b/gerber/am_statements.py
@@ -334,6 +334,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(",")
@@ -376,17 +389,18 @@ class AMOutlinePrimitive(AMPrimitive):
code=self.code,
exposure="1" if self.exposure == "on" else "0",
n_points=len(self.points),
- start_point="%.4g,%.4g" % self.start_point,
- points=",".join(["%.4g,%.4g" % point for point in self.points]),
+ start_point="%.6g,%.6g" % self.start_point,
+ points=",\n".join(["%.6g,%.6g" % point for point in self.points]),
rotation=str(self.rotation)
)
- return "{code},{exposure},{n_points},{start_point},{points},{rotation}*".format(**data)
+ # 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)
def to_primitive(self, units):
lines = []
- prev_point = rotate_point(self.points[0], self.rotation)
- for point in self.points[1:]:
+ 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)))
diff --git a/gerber/cam.py b/gerber/cam.py
index 08d80de..53f5c0d 100644
--- a/gerber/cam.py
+++ b/gerber/cam.py
@@ -255,6 +255,7 @@ class CamFile(object):
filename : string <optional>
If provided, save the rendered image to `filename`
"""
+
ctx.set_bounds(self.bounds)
ctx._paint_background()
if ctx.invert:
diff --git a/gerber/gerber_statements.py b/gerber/gerber_statements.py
index bb190f4..dcdd90d 100644
--- a/gerber/gerber_statements.py
+++ b/gerber/gerber_statements.py
@@ -168,6 +168,10 @@ class FSParamStmt(ParamStmt):
class MOParamStmt(ParamStmt):
""" MO - Gerber Mode (measurement units) Statement.
"""
+
+ @classmethod
+ def from_units(cls, units):
+ return cls(None, 'inch')
@classmethod
def from_dict(cls, stmt_dict):
diff --git a/gerber/primitives.py b/gerber/primitives.py
index 21efb55..07a28db 100644
--- a/gerber/primitives.py
+++ b/gerber/primitives.py
@@ -779,7 +779,7 @@ class AMGroup(Primitive):
if self._position:
dx = new_pos[0] - self._position[0]
- dy = new_pos[0] - self._position[0]
+ dy = new_pos[1] - self._position[1]
else:
dx = new_pos[0]
dy = new_pos[1]
diff --git a/gerber/render/rs274x_backend.py b/gerber/render/rs274x_backend.py
index 0094192..bdb77f4 100644
--- a/gerber/render/rs274x_backend.py
+++ b/gerber/render/rs274x_backend.py
@@ -1,12 +1,49 @@
from .render import GerberContext
+from ..am_statements import *
from ..gerber_statements import *
-from ..primitives import AMGroup, Arc, Circle, Line, Rectangle
+from ..primitives import AMGroup, Arc, Circle, Line, Outline, Rectangle
+from copy import deepcopy
+
+class AMGroupContext(object):
+ '''A special renderer to generate aperature macros from an AMGroup'''
+
+ def __init__(self):
+ self.statements = []
+
+ def render(self, amgroup, name):
+
+ # Clone ourselves, then offset by the psotion so that
+ # our render doesn't have to consider offset. Just makes things simplder
+ nooffset_group = deepcopy(amgroup)
+ nooffset_group.position = (0, 0)
+
+ # Now draw the shapes
+ for primitive in nooffset_group.primitives:
+ if isinstance(primitive, Outline):
+ self._render_outline(primitive)
+
+ statement = AMParamStmt('AM', name, self._statements_to_string())
+ return statement
+
+ def _statements_to_string(self):
+ macro = ''
+
+ for statement in self.statements:
+ macro += statement.to_gerber()
+
+ return macro
+
+ def _render_outline(self, outline):
+ self.statements.append(AMOutlinePrimitive.from_primitive(outline))
+
+
class Rs274xContext(GerberContext):
def __init__(self, settings):
GerberContext.__init__(self)
+ self.comments = []
self.header = []
self.body = []
self.end = [EofStmt()]
@@ -27,8 +64,13 @@ class Rs274xContext(GerberContext):
self._i_none = 0
self._j_none = 0
+ self.settings = settings
+
+ self._start_header(settings)
self._define_dcodes()
+ def _start_header(self, settings):
+ self.header.append(MOParamStmt.from_units(settings.units))
def _define_dcodes(self):
@@ -67,7 +109,7 @@ class Rs274xContext(GerberContext):
@property
def statements(self):
- return self.header + self.body + self.end
+ return self.comments + self.header + self.body + self.end
def set_bounds(self, bounds):
pass
@@ -93,6 +135,8 @@ class Rs274xContext(GerberContext):
def _render_line(self, line, color):
self._select_aperture(line.aperture)
+
+ self._render_level_polarity(line)
# Get the right function
if self._func != CoordStmt.FUNC_LINEAR:
@@ -125,6 +169,8 @@ class Rs274xContext(GerberContext):
# Select the right aperture if not already selected
self._select_aperture(arc.aperture)
+ self._render_level_polarity(arc)
+
# Find the right movement mode. Always set to be sure it is really right
dir = arc.direction
if dir == 'clockwise':
@@ -243,7 +289,7 @@ class Rs274xContext(GerberContext):
hash += str(len(primitive.primitives))
return hash
-
+
def _get_amacro(self, amgroup, dcode = None):
# Macros are a little special since we don't have a good way to compare them quickly
# but in most cases, this should work
@@ -261,8 +307,13 @@ class Rs274xContext(GerberContext):
# Create the statements
# TODO
- statements = []
+ amrenderer = AMGroupContext()
+ statement = amrenderer.render(amgroup, hash)
+
+ self.header.append(statement)
+
aperdef = ADParamStmt.macro(dcode, hash)
+ self.header.append(aperdef)
# Store the dcode and the original so we can check if it really is the same
macro = (aperdef, amgroup)
@@ -281,6 +332,8 @@ class Rs274xContext(GerberContext):
aper = self._get_amacro(amgroup)
self._render_flash(amgroup, aper)
+
+
def _render_inverted_layer(self):
pass
diff --git a/gerber/utils.py b/gerber/utils.py
index 16323d6..72bf2d1 100644
--- a/gerber/utils.py
+++ b/gerber/utils.py
@@ -284,10 +284,13 @@ def rotate_point(point, angle, center=(0.0, 0.0)):
`point` rotated about `center` by `angle` degrees.
"""
angle = radians(angle)
- xdelta, ydelta = tuple(map(sub, point, center))
- x = center[0] + (cos(angle) * xdelta) - (sin(angle) * ydelta)
- y = center[1] + (sin(angle) * xdelta) - (cos(angle) * ydelta)
- return (x, y)
+
+ cos_angle = cos(angle)
+ sin_angle = sin(angle)
+
+ return (
+ cos_angle * (point[0] - center[0]) - sin_angle * (point[1] - center[1]) + center[0],
+ sin_angle * (point[0] - center[0]) + cos_angle * (point[1] - center[1]) + center[1])
def nearly_equal(point1, point2, ndigits = 6):