Fix critical issue with rotatin points (when the angle is zero the y would be flipped). Render AM with outline to gerber
This commit is contained in:
parent
29c0d82bf5
commit
223a010831
6 changed files with 89 additions and 14 deletions
|
|
@ -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)))
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue