1 /*
2 * gEDA - GNU Electronic Design Automation
3 * This file is a part of Gerbv.
4 *
5 * Copyright (C) 2014 Sergey Alyoshin
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 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 */
21
22 /** \file export-geda-pcb.c
23 \brief Functions for exporting Gerbv images to gEDA PCB files
24 \ingroup libgerbv
25 */
26
27 #include "gerbv.h"
28 #include "common.h"
29
30 #include <glib/gstdio.h>
31
32 static void
write_line(FILE * fd,gerbv_net_t * net,double thick,double dx_p,double dy_m,const char * sflags)33 write_line(FILE *fd, gerbv_net_t *net, double thick,
34 double dx_p, double dy_m, const char *sflags)
35 {
36 dx_p = COORD2MILS(dx_p);
37 dy_m = COORD2MILS(dy_m);
38
39 fprintf(fd, "\tLine[%.2fmil %.2fmil %.2fmil %.2fmil "
40 "%.2fmil %.2fmil \"%s\"]\n",
41 dx_p + COORD2MILS(net->stop_x),
42 dy_m - COORD2MILS(net->stop_y),
43 dx_p + COORD2MILS(net->start_x),
44 dy_m - COORD2MILS(net->start_y),
45 COORD2MILS(thick), 100.0, sflags);
46 }
47
48 static void
write_element_with_pad(FILE * fd,gerbv_net_t * net,double thick,double dx_p,double dy_m,const char * sflags)49 write_element_with_pad(FILE *fd, gerbv_net_t *net, double thick,
50 double dx_p, double dy_m, const char *sflags)
51 {
52 double xc, yc;
53 static unsigned int element_num = 1;
54
55 dx_p = COORD2MILS(dx_p);
56 dy_m = COORD2MILS(dy_m);
57
58 xc = COORD2MILS(net->stop_x + net->start_x)/2;
59 yc = COORD2MILS(net->stop_y + net->start_y)/2;
60
61 fprintf(fd, "Element[\"\" \"\" \"pad%d\" \"\" "
62 "%.2fmil %.2fmil 0mil 0mil 0 100 \"\"]\n(\n",
63 element_num++, dx_p + xc, dy_m - yc);
64 fprintf(fd, "\tPad[%.2fmil %.2fmil %.2fmil %.2fmil "
65 "%.2fmil 0mil %.2fmil "
66 "\"%s\" \"%s\" \"%s\"]\n)\n",
67 xc - COORD2MILS(net->stop_x),
68 yc - COORD2MILS(net->stop_y),
69 xc - COORD2MILS(net->start_x),
70 yc - COORD2MILS(net->start_y),
71 COORD2MILS(thick), /* Thickness */
72 COORD2MILS(thick), /* Mask */
73 "1", /* Name */
74 "1", /* Number */
75 sflags); /* String flags */
76 }
77
78 static void
write_polygon(FILE * fd,gerbv_net_t * net,double dx_p,double dy_m,const char * sflags)79 write_polygon(FILE *fd, gerbv_net_t *net,
80 double dx_p, double dy_m, const char *sflags)
81 {
82 dx_p = COORD2MILS(dx_p);
83 dy_m = COORD2MILS(dy_m);
84
85 fprintf(fd, "\tPolygon(\"%s\")\n\t(", sflags);
86 net = net->next;
87
88 unsigned int i = 0;
89 while (net != NULL
90 && net->interpolation != GERBV_INTERPOLATION_PAREA_END) {
91 if (net->aperture_state == GERBV_APERTURE_STATE_ON) {
92 fprintf(fd, "%s[%.2fmil %.2fmil] ",
93 !(i%5)? "\n\t\t": "",
94 dx_p + COORD2MILS(net->stop_x),
95 dy_m - COORD2MILS(net->stop_y));
96 i++;
97 }
98 net = net->next;
99 }
100
101 fprintf(fd, "\n\t)\n");
102 }
103
104 gboolean
gerbv_export_geda_pcb_file_from_image(const gchar * file_name,gerbv_image_t * input_img,gerbv_user_transformation_t * trans)105 gerbv_export_geda_pcb_file_from_image(const gchar *file_name,
106 gerbv_image_t *input_img,
107 gerbv_user_transformation_t *trans)
108 {
109 gerbv_aperture_t *apert;
110 gerbv_image_t *img;
111 gerbv_net_t *net;
112 double dx_p, dy_m;
113 double thick, len;
114 FILE *fd;
115
116 if ((fd = g_fopen(file_name, "w")) == NULL) {
117 GERB_MESSAGE(_("Can't open file for writing: %s"), file_name);
118 return FALSE;
119 }
120
121 /* Output decimals as dots for all locales */
122 setlocale(LC_NUMERIC, "C");
123
124 /* Duplicate the image, cleaning it in the process */
125 img = gerbv_image_duplicate_image(input_img, trans);
126
127 /* Header */
128 fputs("# Generated with gerbv\n\n", fd);
129 fputs("FileVersion[20091103]\n", fd);
130
131 dx_p = (img->info->max_x - img->info->min_x) - img->info->min_x;
132 dy_m = 2*(img->info->max_y - img->info->min_y) + img->info->min_y;
133
134 /* Make board size is 3 times more than Gerber size */
135 fprintf(fd, "PCB[\"%s\" %.2fmil %.2fmil]\n",
136 img->info->name,
137 3*COORD2MILS(img->info->max_x - img->info->min_x),
138 3*COORD2MILS(img->info->max_y - img->info->min_y));
139
140 fputs("Grid[1000.000000 0.0000 0.0000 0]\n", fd);
141
142 /* Write all apertures as elements with single pad, before layer
143 * definition */
144 for (net = img->netlist; net != NULL; net = net->next) {
145 apert = img->aperture[net->aperture];
146 if (!apert)
147 continue;
148
149 /* Skip polygon, it will be written in layer section */
150 if (net->interpolation == GERBV_INTERPOLATION_PAREA_START) {
151 /* Skip to the end for polygon */
152 do {
153 net = net->next;
154 } while (net != NULL && net->interpolation !=
155 GERBV_INTERPOLATION_PAREA_END);
156 continue;
157 }
158
159 switch (net->aperture_state) {
160 case GERBV_APERTURE_STATE_FLASH:
161 switch (apert->type) {
162 case GERBV_APTYPE_CIRCLE:
163 /* Set start to stop coords for Circle flash */
164 net->start_x = net->stop_x;
165 net->start_y = net->stop_y;
166 write_element_with_pad(fd, net,
167 apert->parameter[0],
168 dx_p, dy_m, "");
169 break;
170 case GERBV_APTYPE_OVAL:
171 case GERBV_APTYPE_RECTANGLE:
172
173 if (apert->parameter[0] > apert->parameter[1]) {
174 /* Horizontal */
175 len = apert->parameter[0];
176 thick = apert->parameter[1];
177
178 net->start_x = net->stop_x - len/2 +
179 thick/2;
180 net->stop_x += len/2 - thick/2;
181 net->start_y = net->stop_y;
182 } else {
183 /* Vertical */
184 len = apert->parameter[1];
185 thick = apert->parameter[0];
186
187 net->start_x = net->stop_x;
188 net->start_y = net->stop_y - len/2 +
189 thick/2;
190 net->stop_y += len/2 - thick/2;
191 }
192
193 write_element_with_pad(fd, net, thick,
194 dx_p, dy_m,
195 (apert->type == GERBV_APTYPE_RECTANGLE)?
196 "square": "");
197 break;
198 default:
199 /* TODO */
200 GERB_COMPILE_WARNING(
201 "%s:%d: aperture type %d is "
202 "not yet supported",
203 __func__, __LINE__,
204 apert->type);
205 break;
206 }
207 break;
208 case GERBV_APERTURE_STATE_ON:
209 /* Will be done in layer section */
210 break;
211 default:
212 /* TODO */
213 GERB_COMPILE_WARNING(
214 "%s:%d: aperture type %d is "
215 "not yet supported",
216 __func__, __LINE__,
217 apert->type);
218 break;
219 }
220 }
221
222 /* Write all lines in layer definition */
223 fputs("Layer(1 \"top\")\n(\n", fd);
224
225 for (net = img->netlist; net != NULL; net = net->next) {
226 apert = img->aperture[net->aperture];
227 if (!apert)
228 continue;
229
230 if (net->interpolation == GERBV_INTERPOLATION_PAREA_START) {
231 write_polygon(fd, net, dx_p, dy_m, "clearpoly");
232
233 /* Skip to the end for polygon */
234 do {
235 net = net->next;
236 } while (net != NULL && net->interpolation !=
237 GERBV_INTERPOLATION_PAREA_END);
238 continue;
239 }
240
241 switch (net->aperture_state) {
242 case GERBV_APERTURE_STATE_FLASH:
243 /* Already done in elements section */
244 break;
245
246 case GERBV_APERTURE_STATE_ON:
247 /* Trace (or cut slot in drill file) */
248 switch (apert->type) {
249 case GERBV_APTYPE_CIRCLE:
250 write_line(fd, net, apert->parameter[0],
251 dx_p, dy_m, "clearline");
252 break;
253 default:
254 GERB_COMPILE_WARNING(
255 "%s:%d: aperture type %d is "
256 "not yet supported",
257 __func__, __LINE__,
258 apert->type);
259 break;
260 }
261 break;
262 default:
263 GERB_COMPILE_WARNING(
264 "%s:%d: aperture state %d type %d is "
265 "not yet supported",
266 __func__, __LINE__,
267 net->aperture_state, apert->type);
268 break;
269 }
270 }
271
272 fputs(")\n", fd); /* End of Layer 1 */
273
274 /* Necessary layer */
275 fputs("Layer(7 \"outline\")\n(\n)\n", fd);
276
277 gerbv_destroy_image (img);
278 fclose(fd);
279
280 setlocale(LC_NUMERIC, ""); /* Return to the default locale */
281
282 return TRUE;
283 }
284