Root/cameo/gerber.c

1/*
2 * gerber.c - Gerber file input
3 *
4 * Written 2010, 2013, 2015, 2017 by Werner Almesberger
5 * Copyright 2010, 2013, 2015, 2017 Werner Almesberger
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 */
12
13/*
14 * Note: this is limited to the Gerber produced by KiCad for the PCB Edge
15 * layer. Furthermore, we ignore the tool diameter for now.
16 *
17 * The relevant details are nicely explained at
18 * http://www.pcbmilling.com/Examples of Gerber and Excellon Data Files.htm
19 */
20
21#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <math.h>
25
26#include "path.h"
27#include "gerber.h"
28
29
30static double scale; /* KiCad Gerber units */
31
32#define KU2MM(in) ((in)/scale)
33
34
35/*
36 * @@@ Very crude implementation of G03. Tested with only one example in
37 * KiCad.
38 *
39 * Command definition from:
40 * http://www.rulabinsky.com/cavd/text/chapa.html
41 */
42
43static void arc(struct path *path, const char *buf, double ax, double ay)
44{
45    int xi, yi, cxi, cyi;
46    double bx, by, cx, cy;
47    double r, a, b, t;
48    double x, y;
49
50    if (sscanf(buf, "G03X%dY%dI%dJ%dD01*\n", &xi, &yi, &cxi, &cyi) != 4)
51        return;
52    bx = KU2MM(xi);
53    by = KU2MM(yi);
54    cx = KU2MM(cxi);
55    cy = KU2MM(cyi);
56    r = hypot(cx, cy);
57    cx += ax;
58    cy += ay;
59    a = atan2(ay-cy, ax-cx);
60    b = atan2(by-cy, bx-cx);
61    if (a > b)
62        b += 2*M_PI;
63//fprintf(stderr, "@(%g,%g) (%g,%g)-(%g-%g) %g %g\n",
64// cx, cy, ax, ay, bx, by, a/M_PI*180, b/M_PI*180);
65    for (t = a; t <= b; t += M_PI/180) { /* @@@ 1 deg increment */
66        x = cx+r*cos(t);
67        y = cy+r*sin(t);
68        path_add(path, x, y, 0);
69    }
70    path_add(path, bx, by, 0);
71}
72
73
74struct path *gerber_read(const char *name, double r_tool_default)
75{
76    FILE *file;
77    int lineno = 0;
78    char buf[1024];
79    struct path *paths = NULL, **anchor = &paths, *path = NULL;
80    double start_x = 0, start_y = 0;
81    int xi, yi, d;
82    double x, y;
83
84    file = name ? fopen(name, "r") : stdin;
85    if (!file) {
86        perror(name);
87        exit(1);
88    }
89
90    while (fgets(buf, sizeof(buf), file)) {
91        lineno++;
92        if (!strncmp(buf, "%FS", 3)) {
93            if (!strcmp(buf, "%FSLAX34Y34*%\n")) {
94                scale = 10 * 1000;
95            } else if (!strcmp(buf, "%FSLAX46Y46*%\n")) {
96                scale = 1000 * 1000;
97            } else {
98                fprintf(stderr,
99                    "unrecognized format %s\n", buf);
100                exit(1);
101            }
102            continue;
103        }
104        /* @@@ we assume that %MO follows %FS */
105        if (!strncmp(buf, "%MO", 3)) {
106            if (!strcmp(buf, "%MOIN*%\n")) {
107                scale /= 25.4;
108            } else if (strcmp(buf, "%MOMM*%\n")) {
109                fprintf(stderr,
110                    "unrecognized mode %s\n", buf);
111                exit(1);
112            }
113            continue;
114        }
115        if (!strncmp(buf, "G03", 3)) {
116            if (path)
117                abort();
118            path = path_new(r_tool_default, name);
119            *anchor = path;
120            anchor = &path->next;
121            arc(path, buf, start_x, start_y);
122            continue;
123        }
124        if (sscanf(buf, "X%dY%dD%d*\n", &xi, &yi, &d) != 3)
125            continue;
126        x = KU2MM(xi);
127        y = KU2MM(yi);
128        switch (d) {
129        case 1:
130            if (!path) {
131                path = path_new(r_tool_default, name);
132                *anchor = path;
133                anchor = &path->next;
134                path_add(path, start_x, start_y, 0);
135            }
136            path_add(path, x, y, 0);
137            break;
138        case 2:
139            path = NULL;
140            start_x = x;
141            start_y = y;
142            break;
143        default:
144            fprintf(stderr, "don't recognize D%d\n", d);
145            exit(1);
146        }
147    }
148    fclose(file);
149    return path_connect(paths);
150}
151
152
153static int gerber_do_write(FILE *file, const struct path *paths)
154{
155    const struct path *path;
156    const struct point *p;
157
158    fprintf(file,
159"G04 Generated by cameo*\n"
160"%%MOMM*%%\n" // dimensions are in mm
161"%%FSLAX33Y33*%%\n" // no leading zeroes; absolute; 3 digits int,
162                // 3 digits fractional
163"G01*\n" // linear interpolation
164"%%ADD10C,0.01*%%\n" // aperture D10, 10 um circle
165"D10*\n"); // select D10
166
167    for (path = paths; path; path = path->next)
168        for (p = path->first; p; p = p->next)
169            fprintf(file, "X%.0fY%.0fD0%u*\n",
170                p->x * 1000.0, p->y * 1000.0,
171                p == path->first ? 2 : 1);
172
173    fprintf(file, "M02**\n");// end of file
174
175    if (file == stdout) {
176        if (fflush(file) == EOF)
177            return 0;
178    } else {
179        if (fclose(file) < 0)
180            return 0;
181    }
182    return 1;
183}
184
185
186void gerber_write(const char *name, const struct path *paths)
187{
188    FILE *file;
189
190    file = name ? fopen(name, "w") : stdout;
191    if (!file) {
192        perror(name);
193        exit(1);
194    }
195    if (!gerber_do_write(file, paths)) {
196        perror(name ? name : "(stdout)");
197        exit(1);
198    }
199}
200

Archive Download this file

Branches:
master



interactive