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