aboutsummaryrefslogtreecommitdiff
path: root/post.html
blob: dbfbcf3853d795727f240eb3b2cd7b95cc4cafd6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
<!doctype html> <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Create Beautiful Circuit Boards With Gerbolyze</title>
<style type="text/css">
@font-face {
    font-family: "playfair display webfont";
    font-weight: 600;
    src: url("fonts/playfair-display-v22-latin-ext_latin-600.woff2") format("woff2");
}

@font-face {
    font-family: "playfair display webfont";
    font-weight: 400;
    src: url("fonts/playfair-display-v22-latin-ext_latin-regular.woff2") format("woff2");
}

@font-face {
    font-family: "playfair display webfont";
    font-weight: 700;
    src: url("fonts/playfair-display-v22-latin-ext_latin-700.woff2") format("woff2");
}

:root {
    --textw: calc(min(600px, 100vw));
    --mar: calc(50vw - 0.5*var(--textw));
}

html, body {
    margin: 0;
    padding: 0;
    hyphens: auto;
    overflow-wrap: break-word;
    font-size: 14pt;
    font-family: "Source Sans Pro";
}

.content {
    padding-left: 10px;
    padding-right: 10px;
    width: 100%;
    box-sizing: border-box;
}

/*
* { border: 1px solid red; }
*/

figure {
    overflow: hidden;
    padding-top: 20px;
    padding-right: 0;
    padding-bottom: 20px;
    padding-left: var(--mar);
    margin: 0;
    box-sizing: border-box;
    width: 100vw;
    max-width: 100%;
}

img {
    display: inline-block;
    width: var(--textw);
    margin-right: 2em;
}

figcaption {
    display: inline-block;
    margin: 0;
    width: 20em;
    vertical-align: top;
    text-align: justify;
}

figcaption > strong {
    display: block;
    font-family: "playfair display webfont";
    font-weight: 700;
    color: #c00;
    font-size: 16pt;
    margin-bottom: .5em;
}

.content > p {
    margin-left: var(--mar);
    width: var(--textw);
    box-sizing: border-box;
    text-align: justify;
    line-height: 1.5;
    max-width: 100%;
}

h1, h2, h3, h4, h5, h6 {
    font-family: "playfair display webfont";
    font-weight: 600;
    color: #c00;
    text-align: right;
    margin: 0;
    padding-left: 1em;
    padding-top: 0;
    box-sizing: border-box;
    width: calc(var(--mar) + var(--textw));
    max-width: 100%;
}

h1 {
    font-size: calc(24pt + 2vh + 2vw);
    padding-bottom: 0.7em;
}

body::before {
    content: "";
    display: block;
    margin-top: 100px;
    border-top: 0.7mm dashed #c00;
    width: 100vw;
    max-width: 100%;
}

h2 {
    font-size: calc(18pt + .2vh + .2vw);
    margin-top: 1em;
    margin-bottom: .5em;
}

</style>
    </head>
    <body lang="en">
        <div class="content">
            <h1>Create Beautiful Circuit Boards With Gerbolyze</h1>
            <p>
            Today, there is an increasingly large crowd of people who do artistic circuit board designs. People who fuse
            the roles of engineer and artist. Unitl today, circuit board design tools mostly ignore this use case and
            present a multitude of obstacles for such use. Gerbolyze finally solves this problem and presents an
            integrated solution for artistic PCB design that is compatible with real designer's workflows on one side
            and with real electronic design automation software on the other side.
            </p>
            <figure>
                <a href="pics/pcbway_sample_02_small.jpg"><img src="pics/pcbway_sample_02_small.jpg" alt="A printed
                         circuit board showing a surrealist manga-style drawing of a woman sitting atop several traffic
                         lights. The woman's hair looks golden from the circuit board's gold copper finish. The
                         background is blue and white with scales of gray emulated through a halftone technique like it
                         is used in newspapers."/></a>
                <figcaption>
                    <strong>An artistic PCB design</strong>
                    <p>
                    This design was created from a digital artwork in a raster image file after circuit board
                    manufacturer PCBWay offered me some free boards. The artwork was pre-processed using a raster
                    graphics tool: It was split into layers for the different colors. Then, its color components were
                    adjusted for brightness and contrast and finally passed through a raster-based halftone filter. The
                    resulting file was then converted into circuit board manufacturing files using Gerbolyze.
                    </p>
                </figcaption>
            </figure>
            <p>
            Thirty years ago, the world of printed circuit board design was revolutionized by the introduction of
            computer aided design tools. These tools enabled extremely complex designs through automation features
            like autorouting and through automatic design rule checking to weed out human error. While the first
            such tools were still very limited, their capabilites quickly grew and a few years after their
            introduction modern electronics design without computers was already unthinkable.
            </p>
            <p>
            Today, circuit board design programs can look back on a rich history and have accumulated a healty
            amount of expert knowledge in their design. Despite their difficult economic niche, even <em>free
                software</em> design tools have grown to become usable for advanced designs. However, all modern
            circuit board design tools are severely lacking in one area: That of <em>artistic</em> design.  Many
            design assumptions are hard-wired deep into their design: Traces should be at 45° angles.  Silkscreen is
            one opaque color. etc. These design assumptions lead to these tools being <em>in the way</em> more often
            than not for the increasing crowd of designers who try to create art with them.
            </p>
            <p>
            Gerbolyze solves this problem. Gerbolyze interfaces with circuit board design tools such as Altium or Kicad
            on one side through standard Gerber files. It interfaces with vector graphics editors such as inkscape on
            the other side through Scaleable Vector Graphics (SVG) files. By fusing both, it yields a powerful
            environment for artistic circuit board design.
            </p>
            <h2>Gerbolyze Algorithm Overview</h2>
            <p>
            Gerbolyze has two major components. The first is the gerbolyze executable itself, which orchestrates the
            process of fusing SVG and Gerber files. The second is svg-flatten, a tool encapsulating all of the
            heavy-duty computer graphics code. The gerbolyze executable is a python script for readability, while the
            geometry backend is a C++ binary for performance.
            </p>
            <p>
            In the beginning of the fusing process, the orchestrator figures out what semantic layers such as silkscreen
            or copper the tool's input files correspond to. The assigned layers are then processed one by one. For each
            layer, the tool first checks the input SVG file for any content. If there is none on this layer, the layer
            file is directly copied to the output. If ther is some, this SVG content is passed through the geometry
            backend to convert it to Gerber code. The resulting Gerber code is then read and added on top of the input
            file's gerber code. The result is written to the output.
            </p>
            <h2>The Computer Geometry of Scaleable Vector Graphics</h2>
            <figure>
                <a href="pics/test_svg_readme_composited.png"><img src="pics/test_svg_readme_composited.png"/></a>
                <figcaption>
                    <strong>A complex SVG file...</strong>
                    ...illustrates the range of features that Gerbolyze supports. The left side of this picture shows
                    the input to gerbolze, the right side the resulting output. As you can see, clips, bitmap images,
                    pattern fills and strokes all behave in a "visually intuitive" way.
                </figcaption>
            </figure>
            <p>
            The heavy lifting during this process is done by the geometry backend. While its job seems simple at first,
            it is surprisingly stretching the state of the art in both academic research and technical implementations
            of computer graphics. In its core the problem is that while SVG and Gerber are both essentially vector
            graphics formats, both have very different conceptions of their drawing models: They differ significantly in
            what happens when one of the input file's vectors is drawn.
            </p>
            <p>
            SVG is little more than a highly standardized description of the basic operations provided by the modern 2D
            graphics interfaces such as Qt, Cairo or Skia that are built-in to all operating systems. Drawing
            <em>paths</em> that are described by the vector coördinates of points along them is the most basic of these
            operations. SVG also includes support for a surprising number of decidedly <em>raster</em> operations such
            as masking but, operating on grayscales, these are less relevant for the type of design one would create
            when targeting circuit board production processes.
            </p>
            <p>
            Similar to SVG, the Gerber file format also targets a type of graphics programming interface. Only instead
            of that of operating systems 2D graphics APIs of the 90ies and 2000s, the Gerber format was created as a way
            to encapsulate commands for photoplotters, computer-controlled machines that physically move a light source
            across a photo-sensitive material. Gerber's concept of "aptertures" goes back to mechanical photoplotters
            having magazines of stencils of different shapes and sizes that could be swapped into the path of light
            during the plotting process.
            </p>
            <figure>
                <a href="pics/ex-intersections.png"><img src="pics/ex-intersections.png"/></a>
                <figcaption>
                    <strong>An SVG path with one self-intersection and one hole</strong>
                    On the left you see our example path illustrated with the locations of its <em>nodes</em>, that is
                    the points where one segment starts and another ends. Also illustrated are the <em>handles</em> that
                    define its curvature. Note that not every node has handles. This is because some of the path's
                    segments are straight lines instead of bezier curves.
                </figcaption>
            </figure>
            <p>
            Like SVG has its paths, the Gerber format has polygons. Polygons were added to the format to ease the
            description of irregularly-shaped areas: Previously, these would have to be drawn by overlaying thousands of
            thin lines, described one by one in the Gerber file. Using a Polygon, one only needs to describe the shape's
            outline as a series of points and the photoplotter will fill in the rest.
            </p>
            <h2>Transforming Vectors into Vectors</h2>
            <p>
            The crux in converting from SVG to Gerber lies here, in the conversion of paths. While in both a path or
            polygon is described by its outline, which is described by points, there are significant differences in the
            limitations both place on these outlines. In SVG an outline can consist of several types of segments:
            besides basic straight lines, multiple types of parametrized curves including cubic bezier curves are
            possible. An SVG path's outline can self-intersect (cross over itself). The path can also have holes,
            additional parts that are inside the outline.
            </p>
            <figure>
                <a href="pics/ex-flattening.png"><img src="pics/ex-flattening.png"/></a>
                <figcaption>
                    <strong>Bezier flattening...</strong>
                    ...transforms a elegant bezier curve into a dumb list of points. The resulting image can still be
                    called a <em>vector</em> image since after all points are vectors, too, but they can only allude to
                    their previous mathematical glory. At least straight lines are easy to deal with, though!
                </figcaption>
            </figure>
            <p>
            Gerber, on the other hand, has a much more limited view of what a polygon is. In gerber, a polygon is
            something bounded by straight line segments, that cannot touch except under very particular circumstances,
            and holes are simply not supported. Converting from SVG's flexible model of a path to Gerber's very
            limited model of a polygon while preserving the fidelity of the input data is the true challenge here. As an
            aside, a fun complication one will encounter when embarking on this endeavour is that most programs that
            display Gerber files use modern graphics libraries in the backend. In these programs, a valid SVG path
            ineptly converted into an illegal gerber polygon may still end up looking alright since these programs
            usually just pass through the gerber's input data to the underlying graphics layer without validation—and
            that graphics layer is the one from SVG.
            </p>
            <h2>Styles and Strokes</h2>
            <p>
            Creating gerber-compatible polygons from SVG paths is not the only place where some heavy computer geometry
            is necessary. SVG also allows a path to be drawn with its outline stroked with a set width. Though stroking
            a path with a given width is very intuitive, it again happens to be surprisingly complex to do in
            computer-geometrically.
            </p>
            <p>
            At first one might think SVG stroke widths naturally map to gerber apertures, and all that is left is
            flattening the path's bezier curves into straight line segments for it to be drawn. This approach would be
            a passable approximation in many cases, but there is a large part of SVG's expressivity that will be lost
            under this mapping. SVG allows designers to define join styles and end cap styles on a path. The join style
            describes how two path segments that are at an angle will be joined. End caps describe how open ends of the
            path will be rendered. Gerber does not have native support for either.
            </p>
            <figure>
                <a href="pics/ex-strokes.png"><img src="pics/ex-strokes.png"/></a>
                <figcaption>
                    <strong>Strokes can be quite complex</strong>
                    <p>
                    In this picture, on the left you see a circle that is stroked with a pattern. To draw this to screen
                    or gerber, you have to first convert the ring's path to its outline. Then, you have to render the
                    pattern tiles that overlap that outline, while clipping them against the outline.  The right-hand
                    picture illustrates different end and join styles.
                </figcaption>
            </figure>
            <p>
            Regular 2D renderers perform stroking as a part of their rasterization routine. This means that a regular
            renderer will likely never actually calculate the vector representation of the outline of the stroke at all,
            instead bypassing that step and directly converting the path's vector representation into its pixel
            representation given some stroke width. In our implementation we instead convert the outline of the path's
            stroke into its vector polygon representation, which we then output as gerber code.
            </p>
            <p>
            This transformation from path plus stroke width to vector outline can be done in several ways. The one we
            chose was to leverage the excellent Clipper library that we are already using for clipping shapes. Clipper's
            offsetting function is essentially a turn-key solution for this use case. A nice side-effect of this
            approach is that we can directly use the resulting stroke polygons as clips when a user specifies a path
            with a patterned stroke!
            </p>
            <h2>Gerbolyze Image Vectorization</h2>
            <p>
            To make Gerbolyze as user-friendly as possible I decided to include support for raster images as well. The
            previous version of Gerbolyze in fact exclusively handled raster images, so keeping this support seemed
            natural to me. 
            </p>
            <p>
            There are several ways to convert raster images into a vector representation. Roughly, they fall into two
            categories: Tracing and halftone processing. Tracing tries to read contours of colored areas of a raster
            image, and approximates these contours with vector shapes. Tracing is most useful for raster images that
            contain text or graphics. On good-quality input, tracing can produce surprisingly accurate results. In
            contrast to tracing, halftone processing tries to emulate the picture's tones (be they grayscale or color)
            with thousands or even millions of tiny colored filled shapes. Halftone processing to this day is used in
            all kinds of printing processes.
            </p>
            <p>
            For bringing grayscale imagery into circuit board production, halftone processing is a very good fit. The
            silkscreen processes that are commonly used for circuit boards have very high resolution and can reproduce
            any input shape with micrometer precision, but they are limited in the smallest amount of ink they can put
            on a board or the smallest gap between two blobs of ink that they can reliably produce. These limitations
            are not due to the printers' or photoplotters' resolution or precision but simply due to the mechanics of
            small droplets of liquid being squeegied onto or shot at a circuit board.
            </p>
            <!-- FIXME some microscope images of silkscreen's 3d structure would be great here! -->
            <p>
            The following pictures illustrate the different vectorization processes gerbolyze supports. In each row you
            see the output of each vectorization process zoomed out on the left, and a zoomed-in detail view on the
            right. For grayscale images, the poisson-disc-sampled halftone vectorizer works best. For tracing graphics,
            the <a href="https://opencv.org/">OpenCV</a> contour tracer does a good job. This contour tracer is the
            exact same one that was used in the previous version of Gerbolyze.
            <figure>
                <a href="pics/vec_square_composited.png"><img src="pics/vec_poisson_composited.png"/></a>
                <figcaption>
                    <strong>Poisson disc sampling</strong>
                    Poisson disc sampling randomly distributes points on the plane. We then calculate these point's
                    voronoi tesselation, whose cells we then fill proportional to the image's brightness at that spot.
                    The resulting image looks very natural as it is devoid of distracting regular aliasing patterns.
                </figcaption>
            </figure>
            <figure>
                <a href="pics/vec_square_composited.png"><img src="pics/vec_hexgrid_composited.png"/></a>
                <figcaption>
                    <strong>Hexagon grid sampling</strong>
                    The hexgrid sampler actually uses the same voronoi-based halftone code of the poisson-disc
                    sampling-based code, just with points generated on a hexgrid instead of randomly. The result is an
                    image that has a decidedly "space" look to it. At coarser resolutions, this sampling method has the
                    chance to shine with its attractive geometry.
                </figcaption>
            </figure>
            <figure>
                <a href="pics/vec_square_composited.png"><img src="pics/vec_square_composited.png"/></a>
                <figcaption>
                    <strong>Square grid sampling</strong>
                    Though I think the square grid method looks the worst of the three halftone methods compared here,
                    it would have been ridiculous not to implement it given how little work it was using the
                    voronoi-cell halftone code.
                </figcaption>
            </figure>
            <figure>
                <a href="pics/vec-comparison-contour.png"><img src="pics/vec-comparison-contour.png"/></a>
                <figcaption>
                    <strong>Binary contour tracing</strong>
                    This method calls into the same piece of the <a href="https://opencv.org/">OpenCV</a> image
                    processing library that the old gerbolyze used. As demonstrated here, this method lends itself well
                    to graphic inputs. It does also enable you to experiment with basically any rasterized halftone
                    processor such as the "Newsprint" filter built into GIMP.
                </figcaption>
            </figure>
            <h2>Manufacturing Considerations</h2>
            <!-- minimum trace/space guarantees in the vectorizer -->
            <p>
            When creating artistic designs for PCB manufacturing, you have to keep in mind the limitations of the PCB
            manufacturing process at all times. PCB manufacturing processes only know filled and unfilled areas, and
            fundamentally cannot do grayscale without hacks like halftone processing. More importantly, these
            manufacturing processes have significant limitations in the smallest detail size that they can resolve.
            For inexpensive processes, these trace/space design rules are commonly in the range of 50-150µm. While this
            sounds great at first, it is <em>vastly</em> larger than what even a cheap home printer can accomplish. For
            comparison, a regular inkjet printer for home use can print photos at 1200 dpi without breaking a sweat.
            1200 dpi means that this printer can put dots of ink on paper that are only 20 µm in size! And it can do
            these dots in millions of colors, too.
            </p>
            <p>
            When tailoring a design for PCB manufacturing there's two things one can do. Number one is to be creative
            with graphical parts of the design and avoid extremely narrow lines, wedges or other thin features that will
            not come out during circuit board manufacturing. Number two is to keep detail in raster images several times
            larger than the manufacturing processes native capability. For example, to target a trace/space design rule
            of 100 µm, the smallest detail in embedded raster graphics should not be much below 1mm.
            </p>
            <p>
            Gerbolyze's halftone vectorizers have built-in support for trace/space design rules. While they can still
            produce small artifacts that violate these rules, their output should be close enough to satifsy board
            houses and close enough for the result to look good. The way gerbolyze does this is to clip the halftone
            cell's values to zero whenevery they get too small, and to forcefully split or merge two neighboring cells
            when they get too close. While this process introduces slight steps at the top and bottom of grayscale
            response, for most inputs these are not noticeable.
            </p>
            <p>
            On the other hand, for SVG vector elements as well as for traced raster images, Gerbolyze cannot help with
            these design rules. There is no heuristic that would allow Gerbolyze to non-destructively "fix" a design
            here, so all that's on the roadmap here is to eventually include a gerber-level design rule checker.
            </p>
            <p>
            As far as board houses go, I have made good experiences with the popular Chinese board houses. In my
            experience, JLC will just produce whatever you send them with little fucks being given about design rule
            adherence or validity of the input gerbers. This is great if you just want artistic circuit boards without
            much of a hassle, and you don't care if they come out exactly as you imagined. The worst I've had happen was
            when an older version of gerbolyze generated polygons with holes assuming standard fill-rule processing. The
            in the board house's online gerber viewer things looked fine, and neither did they complain during file
            review. However, the resulting boards looked completely wrong because all the dark halftones were missing.
            </p>
            <p>
            PCBWay on the other hand has a much more rigurous file review process. They <em>will</em> complain when you
            throw illegal garbage gerbers at them, and they will helpfully guide you through your design rule
            violations. In this way you get much more of a professional service from them and for designs that have to
            be functional their higher level of scrutiny definitely is a good thing. For the design you saw in the
            first picture in this article, I ended up begging them to just plot my files if it doesn't physically break
            their machines and to their credit, while they seemed unhappy about it they did it and the result looks
            absolutely stunning.
            </p>
            <p>
            PCBWay is a bit more expensive on their lowest-end offering than JLC, but I found that for anything else
            (large boards, multi-layer, gold plating etc.) their prices match. PCBWay offers a much broader range of
            manufacturing options such as flexible circuit boards, multi-layer boards, thick or thin substrates and
            high-temperature substrates so they closer to an industry supplier like Eurocircuits than they are to a
            hobbyist prototyping service like dirtypcbs.
            </p>
            <figure>
                <a href="pics/fr4_comparison2.jpg"><img src="pics/fr4_comparison2.jpg"/></a>
                <figcaption>
                    <strong>FR-4 substrate color differs significantly...</strong>
                    ...between these two boards. These boards come from two batches PCBWay produced of the exact same
                    design. As you can see, it would not have been wise to rely too much on the substrate's color in
                    this design. Obviously, this is not a defect as the precise color of the FR-4 substrate used is
                    perfectly irrelevant for the market these manufacturers actually target.
                </figcaption>
            </figure>
            <p>
            When in doubt about how your design is going to come out on the board, do not hesitate to contact your board
            house. Most of the customer-facing online PCB services have a number of different factories that do a number
            of different fabrication processes for them depending on order parameters. Places like PCBWay have
            exceptional quality control, but that is mostly focused on the technical aspects of the PCB. If you rely on
            visual aspects like silkscreen uniformity or solder mask color, you may find significant variations between
            manufacturers or even between orders with the same manufacturer.
            </p>
            <h2>Conclusion</h2>
            <p>
            I hope Gerbolyze will make you life a bit easier when it comes to artistic PCB design. I hope I have managed
            to illustrate a bit the design choices I made in Gerbolyze in this article. If you have any comments or
            suggestions, please feel free to write me <a href="mailto:gerbolyze.nospam@jaseg.de">an email</a> or open an
            issue <a href="https://github.com/jaseg/gerbolyze">on Github</a>.
            </p>
        </div>
    </body>
</html>