summaryrefslogtreecommitdiff
path: root/gerber/render
diff options
context:
space:
mode:
authorGarret Fick <garret@ficksworkshop.com>2016-07-24 17:08:47 +0800
committerGarret Fick <garret@ficksworkshop.com>2016-07-24 17:08:47 +0800
commit7cd6acf12670f3773113f67ed2acb35cb21c32a0 (patch)
treece2d79376375b8c7b4ee8c0f519f23d3f3fc1db9 /gerber/render
parentcd4614f9973eb9f4ce858b3864573367614f54b6 (diff)
downloadgerbonara-7cd6acf12670f3773113f67ed2acb35cb21c32a0.tar.gz
gerbonara-7cd6acf12670f3773113f67ed2acb35cb21c32a0.tar.bz2
gerbonara-7cd6acf12670f3773113f67ed2acb35cb21c32a0.zip
Add many render tests based on the Umaco gerger specification. Fix multiple rendering bugs, especially related to holes in flashed apertures
Diffstat (limited to 'gerber/render')
-rw-r--r--gerber/render/cairo_backend.py105
-rw-r--r--gerber/render/rs274x_backend.py12
2 files changed, 90 insertions, 27 deletions
diff --git a/gerber/render/cairo_backend.py b/gerber/render/cairo_backend.py
index 0cb230b..78ccf34 100644
--- a/gerber/render/cairo_backend.py
+++ b/gerber/render/cairo_backend.py
@@ -20,13 +20,14 @@ try:
except ImportError:
import cairocffi as cairo
-from operator import mul, div
import math
+from operator import mul, div
import tempfile
+from ..primitives import *
from .render import GerberContext, RenderSettings
from .theme import THEMES
-from ..primitives import *
+
try:
from cStringIO import StringIO
@@ -219,15 +220,30 @@ class GerberCairoContext(GerberContext):
center = tuple(map(mul, circle.position, self.scale))
if not self.invert:
ctx = self.ctx
- ctx.set_source_rgba(*color, alpha=self.alpha)
+ ctx.set_source_rgba(color[0], color[1], color[2], alpha=self.alpha)
ctx.set_operator(cairo.OPERATOR_OVER if circle.level_polarity == "dark" else cairo.OPERATOR_CLEAR)
else:
ctx = self.mask_ctx
ctx.set_source_rgba(0.0, 0.0, 0.0, 1.0)
ctx.set_operator(cairo.OPERATOR_CLEAR)
+
+ if circle.hole_diameter > 0:
+ ctx.push_group()
+
ctx.set_line_width(0)
ctx.arc(center[0], center[1], radius=circle.radius * self.scale[0], angle1=0, angle2=2 * math.pi)
- ctx.fill()
+ ctx.fill()
+
+ if circle.hole_diameter > 0:
+ # Render the center clear
+
+ ctx.set_source_rgba(color[0], color[1], color[2], self.alpha)
+ ctx.set_operator(cairo.OPERATOR_CLEAR)
+ ctx.arc(center[0], center[1], radius=circle.hole_radius * self.scale[0], angle1=0, angle2=2 * math.pi)
+ ctx.fill()
+
+ ctx.pop_group_to_source()
+ ctx.paint_with_alpha(1)
def _render_rectangle(self, rectangle, color):
ll = map(mul, rectangle.lower_left, self.scale)
@@ -253,48 +269,95 @@ class GerberCairoContext(GerberContext):
ll[1] = ll[1] - center[1]
matrix.rotate(rectangle.rotation)
ctx.transform(matrix)
-
+
+ if rectangle.hole_diameter > 0:
+ ctx.push_group()
+
ctx.set_line_width(0)
ctx.rectangle(ll[0], ll[1], width, height)
ctx.fill()
+ if rectangle.hole_diameter > 0:
+ # Render the center clear
+ ctx.set_source_rgba(color[0], color[1], color[2], self.alpha)
+ ctx.set_operator(cairo.OPERATOR_CLEAR)
+ center = map(mul, rectangle.position, self.scale)
+ ctx.arc(center[0], center[1], radius=rectangle.hole_radius * self.scale[0], angle1=0, angle2=2 * math.pi)
+ ctx.fill()
+
+ ctx.pop_group_to_source()
+ ctx.paint_with_alpha(1)
+
if rectangle.rotation != 0:
ctx.restore()
def _render_obround(self, obround, color):
+
+ if not self.invert:
+ ctx = self.ctx
+ ctx.set_source_rgba(color[0], color[1], color[2], alpha=self.alpha)
+ ctx.set_operator(cairo.OPERATOR_OVER if obround.level_polarity == "dark" else cairo.OPERATOR_CLEAR)
+ else:
+ ctx = self.mask_ctx
+ ctx.set_source_rgba(0.0, 0.0, 0.0, 1.0)
+ ctx.set_operator(cairo.OPERATOR_CLEAR)
+
+ if obround.hole_diameter > 0:
+ ctx.push_group()
+
self._render_circle(obround.subshapes['circle1'], color)
self._render_circle(obround.subshapes['circle2'], color)
self._render_rectangle(obround.subshapes['rectangle'], color)
+ if obround.hole_diameter > 0:
+ # Render the center clear
+ ctx.set_source_rgba(color[0], color[1], color[2], self.alpha)
+ ctx.set_operator(cairo.OPERATOR_CLEAR)
+ center = map(mul, obround.position, self.scale)
+ ctx.arc(center[0], center[1], radius=obround.hole_radius * self.scale[0], angle1=0, angle2=2 * math.pi)
+ ctx.fill()
+
+ ctx.pop_group_to_source()
+ ctx.paint_with_alpha(1)
+
def _render_polygon(self, polygon, color):
+
+ # TODO Ths does not handle rotation of a polygon
+ if not self.invert:
+ ctx = self.ctx
+ ctx.set_source_rgba(color[0], color[1], color[2], alpha=self.alpha)
+ ctx.set_operator(cairo.OPERATOR_OVER if polygon.level_polarity == "dark" else cairo.OPERATOR_CLEAR)
+ else:
+ ctx = self.mask_ctx
+ ctx.set_source_rgba(0.0, 0.0, 0.0, 1.0)
+ ctx.set_operator(cairo.OPERATOR_CLEAR)
+
if polygon.hole_radius > 0:
- self.ctx.push_group()
+ ctx.push_group()
vertices = polygon.vertices
-
- self.ctx.set_source_rgba(color[0], color[1], color[2], self.alpha)
- self.ctx.set_operator(cairo.OPERATOR_OVER if (polygon.level_polarity == "dark" and not self.invert) else cairo.OPERATOR_CLEAR)
- self.ctx.set_line_width(0)
- self.ctx.set_line_cap(cairo.LINE_CAP_ROUND)
+
+ ctx.set_line_width(0)
+ ctx.set_line_cap(cairo.LINE_CAP_ROUND)
# Start from before the end so it is easy to iterate and make sure it is closed
- self.ctx.move_to(*map(mul, vertices[-1], self.scale))
+ ctx.move_to(*map(mul, vertices[-1], self.scale))
for v in vertices:
- self.ctx.line_to(*map(mul, v, self.scale))
+ ctx.line_to(*map(mul, v, self.scale))
- self.ctx.fill()
+ ctx.fill()
if polygon.hole_radius > 0:
# Render the center clear
center = tuple(map(mul, polygon.position, self.scale))
- self.ctx.set_source_rgba(color[0], color[1], color[2], self.alpha)
- self.ctx.set_operator(cairo.OPERATOR_CLEAR)
- self.ctx.set_line_width(0)
- self.ctx.arc(center[0], center[1], polygon.hole_radius * self.scale[0], 0, 2 * math.pi)
- self.ctx.fill()
+ ctx.set_source_rgba(color[0], color[1], color[2], self.alpha)
+ ctx.set_operator(cairo.OPERATOR_CLEAR)
+ ctx.set_line_width(0)
+ ctx.arc(center[0], center[1], polygon.hole_radius * self.scale[0], 0, 2 * math.pi)
+ ctx.fill()
- self.ctx.pop_group_to_source()
- self.ctx.paint_with_alpha(1)
+ ctx.pop_group_to_source()
+ ctx.paint_with_alpha(1)
def _render_drill(self, circle, color):
self._render_circle(circle, color)
diff --git a/gerber/render/rs274x_backend.py b/gerber/render/rs274x_backend.py
index 972edcb..15e9154 100644
--- a/gerber/render/rs274x_backend.py
+++ b/gerber/render/rs274x_backend.py
@@ -151,7 +151,7 @@ class Rs274xContext(GerberContext):
# Select the right aperture if not already selected
if aperture:
if isinstance(aperture, Circle):
- aper = self._get_circle(aperture.diameter)
+ aper = self._get_circle(aperture.diameter, aperture.hole_diameter)
elif isinstance(aperture, Rectangle):
aper = self._get_rectangle(aperture.width, aperture.height)
elif isinstance(aperture, Obround):
@@ -275,10 +275,10 @@ class Rs274xContext(GerberContext):
self._pos = primitive.position
- def _get_circle(self, diameter, dcode = None):
+ def _get_circle(self, diameter, hole_diameter, dcode = None):
'''Define a circlar aperture'''
- aper = self._circles.get(diameter, None)
+ aper = self._circles.get((diameter, hole_diameter), None)
if not aper:
if not dcode:
@@ -287,15 +287,15 @@ class Rs274xContext(GerberContext):
else:
self._next_dcode = max(dcode + 1, self._next_dcode)
- aper = ADParamStmt.circle(dcode, diameter)
- self._circles[diameter] = aper
+ aper = ADParamStmt.circle(dcode, diameter, hole_diameter)
+ self._circles[(diameter, hole_diameter)] = aper
self.header.append(aper)
return aper
def _render_circle(self, circle, color):
- aper = self._get_circle(circle.diameter)
+ aper = self._get_circle(circle.diameter, circle.hole_diameter)
self._render_flash(circle, aper)
def _get_rectangle(self, width, height, dcode = None):