Date: | 2017-01-22 14:39:07 (7 years 2 months ago) |
---|---|
Author: | --- erichvk |
Commit: | 7081258910b767841129be93bff3c971d8db6cf1 |
Message: | diff for gEDA PCB export in fped I have 1) sorted out the tabbing 2) simplified > 1 element export by exporting elements in a layout (.pcb) 3) documented incompatibilities in the README 4) done it as a diff against origin master let me know if you need anything else done Cheers. Erich From dae69d9a63071a15c213c72e70b86fe963a67dd4 Mon Sep 17 00:00:00 2001 From: erich_heinzle <a1039181@gmail.com> Date: Sun, 22 Jan 2017 23:48:57 +1030 Subject: [PATCH] support for export to gEDA format of single and multiple footprints in a .pcb layout |
Files: |
Makefile (2 diffs) README (1 diff) coord.c (1 diff) coord.h (3 diffs) file.c (3 diffs) file.h (2 diffs) geda.c (1 diff) geda.h (1 diff) gui.c (2 diffs) |
Change Details
Makefile | ||
---|---|---|
3 | 3 | # |
4 | 4 | # Written 2009-2012, 2015 by Werner Almesberger |
5 | 5 | # Copyright 2009-2012, 2015 by Werner Almesberger |
6 | # Copyright 2016, Erich Heinzle (gEDA additions) | |
6 | 7 | # |
7 | 8 | # This program is free software; you can redistribute it and/or modify |
8 | 9 | # it under the terms of the GNU General Public License as published by |
... | ... | |
15 | 16 | UPLOAD = www-data@downloads.qi-hardware.com:werner/fped/ |
16 | 17 | |
17 | 18 | OBJS = fped.o expr.o coord.o obj.o delete.o inst.o util.o error.o \ |
18 | unparse.o file.o dump.o kicad.o postscript.o gnuplot.o meas.o \ | |
19 | unparse.o file.o dump.o kicad.o geda.o postscript.o gnuplot.o meas.o \ | |
19 | 20 | layer.o overlap.o hole.o tsort.o bitset.o \ |
20 | 21 | cpp.o lex.yy.o y.tab.o \ |
21 | 22 | gui.o gui_util.o gui_style.o gui_inst.o gui_status.o gui_canvas.o \ |
README | ||
---|---|---|
81 | 81 | process and verificative measurements helps efficient and accurate |
82 | 82 | review. |
83 | 83 | |
84 | Leveraging the work already done, and growing the intellectual commons | |
85 | of available footprints has motivated the addition of an export to gEDA | |
86 | pcb format option. Single or multiple footprints are exported in a | |
87 | gEDA PCB layout (.pcb) file. A select all command can be used, followed | |
88 | by a "disperse elements" command, to allow viewing of multiple elements | |
89 | in the gEDA layout editor. An element can then be selected, cut to | |
90 | buffer, and exported to a footprint (.fp) file with the usual menu | |
91 | commands. | |
92 | ||
93 | gEDA PCB format footprints are exported in centimil units. Pads with | |
94 | offset centre holes are not faithfully reproduced; the pad is exported | |
95 | with minimum dimensions and centred on the hole. Trapezoidal and | |
96 | roundrect pads are not supported in gEDA. | |
84 | 97 | |
85 | 98 | Footprint definition file format |
86 | 99 | -------------------------------- |
coord.c | ||
---|---|---|
3 | 3 | * |
4 | 4 | * Written 2009, 2010, 2016 by Werner Almesberger |
5 | 5 | * Copyright 2009, 2010, 2016 by Werner Almesberger |
6 | * Copyright 2016, Erich Heinzle (gEDA additions) | |
6 | 7 | * |
7 | 8 | * This program is free software; you can redistribute it and/or modify |
8 | 9 | * it under the terms of the GNU General Public License as published by |
coord.h | ||
---|---|---|
3 | 3 | * |
4 | 4 | * Written 2009, 2010, 2016 by Werner Almesberger |
5 | 5 | * Copyright 2009, 2010, 2016 by Werner Almesberger |
6 | * Copyright 2016, Erich Heinzle (gEDA additions) | |
6 | 7 | * |
7 | 8 | * This program is free software; you can redistribute it and/or modify |
8 | 9 | * it under the terms of the GNU General Public License as published by |
... | ... | |
22 | 23 | #define MM_UNITS (1000.0*MICRON_UNITS) |
23 | 24 | #define UM_UNITS MICRON_UNITS |
24 | 25 | #define KICAD_UNIT (MIL_UNITS/10.0) |
26 | #define GEDA_UNIT (MIL_UNITS/100.0) | |
25 | 27 | |
26 | 28 | #define MIL_IN_MM 0.0254 |
27 | 29 | #define UM_IN_MM 0.001 |
... | ... | |
79 | 81 | return (double) u/KICAD_UNIT; |
80 | 82 | } |
81 | 83 | |
84 | static inline int units_to_geda(unit_type u) | |
85 | { | |
86 | return (double) u/GEDA_UNIT; | |
87 | } | |
82 | 88 | |
83 | 89 | static inline int coord_eq(struct coord a, struct coord b) |
84 | 90 | { |
file.c | ||
---|---|---|
3 | 3 | * |
4 | 4 | * Written 2009-2012 by Werner Almesberger |
5 | 5 | * Copyright 2009-2012 by Werner Almesberger |
6 | * Copyright 2016, Erich Heinzle (gEDA additions) | |
6 | 7 | * |
7 | 8 | * This program is free software; you can redistribute it and/or modify |
8 | 9 | * it under the terms of the GNU General Public License as published by |
... | ... | |
19 | 20 | |
20 | 21 | #include "dump.h" |
21 | 22 | #include "kicad.h" |
23 | #include "geda.h" | |
22 | 24 | #include "postscript.h" |
23 | 25 | #include "gnuplot.h" |
24 | 26 | #include "util.h" |
... | ... | |
171 | 173 | } |
172 | 174 | } |
173 | 175 | |
176 | void write_geda(void) | |
177 | { | |
178 | char *name; | |
179 | ||
180 | if (save_file_name) { | |
181 | name = set_extension(save_file_name, "pcb"); | |
182 | save_to(name, geda, NULL); | |
183 | free(name); | |
184 | } else { | |
185 | if (!geda(stdout, NULL)) | |
186 | perror("stdout"); | |
187 | } | |
188 | } | |
189 | ||
174 | 190 | |
175 | 191 | static void do_write_ps(int (*fn)(FILE *file, const char *one), |
176 | 192 | const char *one) |
file.h | ||
---|---|---|
3 | 3 | * |
4 | 4 | * Written 2009-2011 by Werner Almesberger |
5 | 5 | * Copyright 2009-2011 by Werner Almesberger |
6 | * Copyright 2016, Erich Heinzle (gEDA additions) | |
6 | 7 | * |
7 | 8 | * This program is free software; you can redistribute it and/or modify |
8 | 9 | * it under the terms of the GNU General Public License as published by |
... | ... | |
30 | 31 | |
31 | 32 | void save_fpd(void); |
32 | 33 | void write_kicad(void); |
34 | void write_geda(void); | |
33 | 35 | void write_ps(const char *one); |
34 | 36 | void write_ps_fullpage(const char *one); |
35 | 37 | void write_gnuplot(const char *one); |
geda.c | ||
---|---|---|
1 | /* | |
2 | * geda.c - Dump objects in the gEDA PCB board/module format | |
3 | * | |
4 | * Written 2009, 2011 by Werner Almesberger, and 2016 by Erich Heinzle | |
5 | * Copyright 2009, 2011 by Werner Almesberger | |
6 | * Copyright 2016, Erich Heinzle | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | */ | |
13 | ||
14 | ||
15 | #include <stdlib.h> | |
16 | #include <stdio.h> | |
17 | #include <assert.h> | |
18 | ||
19 | #include "coord.h" | |
20 | #include "inst.h" | |
21 | #include "geda.h" | |
22 | ||
23 | ||
24 | static void geda_centric(struct coord a, struct coord b, | |
25 | struct coord *center, struct coord *size) | |
26 | { | |
27 | struct coord min, max; | |
28 | ||
29 | min.x = units_to_geda(a.x); | |
30 | min.y = units_to_geda(a.y); | |
31 | max.x = units_to_geda(b.x); | |
32 | max.y = units_to_geda(b.y); | |
33 | ||
34 | sort_coord(&min, &max); | |
35 | ||
36 | size->x = max.x-min.x; | |
37 | size->y = max.y-min.y; | |
38 | center->x = (min.x+max.x)/2; | |
39 | center->y = -(min.y+max.y)/2; | |
40 | } | |
41 | ||
42 | static unit_type geda_pad_width(struct coord size) | |
43 | { | |
44 | if (size.x >= size.y) { | |
45 | return size.y; | |
46 | } else { | |
47 | return size.x; | |
48 | } | |
49 | } | |
50 | ||
51 | static void geda_pad_start_finish(struct coord a, struct coord b, | |
52 | struct coord *start, struct coord *finish) | |
53 | { | |
54 | struct coord size, center, min, max; | |
55 | ||
56 | min.x = units_to_geda(a.x); | |
57 | min.y = units_to_geda(a.y); | |
58 | max.x = units_to_geda(b.x); | |
59 | max.y = units_to_geda(b.y); | |
60 | ||
61 | sort_coord(&min, &max); | |
62 | ||
63 | size.x = max.x-min.x; | |
64 | size.y = max.y-min.y; | |
65 | center.x = (min.x+max.x)/2; | |
66 | center.y = -(min.y+max.y)/2; | |
67 | /* gEDA pads are drawn as a line, of a certain thickness */ | |
68 | if (size.x >= size.y) { /* wider than tall, width = size.y */ | |
69 | start->x = min.x + size.y/2; | |
70 | start->y = -center.y; | |
71 | finish->x = max.x - size.y/2; | |
72 | finish->y = -center.y; | |
73 | } else { /* taller than wide, width = size.x */ | |
74 | start->y = (min.y + size.x/2); | |
75 | start->x = center.x; | |
76 | finish->y = (max.y - size.x/2); | |
77 | finish->x = center.x; | |
78 | } | |
79 | } | |
80 | ||
81 | static void do_geda_drill(FILE *file, const struct inst *pad, struct coord *padSize) | |
82 | { | |
83 | const struct inst *hole = pad->u.pad.hole; | |
84 | struct coord center, size; | |
85 | ||
86 | if (!hole) | |
87 | return; | |
88 | ||
89 | geda_centric(hole->base, hole->u.hole.other, ¢er, &size); | |
90 | ||
91 | fprintf(file, "%d %d ", center.x, -center.y); /* x,y position of hole */ | |
92 | if (padSize->x <= padSize->y) { /* sort out diameter of copper annulus, remembering obrounds*/ | |
93 | fprintf(file, "%d ", padSize->x); | |
94 | } else { | |
95 | fprintf(file, "%d ", padSize->y); | |
96 | } | |
97 | fprintf(file, "100 100 %d", size.x); /* default copper clearance, mask, then drill size */ | |
98 | } | |
99 | ||
100 | ||
101 | static void geda_pad(FILE *file, const struct inst *inst) | |
102 | { | |
103 | struct coord center, size, start, finish; | |
104 | ||
105 | geda_centric(inst->base, inst->u.pad.other, ¢er, &size); | |
106 | ||
107 | if (inst->u.pad.hole) { /* pin */ | |
108 | /* Pin[X Y Thickness Clearance Mask Drill Name Number SFlags] */ | |
109 | fprintf(file, "\tPin["); | |
110 | do_geda_drill(file, inst, &size); /* need pad size to figure out annulus */ | |
111 | fprintf(file, " \"%s\" \"%s\"", inst->u.pad.name, inst->u.pad.name); | |
112 | if (inst->obj->u.pad.rounded) { /* round pin */ | |
113 | fprintf(file, " \"\"]\n"); | |
114 | } else { /* square pad, ignore octagonal for now */ | |
115 | fprintf(file, " \"square\"]\n"); | |
116 | } | |
117 | } else { /* SMD */ | |
118 | /* Pad[X1 Y1 X2 Y2 Thickness Clearance Mask Name Number SFlags] */ | |
119 | geda_pad_start_finish(inst->base, inst->u.pad.other, &start, &finish); | |
120 | fprintf(file, "\tPad[%d %d %d %d %d 100 100 \"%s\" \"%s\" \"square\"]\n", start.x, -start.y, finish.x, -finish.y, geda_pad_width(size), inst->u.pad.name, inst->u.pad.name); | |
121 | } | |
122 | } | |
123 | ||
124 | ||
125 | static void geda_hole(FILE *file, const struct inst *inst) | |
126 | { | |
127 | struct coord center, size; | |
128 | if (inst->u.hole.pad) | |
129 | return; | |
130 | geda_centric(inst->base, inst->u.hole.other, ¢er, &size); | |
131 | ||
132 | /* Pin[X Y Thickness Clearance Mask Drill Name Number SFlags] */ | |
133 | ||
134 | fprintf(file, "\tPin[%d %d", center.x, center.y); | |
135 | if (size.x <= size.y) { /* see which obround dimension is smallest */ | |
136 | fprintf(file, " %d 100 100 %d", size.x, size.x); | |
137 | /* obround hole turned into round hole of diameter size.x */ | |
138 | } else { | |
139 | fprintf(file, " %d 100 100 %d", size.y, size.y); | |
140 | /* obround hole turned into round hole of diameter size.y */ | |
141 | } | |
142 | fprintf(file, " \"\" \"\" \"hole\"]\n"); | |
143 | } | |
144 | ||
145 | static void geda_line(FILE *file, const struct inst *inst) | |
146 | { | |
147 | /* | |
148 | * Xstart, Ystart, Xend, Yend, Width | |
149 | */ | |
150 | fprintf(file, "\tElementLine[%d %d %d %d %d]\n", | |
151 | units_to_geda(inst->base.x), | |
152 | -units_to_geda(inst->base.y), | |
153 | units_to_geda(inst->u.rect.end.x), | |
154 | -units_to_geda(inst->u.rect.end.y), | |
155 | units_to_geda(inst->u.rect.width)); | |
156 | } | |
157 | ||
158 | ||
159 | static void geda_rect(FILE *file, const struct inst *inst) | |
160 | { | |
161 | unit_type xa, ya, xb, yb; | |
162 | unit_type width; | |
163 | ||
164 | xa = units_to_geda(inst->base.x); | |
165 | ya = units_to_geda(inst->base.y); | |
166 | xb = units_to_geda(inst->u.rect.end.x); | |
167 | yb = units_to_geda(inst->u.rect.end.y); | |
168 | width = units_to_geda(inst->u.rect.width); | |
169 | ||
170 | fprintf(file, "\tElementLine[%d %d %d %d %d]\n", | |
171 | xa, -ya, xa, -yb, width); | |
172 | fprintf(file, "\tElementLine[%d %d %d %d %d]\n", | |
173 | xa, -yb, xb, -yb, width); | |
174 | fprintf(file, "\tElementLine[%d %d %d %d %d]\n", | |
175 | xb, -yb, xb, -ya, width); | |
176 | fprintf(file, "\tElementLine[%d %d %d %d %d]\n", | |
177 | xb, -ya, xa, -ya, width); | |
178 | } | |
179 | ||
180 | ||
181 | static void geda_circ(FILE *file, const struct inst *inst) | |
182 | { | |
183 | /* | |
184 | * Xcenter, Ycenter, Width, Height, startAngle, stopAngle, Width | |
185 | */ | |
186 | fprintf(file, "\tElementArc[ %d %d %d %d 0 360 %d]\n", | |
187 | units_to_geda(inst->base.x), | |
188 | -units_to_geda(inst->base.y), | |
189 | units_to_geda(inst->u.arc.r), | |
190 | units_to_geda(inst->u.arc.r), | |
191 | units_to_geda(inst->u.arc.width)); | |
192 | } | |
193 | ||
194 | ||
195 | static void geda_arc(FILE *file, const struct inst *inst) | |
196 | { | |
197 | double b; | |
198 | ||
199 | /* | |
200 | * Xcenter, Ycenter, Width, Height, startAngle, stopAngle, Width | |
201 | * | |
202 | */ | |
203 | b = inst->u.arc.a1 - 180; | |
204 | while (b <= 0) | |
205 | b += 360; | |
206 | while (b > 360) | |
207 | b -= 360; | |
208 | fprintf(file, "\tElementArc[%d %d %d %d %d %d %d]\n", | |
209 | units_to_geda(inst->base.x), | |
210 | -units_to_geda(inst->base.y), | |
211 | units_to_geda(inst->u.arc.r), | |
212 | units_to_geda(inst->u.arc.r), | |
213 | (int) b, | |
214 | (int) (inst->u.arc.a2-inst->u.arc.a1), | |
215 | units_to_geda(inst->u.arc.width)); | |
216 | } | |
217 | ||
218 | static void geda_layout_header(FILE *file) | |
219 | { | |
220 | fprintf(file, "# release: pcb 20110918\n\n"); | |
221 | fprintf(file, "# To read pcb files, the pcb version (or the git source date) must be >= the file version\n"); | |
222 | fprintf(file, "FileVersion[20070407]\n\n"); | |
223 | fprintf(file, "PCB[\"\" 600000 500000]\n\n"); | |
224 | fprintf(file, "Grid[2500.0 0 0 1]\n"); | |
225 | fprintf(file, "Cursor[2500 62500 0.000000]\n"); | |
226 | fprintf(file, "PolyArea[3100.006200]\n"); | |
227 | fprintf(file, "Thermal[0.500000]\n"); | |
228 | fprintf(file, "DRC[1200 900 1000 700 1500 1000]\n"); | |
229 | fprintf(file, "Flags(\"nameonpcb,clearnew,snappin\")\n"); | |
230 | fprintf(file, "Groups(\"1,3,4,c:2,5,6,s:7:8\")\n"); | |
231 | fprintf(file, "Styles[\"Signal,1000,7874,3150,2000:Power,2000,8661,3937,2000:Fat,8000,13780,4724,2500:Sig-tight,1000,6400,3150,1200\"]\n\n"); | |
232 | fprintf(file, "Attribute(\"PCB::grid::unit\" \"mil\")"); | |
233 | } | |
234 | ||
235 | static void geda_layout_footer(FILE *file) | |
236 | { | |
237 | fprintf(file, "Layer(1 \"component\")\n(\n)\n"); | |
238 | fprintf(file, "Layer(2 \"solder\")\n(\n)\n"); | |
239 | fprintf(file, "Layer(3 \"comp-GND\")\n(\n)\n"); | |
240 | fprintf(file, "Layer(4 \"comp-power\")\n(\n)\n"); | |
241 | fprintf(file, "Layer(5 \"sold-GND\")\n(\n)\n"); | |
242 | fprintf(file, "Layer(6 \"sold-power\")\n(\n)\n"); | |
243 | fprintf(file, "Layer(7 \"signal3\")\n(\n)\n"); | |
244 | fprintf(file, "Layer(8 \"outline\")\n(\n)\n"); | |
245 | fprintf(file, "Layer(9 \"silk\")\n(\n)\n"); | |
246 | fprintf(file, "Layer(10 \"silk\")\n(\n)\n"); | |
247 | } | |
248 | ||
249 | static void geda_inst(FILE *file, enum inst_prio prio, const struct inst *inst) | |
250 | { | |
251 | switch (prio) { | |
252 | case ip_pad_copper: | |
253 | case ip_pad_special: | |
254 | geda_pad(file, inst); | |
255 | break; | |
256 | case ip_hole: | |
257 | geda_hole(file, inst); /* obround is exported as a round circle */ | |
258 | break; | |
259 | case ip_line: | |
260 | geda_line(file, inst); | |
261 | break; | |
262 | case ip_rect: | |
263 | geda_rect(file, inst); | |
264 | break; | |
265 | case ip_circ: | |
266 | geda_circ(file, inst); | |
267 | break; | |
268 | case ip_arc: | |
269 | geda_arc(file, inst); | |
270 | break; | |
271 | default: | |
272 | /* | |
273 | * Don't try to export vectors, frame references, or | |
274 | * measurements. | |
275 | */ | |
276 | break; | |
277 | } | |
278 | } | |
279 | ||
280 | ||
281 | static void geda_module(FILE *file, const struct pkg *pkg, time_t now) | |
282 | { | |
283 | enum inst_prio prio; | |
284 | const struct inst *inst; | |
285 | ||
286 | fprintf(file, "# Footprint generated by FPED utility\n"); | |
287 | fprintf(file, "Element[\"\" \"%s\" \"\" \"\" 0 0 -25590 -14874 0 100 \"\"]\n", pkg->name); | |
288 | fprintf(file, "(\n"); | |
289 | ||
290 | FOR_INST_PRIOS_UP(prio) { | |
291 | for (inst = pkgs->insts[prio]; inst; inst = inst->next) | |
292 | geda_inst(file, prio, inst); | |
293 | for (inst = pkg->insts[prio]; inst; inst = inst->next) | |
294 | geda_inst(file, prio, inst); | |
295 | } | |
296 | ||
297 | fprintf(file, ")\n\n"); /* extra newline between elements */ | |
298 | } | |
299 | ||
300 | ||
301 | int geda(FILE *file, const char *one) | |
302 | { | |
303 | const struct pkg *pkg; | |
304 | time_t now = time(NULL); | |
305 | ||
306 | assert(!one); | |
307 | ||
308 | geda_layout_header(file); /* we place one or more elements in a layout file */ | |
309 | ||
310 | for (pkg = pkgs; pkg; pkg = pkg->next) | |
311 | if (pkg->name) | |
312 | fprintf(file, "# %s\n", pkg->name); | |
313 | ||
314 | for (pkg = pkgs; pkg; pkg = pkg->next) | |
315 | if (pkg->name) | |
316 | geda_module(file, pkg, now); | |
317 | ||
318 | geda_layout_footer(file); | |
319 | ||
320 | fflush(file); | |
321 | return !ferror(file); | |
322 | } |
geda.h | ||
---|---|---|
1 | /* | |
2 | * geda_pcb.h - Dump objects in the gEDA PCB board/module format | |
3 | * | |
4 | * Written 2009, 2011 by Werner Almesberger, 2016 by Erich Heinzle | |
5 | * Copyright 2009, 2011 by Werner Almesberger | |
6 | * Copyright 2016, Erich Heinzle | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | */ | |
13 | ||
14 | ||
15 | #ifndef GEDA_H | |
16 | #define GEDA_H | |
17 | ||
18 | #include <stdio.h> | |
19 | ||
20 | ||
21 | int geda(FILE *file, const char *one); | |
22 | ||
23 | #endif /* !GEDA_H */ |
gui.c | ||
---|---|---|
3 | 3 | * |
4 | 4 | * Written 2009-2012, 2015-2016 by Werner Almesberger |
5 | 5 | * Copyright 2009-2012, 2015-2016 by Werner Almesberger |
6 | * Copyright 2016, Erich Heinzle (gEDA additions) | |
6 | 7 | * |
7 | 8 | * This program is free software; you can redistribute it and/or modify |
8 | 9 | * it under the terms of the GNU General Public License as published by |
... | ... | |
149 | 150 | { "/File/Save as", NULL, save_as_fpd, 0, "<Item>" }, |
150 | 151 | { "/File/sep1", NULL, NULL, 0, "<Separator>" }, |
151 | 152 | { "/File/Write KiCad", NULL, write_kicad, 0, "<Item>" }, |
153 | { "/File/Write gEDA", NULL, write_geda, 0, "<Item>" }, | |
152 | 154 | { "/File/Write Postscript", |
153 | 155 | NULL, write_ps, 0, "<Item>" }, |
154 | 156 | { "/File/sep2", NULL, NULL, 0, "<Separator>" }, |
Branches:
master