More rendering of AMGroup to statements

This commit is contained in:
Garret Fick 2016-03-01 00:06:14 +08:00
parent 223a010831
commit 20a9af279a
5 changed files with 133 additions and 7 deletions

View file

@ -179,6 +179,10 @@ 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):
return cls(1, 'on', primitive.diameter, primitive.position)
def __init__(self, code, exposure, diameter, position):
validate_coordinates(position)
@ -247,6 +251,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(',')
@ -406,6 +415,9 @@ class AMOutlinePrimitive(AMPrimitive):
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)
@ -762,6 +774,8 @@ class AMThermalPrimitive(AMPrimitive):
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]:
@ -818,6 +832,14 @@ class AMCenterLinePrimitive(AMPrimitive):
------
ValueError, TypeError
"""
@classmethod
def from_primitive(cls, primitive):
width = primitive.width
height = primitive.height
center = primitive.position
rotation = math.degrees(primitive.rotation)
return cls(21, 'on', width, height, center, rotation)
@classmethod
def from_gerber(cls, primitive):

View file

@ -166,6 +166,10 @@ class FileSettings(object):
self.zero_suppression == other.zero_suppression and
self.format == other.format and
self.angle_units == other.angle_units)
def __str__(self):
return ('<Settings: %s %s %s %s %s>' %
(self.units, self.notation, self.zero_suppression, self.format, self.angle_units))
class CamFile(object):

View file

@ -93,6 +93,11 @@ class ParamStmt(Statement):
class FSParamStmt(ParamStmt):
""" FS - Gerber Format Specification Statement
"""
@classmethod
def from_settings(cls, settings):
return cls('FS', settings.zero_suppression, settings.notation, settings.format)
@classmethod
def from_dict(cls, stmt_dict):
@ -278,6 +283,11 @@ class ADParamStmt(ParamStmt):
'''Create a circular aperture definition statement'''
return cls('AD', dcode, 'C', ([diameter],))
@classmethod
def obround(cls, dcode, width, height):
'''Create an obrou d aperture definition statement'''
return cls('AD', dcode, 'O', ([width, height],))
@classmethod
def macro(cls, dcode, name):
return cls('AD', dcode, name, '')

View file

@ -397,6 +397,19 @@ class Circle(Primitive):
def offset(self, x_offset=0, y_offset=0):
self.position = tuple(map(add, self.position, (x_offset, y_offset)))
def equivalent(self, other, offset):
'''Is this the same as the other circle, ignoring the offiset?'''
if not isinstance(other, Circle):
return False
if self.diameter != other.diameter:
return False
equiv_position = tuple(map(add, other.position, offset))
return nearly_equal(self.position, equiv_position)
class Ellipse(Primitive):
@ -487,6 +500,19 @@ class Rectangle(Primitive):
return (math.cos(math.radians(self.rotation)) * self.height +
math.sin(math.radians(self.rotation)) * self.width)
def equivalent(self, other, offset):
'''Is this the same as the other rect, ignoring the offiset?'''
if not isinstance(other, Rectangle):
return False
if self.width != other.width or self.height != other.height or self.rotation != other.rotation:
return False
equiv_position = tuple(map(add, other.position, offset))
return nearly_equal(self.position, equiv_position)
class Diamond(Primitive):
"""
@ -815,6 +841,9 @@ class Outline(Primitive):
self.primitives = primitives
self._to_convert = ['primitives']
if self.primitives[0].start != self.primitives[-1].end:
raise ValueError('Outline must be closed')
@property
def flashed(self):
return True
@ -833,6 +862,9 @@ class Outline(Primitive):
def offset(self, x_offset=0, y_offset=0):
for p in self.primitives:
p.offset(x_offset, y_offset)
if self.primitives[0].start != self.primitives[-1].end:
raise ValueError('Outline must be closed')
@property
def width(self):

View file

@ -22,6 +22,14 @@ class AMGroupContext(object):
for primitive in nooffset_group.primitives:
if isinstance(primitive, Outline):
self._render_outline(primitive)
elif isinstance(primitive, Circle):
self._render_circle(primitive)
elif isinstance(primitive, Rectangle):
self._render_rectangle(primitive)
elif isinstance(primitive, Line):
self._render_line(primitive)
else:
raise ValueError('amgroup')
statement = AMParamStmt('AM', name, self._statements_to_string())
return statement
@ -33,10 +41,21 @@ class AMGroupContext(object):
macro += statement.to_gerber()
return macro
def _render_circle(self, circle):
self.statements.append(AMCirclePrimitive.from_primitive(circle))
def _render_rectangle(self, rectangle):
self.statements.append(AMCenterLinePrimitive.from_primitive(rectangle))
def _render_line(self, line):
self.statements.append(AMVectorLinePrimitive.from_primitive(line))
def _render_outline(self, outline):
self.statements.append(AMOutlinePrimitive.from_primitive(outline))
def _render_thermal(self, thermal):
pass
class Rs274xContext(GerberContext):
@ -59,6 +78,8 @@ class Rs274xContext(GerberContext):
self._next_dcode = 10
self._rects = {}
self._circles = {}
self._obrounds = {}
self._polygons = {}
self._macros = {}
self._i_none = 0
@ -67,9 +88,10 @@ class Rs274xContext(GerberContext):
self.settings = settings
self._start_header(settings)
self._define_dcodes()
#self._define_dcodes()
def _start_header(self, settings):
self.header.append(FSParamStmt.from_settings(settings))
self.header.append(MOParamStmt.from_units(settings.units))
def _define_dcodes(self):
@ -151,8 +173,12 @@ class Rs274xContext(GerberContext):
# We already set the function, so the next command doesn't require that
func = None
self.body.append(CoordStmt.line(func, self._simplify_point(line.end)))
self._pos = line.end
point = self._simplify_point(line.end)
# In some files, we see a lot of duplicated ponts, so omit those
if point[0] != None or point[1] != None:
self.body.append(CoordStmt.line(func, self._simplify_point(line.end)))
self._pos = line.end
def _render_arc(self, arc, color):
@ -269,10 +295,33 @@ class Rs274xContext(GerberContext):
aper = self._get_rectangle(rectangle.width, rectangle.height)
self._render_flash(rectangle, aper)
def _get_obround(self, width, height, dcode = None):
key = (width, height)
aper = self._obrounds.get(key, None)
if not aper:
if not dcode:
dcode = self._next_dcode
self._next_dcode += 1
else:
self._next_dcode = max(dcode + 1, self._next_dcode)
aper = ADParamStmt.obround(dcode, width, height)
self._obrounds[(width, height)] = aper
self.header.append(aper)
return aper
def _render_obround(self, obround, color):
aper = self._get_obround(obround.width, obround.height)
self._render_flash(obround, aper)
pass
def _render_polygon(self, polygon, color):
raise NotImplementedError('Not implemented yet')
pass
def _render_drill(self, circle, color):
@ -285,8 +334,19 @@ class Rs274xContext(GerberContext):
for primitive in amgroup.primitives:
hash += primitive.__class__.__name__[0]
bbox = primitive.bounding_box
hash += str((bbox[0][1] - bbox[0][0]) * 100000)[0:2]
hash += str((bbox[1][1] - bbox[1][0]) * 100000)[0:2]
if hasattr(primitive, 'primitives'):
hash += str(len(primitive.primitives))
if isinstance(primitive, Rectangle):
hash += str(primitive.width * 1000000)[0:2]
hash += str(primitive.height * 1000000)[0:2]
elif isinstance(primitive, Circle):
hash += str(primitive.diameter * 1000000)[0:2]
return hash
@ -331,9 +391,7 @@ class Rs274xContext(GerberContext):
aper = self._get_amacro(amgroup)
self._render_flash(amgroup, aper)
def _render_inverted_layer(self):
pass