Root/
Source at commit 103933acf59927d84df7f99d9580dfc0f45059c2 created 7 years 2 months ago. By Werner Almesberger, fix a few whitespace issues in previous commit | |
---|---|
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 | b = inst->u.arc.a1 - 180; |
203 | while (b <= 0) |
204 | b += 360; |
205 | while (b > 360) |
206 | b -= 360; |
207 | fprintf(file, "\tElementArc[%d %d %d %d %d %d %d]\n", |
208 | units_to_geda(inst->base.x), |
209 | -units_to_geda(inst->base.y), |
210 | units_to_geda(inst->u.arc.r), |
211 | units_to_geda(inst->u.arc.r), |
212 | (int) b, |
213 | (int) (inst->u.arc.a2-inst->u.arc.a1), |
214 | units_to_geda(inst->u.arc.width)); |
215 | } |
216 | |
217 | static void geda_layout_header(FILE *file) |
218 | { |
219 | fprintf(file, "# release: pcb 20110918\n\n"); |
220 | fprintf(file, "# To read pcb files, the pcb version (or the git source date) must be >= the file version\n"); |
221 | fprintf(file, "FileVersion[20070407]\n\n"); |
222 | fprintf(file, "PCB[\"\" 600000 500000]\n\n"); |
223 | fprintf(file, "Grid[2500.0 0 0 1]\n"); |
224 | fprintf(file, "Cursor[2500 62500 0.000000]\n"); |
225 | fprintf(file, "PolyArea[3100.006200]\n"); |
226 | fprintf(file, "Thermal[0.500000]\n"); |
227 | fprintf(file, "DRC[1200 900 1000 700 1500 1000]\n"); |
228 | fprintf(file, "Flags(\"nameonpcb,clearnew,snappin\")\n"); |
229 | fprintf(file, "Groups(\"1,3,4,c:2,5,6,s:7:8\")\n"); |
230 | 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"); |
231 | fprintf(file, "Attribute(\"PCB::grid::unit\" \"mil\")"); |
232 | } |
233 | |
234 | static void geda_layout_footer(FILE *file) |
235 | { |
236 | fprintf(file, "Layer(1 \"component\")\n(\n)\n"); |
237 | fprintf(file, "Layer(2 \"solder\")\n(\n)\n"); |
238 | fprintf(file, "Layer(3 \"comp-GND\")\n(\n)\n"); |
239 | fprintf(file, "Layer(4 \"comp-power\")\n(\n)\n"); |
240 | fprintf(file, "Layer(5 \"sold-GND\")\n(\n)\n"); |
241 | fprintf(file, "Layer(6 \"sold-power\")\n(\n)\n"); |
242 | fprintf(file, "Layer(7 \"signal3\")\n(\n)\n"); |
243 | fprintf(file, "Layer(8 \"outline\")\n(\n)\n"); |
244 | fprintf(file, "Layer(9 \"silk\")\n(\n)\n"); |
245 | fprintf(file, "Layer(10 \"silk\")\n(\n)\n"); |
246 | } |
247 | |
248 | static void geda_inst(FILE *file, enum inst_prio prio, const struct inst *inst) |
249 | { |
250 | switch (prio) { |
251 | case ip_pad_copper: |
252 | case ip_pad_special: |
253 | geda_pad(file, inst); |
254 | break; |
255 | case ip_hole: |
256 | geda_hole(file, inst); /* obround is exported as a round circle */ |
257 | break; |
258 | case ip_line: |
259 | geda_line(file, inst); |
260 | break; |
261 | case ip_rect: |
262 | geda_rect(file, inst); |
263 | break; |
264 | case ip_circ: |
265 | geda_circ(file, inst); |
266 | break; |
267 | case ip_arc: |
268 | geda_arc(file, inst); |
269 | break; |
270 | default: |
271 | /* |
272 | * Don't try to export vectors, frame references, or |
273 | * measurements. |
274 | */ |
275 | break; |
276 | } |
277 | } |
278 | |
279 | |
280 | static void geda_module(FILE *file, const struct pkg *pkg, time_t now) |
281 | { |
282 | enum inst_prio prio; |
283 | const struct inst *inst; |
284 | |
285 | fprintf(file, "# Footprint generated by FPED utility\n"); |
286 | fprintf(file, "Element[\"\" \"%s\" \"\" \"\" 0 0 -25590 -14874 0 100 \"\"]\n", pkg->name); |
287 | fprintf(file, "(\n"); |
288 | |
289 | FOR_INST_PRIOS_UP(prio) { |
290 | for (inst = pkgs->insts[prio]; inst; inst = inst->next) |
291 | geda_inst(file, prio, inst); |
292 | for (inst = pkg->insts[prio]; inst; inst = inst->next) |
293 | geda_inst(file, prio, inst); |
294 | } |
295 | |
296 | fprintf(file, ")\n\n"); /* extra newline between elements */ |
297 | } |
298 | |
299 | |
300 | int geda(FILE *file, const char *one) |
301 | { |
302 | const struct pkg *pkg; |
303 | time_t now = time(NULL); |
304 | |
305 | assert(!one); |
306 | |
307 | geda_layout_header(file); /* we place one or more elements in a layout file */ |
308 | |
309 | for (pkg = pkgs; pkg; pkg = pkg->next) |
310 | if (pkg->name) |
311 | fprintf(file, "# %s\n", pkg->name); |
312 | |
313 | for (pkg = pkgs; pkg; pkg = pkg->next) |
314 | if (pkg->name) |
315 | geda_module(file, pkg, now); |
316 | |
317 | geda_layout_footer(file); |
318 | |
319 | fflush(file); |
320 | return !ferror(file); |
321 | } |
322 |
Branches:
master