start arc

This commit is contained in:
Hamilton Kibbe 2014-10-08 22:49:49 -04:00
parent 1653ae5cbe
commit bcb6cbc50d
5 changed files with 116 additions and 47 deletions

View file

@ -206,6 +206,13 @@ class GerberParser(object):
while did_something and len(line) > 0:
did_something = False
# region mode
#if 'G36' in line or 'G37' in line:
# yield RegionModeStmt.from_gerber(line)
# did_something = True
# line = ''
# continue
# coord
(coord, r) = self._match_one(self.COORD_STMT, line)
if coord:

View file

@ -12,7 +12,7 @@ from .utils import parse_gerber_value, write_gerber_value, decimal_string
__all__ = ['FSParamStmt', 'MOParamStmt', 'IPParamStmt', 'OFParamStmt',
'LPParamStmt', 'ADParamStmt', 'AMParamStmt', 'INParamStmt',
'LNParamStmt', 'CoordStmt', 'ApertureStmt', 'CommentStmt',
'EofStmt', 'UnknownStmt']
'EofStmt', 'QuadrantModeStmt', 'RegionModeStmt', 'UnknownStmt']
class Statement(object):
@ -601,7 +601,7 @@ class QuadrantModeStmt(Statement):
def __init__(self, mode):
super(QuadrantModeStmt, self).__init__('Quadrant Mode')
mode = mode.lower
mode = mode.lower()
if mode not in ['single-quadrant', 'multi-quadrant']:
raise ValueError('Quadrant mode must be "single-quadrant" \
or "multi-quadrant"')
@ -610,6 +610,25 @@ class QuadrantModeStmt(Statement):
def to_gerber(self):
return 'G74*' if self.mode == 'single-quadrant' else 'G75*'
class RegionModeStmt(Statement):
@classmethod
def from_gerber(cls, line):
line = line.strip()
if 'G36' not in line and 'G37' not in line:
raise ValueError('%s is not a valid region mode statement' % line)
return (cls('on') if line[:3] == 'G36' else cls('off'))
def __init__(self, mode):
super(RegionModeStmt, self).__init__('Region Mode')
mode = mode.lower()
if mode not in ['on', 'off']:
raise ValueError('Valid modes are "on" or "off"')
self.mode = mode
def to_gerber(self):
return 'G36*' if self.mode == 'on' else 'G37*'
class UnknownStmt(Statement):
""" Unknown Statement

View file

@ -22,16 +22,31 @@ gerber.render.apertures
This module provides base classes for gerber apertures. These are used by
the rendering engine to draw the gerber file.
"""
import math
class Aperture(object):
""" Gerber Aperture base class
"""
def draw(self, ctx, x, y):
raise NotImplementedError('The draw method must be implemented in an Aperture subclass.')
raise NotImplementedError('The draw method must be implemented \
in an Aperture subclass.')
def flash(self, ctx, x, y):
raise NotImplementedError('The flash method must be implemented in an Aperture subclass.')
raise NotImplementedError('The flash method must be implemented \
in an Aperture subclass.')
def _arc_params(self, startx, starty, x, y, i, j):
center = (startx + i, starty + j)
radius = math.sqrt(math.pow(center[0] - x, 2) +
math.pow(center[1] - y, 2))
delta_x0 = startx - center[0]
delta_y0 = center[1] - starty
delta_x1 = x - center[0]
delta_y1 = center[1] - y
start_angle = math.atan2(delta_y0, delta_x0)
end_angle = math.atan2(delta_y1, delta_x1)
return {'center': center, 'radius': radius,
'start_angle': start_angle, 'end_angle': end_angle}
class Circle(Aperture):

View file

@ -22,19 +22,20 @@ from ..gerber_statements import (
class GerberContext(object):
settings = {}
x = 0
y = 0
aperture = 0
interpolation = 'linear'
image_polarity = 'positive'
level_polarity = 'dark'
def __init__(self):
pass
self.settings = {}
self.x = 0
self.y = 0
self.aperture = 0
self.interpolation = 'linear'
self.direction = 'clockwise'
self.image_polarity = 'positive'
self.level_polarity = 'dark'
self.region_mode = 'off'
self.color = (0.7215, 0.451, 0.200)
self.drill_color = (0.25, 0.25, 0.25)
def set_format(self, settings):
self.settings = settings
@ -62,6 +63,12 @@ class GerberContext(object):
def set_aperture(self, d):
self.aperture = d
def set_color(self, color):
self.color = color
def set_drill_color(self, color):
self.drill_color = color
def resolve(self, x, y):
x = x if x is not None else self.x
y = y if y is not None else self.y
@ -76,13 +83,13 @@ class GerberContext(object):
else:
self.x, self.y = x, y
def stroke(self, x, y):
def stroke(self, x, y, i, j):
pass
def line(self, x, y):
pass
def arc(self, x, y):
def arc(self, x, y, i, j):
pass
def flash(self, x, y):
@ -109,7 +116,8 @@ class GerberContext(object):
def _evaluate_param(self, stmt):
if stmt.param == "FS":
self.set_coord_format(stmt.zero_suppression, stmt.format, stmt.notation)
self.set_coord_format(stmt.zero_suppression, stmt.format,
stmt.notation)
self.set_coord_notation(stmt.notation)
elif stmt.param == "MO:":
self.set_coord_unit(stmt.mode)
@ -123,9 +131,11 @@ class GerberContext(object):
def _evaluate_coord(self, stmt):
if stmt.function in ("G01", "G1", "G02", "G2", "G03", "G3"):
self.set_interpolation(stmt.function)
if stmt.function not in ('G01', 'G1'):
self.direction = ('clockwise' if stmt.function in ('G02', 'G2')
else 'counterclockwise')
if stmt.op == "D01":
self.stroke(stmt.x, stmt.y)
self.stroke(stmt.x, stmt.y, stmt.i, stmt.j)
elif stmt.op == "D02":
self.move(stmt.x, stmt.y)
elif stmt.op == "D03":

View file

@ -23,64 +23,71 @@ import svgwrite
SCALE = 300
def convert_color(color):
color = tuple([int(ch * 255) for ch in color])
return 'rgb(%d, %d, %d)' % color
class SvgCircle(Circle):
def draw(self, ctx, x, y):
def line(self, ctx, x, y, color='rgb(184, 115, 51)'):
return ctx.dwg.line(start=(ctx.x * SCALE, -ctx.y * SCALE),
end=(x * SCALE, -y * SCALE),
stroke="rgb(184, 115, 51)",
stroke=color,
stroke_width=SCALE * self.diameter,
stroke_linecap="round")
def flash(self, ctx, x, y):
def arc(self, ctx, x, y, i, j, direction, color='rgb(184, 115, 51)'):
pass
def flash(self, ctx, x, y, color='rgb(184, 115, 51)'):
return [ctx.dwg.circle(center=(x * SCALE, -y * SCALE),
r = SCALE * (self.diameter / 2.0),
fill='rgb(184, 115, 51)'), ]
fill=color), ]
class SvgRect(Rect):
def draw(self, ctx, x, y):
def line(self, ctx, x, y, color='rgb(184, 115, 51)'):
return ctx.dwg.line(start=(ctx.x * SCALE, -ctx.y * SCALE),
end=(x * SCALE, -y * SCALE),
stroke="rgb(184, 115, 51)", stroke_width=2,
stroke=color, stroke_width=2,
stroke_linecap="butt")
def flash(self, ctx, x, y):
def flash(self, ctx, x, y, color='rgb(184, 115, 51)'):
xsize, ysize = self.size
return [ctx.dwg.rect(insert=(SCALE * (x - (xsize / 2)),
-SCALE * (y + (ysize / 2))),
size=(SCALE * xsize, SCALE * ysize),
fill="rgb(184, 115, 51)"), ]
fill=color), ]
class SvgObround(Obround):
def draw(self, ctx, x, y):
def line(self, ctx, x, y, color='rgb(184, 115, 51)'):
pass
def flash(self, ctx, x, y):
def flash(self, ctx, x, y, color='rgb(184, 115, 51)'):
xsize, ysize = self.size
# horizontal obround
if xsize == ysize:
return [ctx.dwg.circle(center=(x * SCALE, -y * SCALE),
r = SCALE * (x / 2.0),
fill='rgb(184, 115, 51)'), ]
fill=color), ]
if xsize > ysize:
rectx = xsize - ysize
recty = ysize
lcircle = ctx.dwg.circle(center=((x - (rectx / 2.0)) * SCALE,
-y * SCALE),
r = SCALE * (ysize / 2.0),
fill='rgb(184, 115, 51)')
fill=color)
rcircle = ctx.dwg.circle(center=((x + (rectx / 2.0)) * SCALE,
-y * SCALE),
r = SCALE * (ysize / 2.0),
fill='rgb(184, 115, 51)')
fill=color)
rect = ctx.dwg.rect(insert=(SCALE * (x - (xsize / 2.)),
-SCALE * (y + (ysize / 2.))),
size=(SCALE * xsize, SCALE * ysize),
fill='rgb(184, 115, 51)')
fill=color)
return [lcircle, rcircle, rect, ]
# Vertical obround
@ -90,17 +97,17 @@ class SvgObround(Obround):
lcircle = ctx.dwg.circle(center=(x * SCALE,
(y - (recty / 2.)) * -SCALE),
r = SCALE * (xsize / 2.),
fill='rgb(184, 115, 51)')
fill=color)
ucircle = ctx.dwg.circle(center=(x * SCALE,
(y + (recty / 2.)) * -SCALE),
r = SCALE * (xsize / 2.),
fill='rgb(184, 115, 51)')
fill=color)
rect = ctx.dwg.rect(insert=(SCALE * (x - (xsize / 2.)),
-SCALE * (y + (ysize / 2.))),
size=(SCALE * xsize, SCALE * ysize),
fill='rgb(184, 115, 51)')
fill=color)
return [lcircle, ucircle, rect, ]
@ -116,7 +123,9 @@ class GerberSvgContext(GerberContext):
xbounds, ybounds = bounds
size = (SCALE * (xbounds[1] - xbounds[0]), SCALE * (ybounds[1] - ybounds[0]))
if not self.background:
self.dwg.add(self.dwg.rect(insert=(SCALE * xbounds[0], -SCALE * ybounds[1]), size=size, fill="black"))
self.dwg.add(self.dwg.rect(insert=(SCALE * xbounds[0],
-SCALE * ybounds[1]),
size=size, fill="black"))
self.background = True
def define_aperture(self, d, shape, modifiers):
@ -129,13 +138,13 @@ class GerberSvgContext(GerberContext):
aperture = SvgObround(size=modifiers[0][0:2])
self.apertures[d] = aperture
def stroke(self, x, y):
super(GerberSvgContext, self).stroke(x, y)
def stroke(self, x, y, i, j):
super(GerberSvgContext, self).stroke(x, y, i, j)
if self.interpolation == 'linear':
self.line(x, y)
elif self.interpolation == 'arc':
self.arc(x, y)
self.arc(x, y, i, j)
def line(self, x, y):
super(GerberSvgContext, self).line(x, y)
@ -143,11 +152,18 @@ class GerberSvgContext(GerberContext):
ap = self.apertures.get(self.aperture, None)
if ap is None:
return
self.dwg.add(ap.draw(self, x, y))
self.dwg.add(ap.line(self, x, y, convert_color(self.color)))
self.move(x, y, resolve=False)
def arc(self, x, y):
super(GerberSvgContext, self).arc(x, y)
def arc(self, x, y, i, j):
super(GerberSvgContext, self).arc(x, y, i, j)
x, y = self.resolve(x, y)
ap = self.apertures.get(self.aperture, None)
if ap is None:
return
#self.dwg.add(ap.arc(self, x, y, i, j, self.direction,
# convert_color(self.color)))
self.move(x, y, resolve=False)
def flash(self, x, y):
super(GerberSvgContext, self).flash(x, y)
@ -155,12 +171,14 @@ class GerberSvgContext(GerberContext):
ap = self.apertures.get(self.aperture, None)
if ap is None:
return
for shape in ap.flash(self, x, y):
for shape in ap.flash(self, x, y, convert_color(self.color)):
self.dwg.add(shape)
self.move(x, y, resolve=False)
def drill(self, x, y, diameter):
hit = self.dwg.circle(center=(x*SCALE, -y*SCALE), r=SCALE*(diameter/2.0), fill='gray')
hit = self.dwg.circle(center=(x*SCALE, -y*SCALE),
r=SCALE*(diameter/2.0),
fill=convert_color(self.drill_color))
self.dwg.add(hit)
def dump(self, filename):