Add cairo example code, and use example-generated image in readme
This commit is contained in:
parent
5cf1fa74b4
commit
bfe1484160
16 changed files with 5869 additions and 22 deletions
17
Makefile
17
Makefile
|
|
@ -3,25 +3,32 @@ PYTHON ?= python
|
|||
NOSETESTS ?= nosetests
|
||||
|
||||
DOC_ROOT = doc
|
||||
EXAMPLES = examples
|
||||
|
||||
.PHONY: clean
|
||||
clean: doc-clean
|
||||
#$(PYTHON) setup.py clean
|
||||
find . -name '*.pyc' -delete
|
||||
rm -rf coverage .coverage
|
||||
rm -rf *.egg-info
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
$(NOSETESTS) -s -v gerber
|
||||
|
||||
|
||||
.PHONY: test-coverage
|
||||
test-coverage:
|
||||
rm -rf coverage .coverage
|
||||
$(NOSETESTS) -s -v --with-coverage --cover-package=gerber
|
||||
|
||||
|
||||
.PHONY: doc-html
|
||||
doc-html:
|
||||
(cd $(DOC_ROOT); make html)
|
||||
|
||||
|
||||
.PHONY: doc-clean
|
||||
doc-clean:
|
||||
(cd $(DOC_ROOT); make clean)
|
||||
|
||||
|
||||
.PHONY: examples
|
||||
examples:
|
||||
PYTHONPATH=. $(PYTHON) examples/cairo_example.py
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
pcb-tools
|
||||
============
|
||||

|
||||
[](https://travis-ci.org/curtacircuitos/pcb-tools)
|
||||
[](https://coveralls.io/r/curtacircuitos/pcb-tools?branch=master)
|
||||
|
||||
Tools to handle Gerber and Excellon files in Python.
|
||||
|
|
@ -25,7 +25,5 @@ Useage Example:
|
|||
Rendering Examples:
|
||||
-------------------
|
||||
###Top Composite rendering
|
||||

|
||||
|
||||
###Bottom Composite rendering
|
||||

|
||||

|
||||
Source code for this example can be found [here](examples/cairo_example.py).
|
||||
|
|
|
|||
BIN
examples/cairo_example.png
Normal file
BIN
examples/cairo_example.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 MiB |
68
examples/cairo_example.py
Normal file
68
examples/cairo_example.py
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2015 Hamilton Kibbe <ham@hamiltonkib.be>
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations under
|
||||
# the License.
|
||||
|
||||
"""
|
||||
This example demonstrates the use of pcb-tools with cairo to render a composite
|
||||
image from a set of gerber files. Each layer is loaded and drawn using a
|
||||
GerberCairoContext. The color and opacity of each layer can be set individually.
|
||||
Once all thedesired layers are drawn on the context, the context is written to
|
||||
a .png file.
|
||||
"""
|
||||
|
||||
import os
|
||||
from gerber import read
|
||||
from gerber.render import GerberCairoContext
|
||||
|
||||
GERBER_FOLDER = os.path.abspath(os.path.join(os.path.dirname(__file__), 'gerbers'))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Open the gerber files
|
||||
copper = read(os.path.join(GERBER_FOLDER, 'copper.GTL'))
|
||||
mask = read(os.path.join(GERBER_FOLDER, 'soldermask.GTS'))
|
||||
silk = read(os.path.join(GERBER_FOLDER, 'silkscreen.GTO'))
|
||||
drill = read(os.path.join(GERBER_FOLDER, 'ncdrill.DRD'))
|
||||
|
||||
|
||||
# Create a new drawing context
|
||||
ctx = GerberCairoContext()
|
||||
|
||||
# Draw the copper layer
|
||||
copper.render(ctx)
|
||||
|
||||
# Set opacity and color for soldermask layer
|
||||
ctx.alpha = 0.65
|
||||
ctx.color = (0.2, 0.2, 0.75)
|
||||
|
||||
# Draw the soldermask layer
|
||||
mask.render(ctx)
|
||||
|
||||
# Set opacity and color for silkscreen layer
|
||||
ctx.alpha = 0.9
|
||||
ctx.color = (1, 1, 1)
|
||||
|
||||
# Draw the silkscreen layer
|
||||
silk.render(ctx)
|
||||
|
||||
# Set opacity for drill layer
|
||||
ctx.alpha = 1.
|
||||
drill.render(ctx)
|
||||
|
||||
# Write output to png file
|
||||
ctx.dump(os.path.join(os.path.dirname(__file__), 'cairo_example.png'))
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 143 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 832 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 286 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 569 KiB |
3457
examples/gerbers/copper.GTL
Normal file
3457
examples/gerbers/copper.GTL
Normal file
File diff suppressed because it is too large
Load diff
51
examples/gerbers/ncdrill.DRD
Normal file
51
examples/gerbers/ncdrill.DRD
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
%
|
||||
M48
|
||||
M72
|
||||
T01C0.0236
|
||||
T02C0.0354
|
||||
T03C0.0400
|
||||
T04C0.1260
|
||||
T05C0.1280
|
||||
%
|
||||
T01
|
||||
X9250Y4064
|
||||
X12100Y5314
|
||||
X13500Y6864
|
||||
X15650Y6264
|
||||
X15200Y4514
|
||||
X13550Y8764
|
||||
X13350Y10114
|
||||
X13300Y11464
|
||||
X11650Y13164
|
||||
X10000Y15114
|
||||
X6500Y13714
|
||||
X4150Y11564
|
||||
X14250Y14964
|
||||
X15850Y9914
|
||||
T02
|
||||
X17200Y9464
|
||||
X18200Y9964
|
||||
X18200Y10964
|
||||
X17200Y10464
|
||||
X17200Y11464
|
||||
X18200Y11964
|
||||
T03
|
||||
X18350Y16814
|
||||
X17350Y16814
|
||||
X7350Y16964
|
||||
X6350Y16964
|
||||
X5350Y16964
|
||||
X1500Y12564
|
||||
X1500Y11564
|
||||
X1500Y10564
|
||||
X1500Y9564
|
||||
X1500Y8564
|
||||
T04
|
||||
X2350Y5114
|
||||
X2300Y16064
|
||||
X20800Y16064
|
||||
X20800Y5064
|
||||
T05
|
||||
X20700Y8714
|
||||
X20700Y12714
|
||||
M30
|
||||
2099
examples/gerbers/silkscreen.GTO
Normal file
2099
examples/gerbers/silkscreen.GTO
Normal file
File diff suppressed because it is too large
Load diff
162
examples/gerbers/soldermask.GTS
Normal file
162
examples/gerbers/soldermask.GTS
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
G75*
|
||||
%MOIN*%
|
||||
%OFA0B0*%
|
||||
%FSLAX24Y24*%
|
||||
%IPPOS*%
|
||||
%LPD*%
|
||||
%AMOC8*
|
||||
5,1,8,0,0,1.08239,22.5*
|
||||
%
|
||||
%ADD10R,0.0340X0.0880*%
|
||||
%ADD11R,0.0671X0.0237*%
|
||||
%ADD12R,0.4178X0.4332*%
|
||||
%ADD13R,0.0930X0.0500*%
|
||||
%ADD14R,0.0710X0.1655*%
|
||||
%ADD15R,0.0671X0.0592*%
|
||||
%ADD16R,0.0592X0.0671*%
|
||||
%ADD17R,0.0710X0.1615*%
|
||||
%ADD18R,0.1419X0.0828*%
|
||||
%ADD19C,0.0634*%
|
||||
%ADD20C,0.1360*%
|
||||
%ADD21R,0.0474X0.0580*%
|
||||
%ADD22C,0.0680*%
|
||||
%ADD23R,0.0552X0.0552*%
|
||||
%ADD24C,0.1340*%
|
||||
%ADD25C,0.0476*%
|
||||
D10*
|
||||
X005000Y010604D03*
|
||||
X005500Y010604D03*
|
||||
X006000Y010604D03*
|
||||
X006500Y010604D03*
|
||||
X006500Y013024D03*
|
||||
X006000Y013024D03*
|
||||
X005500Y013024D03*
|
||||
X005000Y013024D03*
|
||||
D11*
|
||||
X011423Y007128D03*
|
||||
X011423Y006872D03*
|
||||
X011423Y006616D03*
|
||||
X011423Y006360D03*
|
||||
X011423Y006104D03*
|
||||
X011423Y005848D03*
|
||||
X011423Y005592D03*
|
||||
X011423Y005336D03*
|
||||
X011423Y005080D03*
|
||||
X011423Y004825D03*
|
||||
X011423Y004569D03*
|
||||
X011423Y004313D03*
|
||||
X011423Y004057D03*
|
||||
X011423Y003801D03*
|
||||
X014277Y003801D03*
|
||||
X014277Y004057D03*
|
||||
X014277Y004313D03*
|
||||
X014277Y004569D03*
|
||||
X014277Y004825D03*
|
||||
X014277Y005080D03*
|
||||
X014277Y005336D03*
|
||||
X014277Y005592D03*
|
||||
X014277Y005848D03*
|
||||
X014277Y006104D03*
|
||||
X014277Y006360D03*
|
||||
X014277Y006616D03*
|
||||
X014277Y006872D03*
|
||||
X014277Y007128D03*
|
||||
D12*
|
||||
X009350Y010114D03*
|
||||
D13*
|
||||
X012630Y010114D03*
|
||||
X012630Y010784D03*
|
||||
X012630Y011454D03*
|
||||
X012630Y009444D03*
|
||||
X012630Y008774D03*
|
||||
D14*
|
||||
X010000Y013467D03*
|
||||
X010000Y016262D03*
|
||||
D15*
|
||||
X004150Y012988D03*
|
||||
X004150Y012240D03*
|
||||
X009900Y005688D03*
|
||||
X009900Y004940D03*
|
||||
X015000Y006240D03*
|
||||
X015000Y006988D03*
|
||||
D16*
|
||||
X014676Y008364D03*
|
||||
X015424Y008364D03*
|
||||
X017526Y004514D03*
|
||||
X018274Y004514D03*
|
||||
X010674Y004064D03*
|
||||
X009926Y004064D03*
|
||||
X004174Y009564D03*
|
||||
X003426Y009564D03*
|
||||
X005376Y014564D03*
|
||||
X006124Y014564D03*
|
||||
D17*
|
||||
X014250Y016088D03*
|
||||
X014250Y012741D03*
|
||||
D18*
|
||||
X014250Y010982D03*
|
||||
X014250Y009447D03*
|
||||
D19*
|
||||
X017200Y009464D03*
|
||||
X018200Y009964D03*
|
||||
X018200Y010964D03*
|
||||
X017200Y010464D03*
|
||||
X017200Y011464D03*
|
||||
X018200Y011964D03*
|
||||
D20*
|
||||
X020700Y012714D03*
|
||||
X020700Y008714D03*
|
||||
D21*
|
||||
X005004Y003814D03*
|
||||
X005004Y004864D03*
|
||||
X005004Y005864D03*
|
||||
X005004Y006914D03*
|
||||
X008696Y006914D03*
|
||||
X008696Y005864D03*
|
||||
X008696Y004864D03*
|
||||
X008696Y003814D03*
|
||||
D22*
|
||||
X001800Y008564D02*
|
||||
X001200Y008564D01*
|
||||
X001200Y009564D02*
|
||||
X001800Y009564D01*
|
||||
X001800Y010564D02*
|
||||
X001200Y010564D01*
|
||||
X001200Y011564D02*
|
||||
X001800Y011564D01*
|
||||
X001800Y012564D02*
|
||||
X001200Y012564D01*
|
||||
X005350Y016664D02*
|
||||
X005350Y017264D01*
|
||||
X006350Y017264D02*
|
||||
X006350Y016664D01*
|
||||
X007350Y016664D02*
|
||||
X007350Y017264D01*
|
||||
X017350Y017114D02*
|
||||
X017350Y016514D01*
|
||||
X018350Y016514D02*
|
||||
X018350Y017114D01*
|
||||
D23*
|
||||
X016613Y004514D03*
|
||||
X015787Y004514D03*
|
||||
D24*
|
||||
X020800Y005064D03*
|
||||
X020800Y016064D03*
|
||||
X002300Y016064D03*
|
||||
X002350Y005114D03*
|
||||
D25*
|
||||
X009250Y004064D03*
|
||||
X012100Y005314D03*
|
||||
X013500Y006864D03*
|
||||
X015650Y006264D03*
|
||||
X015200Y004514D03*
|
||||
X013550Y008764D03*
|
||||
X013350Y010114D03*
|
||||
X013300Y011464D03*
|
||||
X011650Y013164D03*
|
||||
X010000Y015114D03*
|
||||
X006500Y013714D03*
|
||||
X004150Y011564D03*
|
||||
X014250Y014964D03*
|
||||
X015850Y009914D03*
|
||||
M02*
|
||||
|
|
@ -265,6 +265,11 @@ class ExcellonParser(object):
|
|||
elif line[0] == 'R' and self.state != 'HEADER':
|
||||
stmt = RepeatHoleStmt.from_excellon(line, self._settings())
|
||||
self.statements.append(stmt)
|
||||
for i in xrange(stmt.count):
|
||||
self.pos[0] += stmt.xdelta
|
||||
self.pos[1] += stmt.ydelta
|
||||
self.hits.append((self.active_tool, tuple(self.pos)))
|
||||
self.active_tool._hit()
|
||||
|
||||
elif line[0] in ['X', 'Y']:
|
||||
stmt = CoordinateStmt.from_excellon(line, self._settings())
|
||||
|
|
|
|||
|
|
@ -296,16 +296,16 @@ class RepeatHoleStmt(ExcellonStatement):
|
|||
if stmt['ydelta'] is not '' else None)
|
||||
return cls(count, xdelta, ydelta)
|
||||
|
||||
def __init__(self, count, xdelta=None, ydelta=None):
|
||||
def __init__(self, count, xdelta=0.0, ydelta=0.0):
|
||||
self.count = count
|
||||
self.xdelta = xdelta
|
||||
self.ydelta = ydelta
|
||||
|
||||
def to_excellon(self, settings):
|
||||
stmt = 'R%d' % self.count
|
||||
if self.xdelta is not None:
|
||||
if self.xdelta != 0.0:
|
||||
stmt += 'X%s' % write_gerber_value(self.xdelta, settings.format, settings.zero_suppression)
|
||||
if self.ydelta is not None:
|
||||
if self.ydelta != 0.0:
|
||||
stmt += 'Y%s' % write_gerber_value(self.ydelta, settings.format, settings.zero_suppression)
|
||||
return stmt
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import math
|
|||
|
||||
from ..primitives import *
|
||||
|
||||
SCALE = 400.
|
||||
SCALE = 4000.
|
||||
|
||||
|
||||
class GerberCairoContext(GerberContext):
|
||||
|
|
@ -42,10 +42,12 @@ class GerberCairoContext(GerberContext):
|
|||
self.background = False
|
||||
|
||||
def set_bounds(self, bounds):
|
||||
xbounds, ybounds = bounds
|
||||
self.ctx.rectangle(SCALE * xbounds[0], SCALE * ybounds[0], SCALE * (xbounds[1]- xbounds[0]), SCALE * (ybounds[1] - ybounds[0]))
|
||||
self.ctx.set_source_rgb(0,0,0)
|
||||
self.ctx.fill()
|
||||
if not self.background:
|
||||
xbounds, ybounds = bounds
|
||||
self.ctx.rectangle(SCALE * xbounds[0], SCALE * ybounds[0], SCALE * (xbounds[1]- xbounds[0]), SCALE * (ybounds[1] - ybounds[0]))
|
||||
self.ctx.set_source_rgb(0,0,0)
|
||||
self.ctx.fill()
|
||||
self.background = True
|
||||
|
||||
def _render_line(self, line, color):
|
||||
start = map(mul, line.start, self.scale)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
# Author: Hamilton Kibbe <ham@hamiltonkib.be>
|
||||
from ..cam import FileSettings
|
||||
from ..excellon import read, detect_excellon_format, ExcellonFile, ExcellonParser
|
||||
from ..excellon_statements import ExcellonTool
|
||||
from tests import *
|
||||
|
||||
import os
|
||||
|
|
@ -120,6 +121,7 @@ def test_parse_absolute_mode():
|
|||
|
||||
def test_parse_repeat_hole():
|
||||
p = ExcellonParser(FileSettings())
|
||||
p.active_tool = ExcellonTool(FileSettings(), number=8)
|
||||
p._parse('R03X1.5Y1.5')
|
||||
assert_equal(p.statements[0].count, 3)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue