diff options
Diffstat (limited to 'gerber/render')
-rw-r--r-- | gerber/render/apertures.py | 21 | ||||
-rw-r--r-- | gerber/render/render.py | 42 | ||||
-rw-r--r-- | gerber/render/svgwrite_backend.py | 70 |
3 files changed, 88 insertions, 45 deletions
diff --git a/gerber/render/apertures.py b/gerber/render/apertures.py index f163b1f..52ae50c 100644 --- a/gerber/render/apertures.py +++ b/gerber/render/apertures.py @@ -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): diff --git a/gerber/render/render.py b/gerber/render/render.py index e40960d..e7ec6ee 100644 --- a/gerber/render/render.py +++ b/gerber/render/render.py @@ -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": diff --git a/gerber/render/svgwrite_backend.py b/gerber/render/svgwrite_backend.py index 8d84da1..3b2f3c1 100644 --- a/gerber/render/svgwrite_backend.py +++ b/gerber/render/svgwrite_backend.py @@ -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): |