* change all gerb_* namespace to gerbv_* namespace, clarifying the libgerbv API.
[geda-gerbv.git] / src / export-rs274x.c
blobf203222a5a368bab6b1e2ed363cbce24ed0d8f34
1 /*
2 * gEDA - GNU Electronic Design Automation
3 * This file is a part of gerbv.
5 * Copyright (C) 2008 Julian Lamb
7 * $Id$
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
24 /** @file export-rs274x.c
25 @brief Functions to export an image to a RS274X file
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
33 #include <glib.h>
34 #include <math.h>
36 #include <glib/gstdio.h>
37 #include "gerbv.h"
38 #include "draw-gdk.h"
40 /* DEBUG printing. #define DEBUG 1 in config.h to use this fcn. */
41 #define dprintf if(DEBUG) printf
42 #define round(x) floor(x+0.5)
44 void
45 export_rs274x_write_macro (FILE *fd, gerbv_aperture_t *currentAperture,
46 gint apertureNumber) {
47 gerbv_simplified_amacro_t *ls = currentAperture->simplified;
49 /* write the macro portion first */
50 fprintf(fd, "%%AMMACRO%d*\n",apertureNumber);
51 while (ls != NULL) {
52 if (ls->type == MACRO_CIRCLE) {
53 fprintf(fd, "1,%d,%f,%f,%f*\n",(int) ls->parameter[CIRCLE_EXPOSURE],
54 ls->parameter[CIRCLE_DIAMETER],ls->parameter[CIRCLE_CENTER_X],
55 ls->parameter[CIRCLE_CENTER_Y]);
57 else if (ls->type == MACRO_OUTLINE) {
58 int pointCounter;
59 int numberOfPoints = (int) ls->parameter[OUTLINE_NUMBER_OF_POINTS];
61 fprintf(fd, "4,%d,%d,\n",(int) ls->parameter[OUTLINE_EXPOSURE],
62 numberOfPoints);
64 for (pointCounter=0; pointCounter < numberOfPoints; pointCounter++) {
65 fprintf(fd, "%f,%f,",ls->parameter[pointCounter * 2 + OUTLINE_FIRST_X],
66 ls->parameter[pointCounter * 2 + OUTLINE_FIRST_Y]);
68 fprintf(fd, "%f*\n",ls->parameter[pointCounter * 2 + OUTLINE_FIRST_X]);
70 else if (ls->type == MACRO_POLYGON) {
71 fprintf(fd, "5,%d,%d,%f,%f,%f,%f*\n",(int) ls->parameter[POLYGON_EXPOSURE],
72 (int) ls->parameter[POLYGON_NUMBER_OF_POINTS],
73 ls->parameter[POLYGON_CENTER_X],ls->parameter[POLYGON_CENTER_Y],
74 ls->parameter[POLYGON_DIAMETER],ls->parameter[POLYGON_ROTATION]);
76 else if (ls->type == MACRO_MOIRE) {
77 fprintf(fd, "6,%f,%f,%f,%f,%f,%d,%f,%f,%f*\n",ls->parameter[MOIRE_CENTER_X],
78 ls->parameter[MOIRE_CENTER_Y],ls->parameter[MOIRE_OUTSIDE_DIAMETER],
79 ls->parameter[MOIRE_CIRCLE_THICKNESS],ls->parameter[MOIRE_GAP_WIDTH],
80 (int) ls->parameter[MOIRE_NUMBER_OF_CIRCLES],ls->parameter[MOIRE_CROSSHAIR_THICKNESS],
81 ls->parameter[MOIRE_CROSSHAIR_LENGTH],ls->parameter[MOIRE_ROTATION]);
83 else if (ls->type == MACRO_THERMAL) {
84 fprintf(fd, "7,%f,%f,%f,%f,%f,%f*\n",ls->parameter[THERMAL_CENTER_X],
85 ls->parameter[THERMAL_CENTER_Y],ls->parameter[THERMAL_OUTSIDE_DIAMETER],
86 ls->parameter[THERMAL_INSIDE_DIAMETER],ls->parameter[THERMAL_CROSSHAIR_THICKNESS],
87 ls->parameter[THERMAL_ROTATION]);
89 else if (ls->type == MACRO_LINE20) {
90 fprintf(fd, "20,%d,%f,%f,%f,%f,%f,%f*\n",(int) ls->parameter[LINE20_EXPOSURE],
91 ls->parameter[LINE20_LINE_WIDTH],ls->parameter[LINE20_START_X],
92 ls->parameter[LINE20_START_Y],ls->parameter[LINE20_END_X],
93 ls->parameter[LINE20_END_Y],ls->parameter[LINE20_ROTATION]);
95 else if (ls->type == MACRO_LINE21) {
96 fprintf(fd, "21,%d,%f,%f,%f,%f,%f*\n",(int) ls->parameter[LINE21_EXPOSURE],
97 ls->parameter[LINE21_WIDTH],ls->parameter[LINE21_HEIGHT],
98 ls->parameter[LINE21_CENTER_X],ls->parameter[LINE21_CENTER_Y],
99 ls->parameter[LINE21_ROTATION]);
101 else if (ls->type == MACRO_LINE22) {
102 fprintf(fd, "22,%d,%f,%f,%f,%f,%f*\n",(int) ls->parameter[LINE22_EXPOSURE],
103 ls->parameter[LINE22_WIDTH],ls->parameter[LINE22_HEIGHT],
104 ls->parameter[LINE22_LOWER_LEFT_X],ls->parameter[LINE22_LOWER_LEFT_Y],
105 ls->parameter[LINE22_ROTATION]);
107 ls = ls->next;
109 fprintf(fd, "%%\n");
110 /* and finally create an aperture definition to use the macro */
111 fprintf(fd, "%%ADD%dMACRO%d*%%\n",apertureNumber,apertureNumber);
114 void
115 export_rs274x_write_apertures (FILE *fd, gerbv_image_t *image) {
116 gerbv_aperture_t *currentAperture;
117 gint numberOfRequiredParameters=0,numberOfOptionalParameters=0,i,j;
119 for (i=APERTURE_MIN; i<APERTURE_MAX; i++) {
120 gboolean writeAperture=TRUE;
122 currentAperture = image->aperture[i];
124 if (!currentAperture)
125 continue;
127 switch (currentAperture->type) {
128 case CIRCLE:
129 fprintf(fd, "%%ADD%d",i);
130 fprintf(fd, "C,");
131 numberOfRequiredParameters = 1;
132 numberOfOptionalParameters = 2;
133 break;
134 case RECTANGLE:
135 fprintf(fd, "%%ADD%d",i);
136 fprintf(fd, "R,");
137 numberOfRequiredParameters = 2;
138 numberOfOptionalParameters = 2;
139 break;
140 case OVAL:
141 fprintf(fd, "%%ADD%d",i);
142 fprintf(fd, "O,");
143 numberOfRequiredParameters = 2;
144 numberOfOptionalParameters = 2;
145 break;
146 case POLYGON:
147 fprintf(fd, "%%ADD%d",i);
148 fprintf(fd, "P,");
149 numberOfRequiredParameters = 2;
150 numberOfOptionalParameters = 3;
151 break;
152 case MACRO:
153 export_rs274x_write_macro (fd, currentAperture, i);
154 writeAperture=FALSE;
155 break;
156 default:
157 writeAperture=FALSE;
158 break;
160 if (writeAperture) {
161 /* write the parameter list */
162 for (j=0; j<(numberOfRequiredParameters + numberOfOptionalParameters); j++) {
163 if ((j < numberOfRequiredParameters) || (currentAperture->parameter[j] != 0)) {
164 /* print the "X" character to separate the parameters */
165 if (j>0)
166 fprintf(fd, "X");
167 fprintf(fd, "%.4f",currentAperture->parameter[j]);
170 fprintf(fd, "*%%\n");
175 void
176 export_rs274x_write_layer_change (gerbv_layer_t *oldLayer, gerbv_layer_t *newLayer, FILE *fd) {
177 if (oldLayer->polarity != newLayer->polarity) {
178 /* polarity changed */
179 if ((newLayer->polarity == CLEAR))
180 fprintf(fd, "%%LPC*%%\n");
181 else
182 fprintf(fd, "%%LPD*%%\n");
186 void
187 export_rs274x_write_state_change (gerbv_netstate_t *oldState, gerbv_netstate_t *newState, FILE *fd) {
192 gboolean
193 gerbv_export_rs274x_file_from_image (gchar *filename, gerbv_image_t *image) {
194 FILE *fd;
195 gerbv_netstate_t *oldState;
196 gerbv_layer_t *oldLayer;
197 gboolean insidePolygon=FALSE;
199 if ((fd = g_fopen(filename, "w")) == NULL) {
200 GERB_MESSAGE("Can't open file for writing: %s\n", filename);
201 return FALSE;
203 /* write header info */
204 fprintf(fd, "G04 Exported by Gerber Viewer version %s*\n",VERSION);
205 fprintf(fd, "G04 --Header info--*\n");
206 fprintf(fd, "%%MOIN*%%\n");
207 fprintf(fd, "%%FSLAX23Y23*%%\n");
209 /* check the image info struct for any non-default settings */
210 /* image offset */
211 if ((image->info->offsetA > 0.0) || (image->info->offsetB > 0.0))
212 fprintf(fd, "%%IOA%fB%f*%%\n",image->info->offsetA,image->info->offsetB);
213 /* image polarity */
214 if (image->info->polarity == CLEAR)
215 fprintf(fd, "%%IPNEG*%%\n");
216 else
217 fprintf(fd, "%%IPPOS*%%\n");
218 /* image name */
219 if (image->info->name)
220 fprintf(fd, "%%IN%s*%%\n",image->info->name);
221 /* plotter film */
222 if (image->info->plotterFilm)
223 fprintf(fd, "%%PF%s*%%\n",image->info->plotterFilm);
224 /* image rotation */
225 if (image->info->imageRotation != 0.0)
226 fprintf(fd, "%%IR%d*%%\n",(int) image->info->imageRotation);
227 if ((image->info->imageJustifyTypeA != NOJUSTIFY) ||
228 (image->info->imageJustifyTypeB != NOJUSTIFY)) {
229 fprintf(fd, "%%IJA");
230 if (image->info->imageJustifyTypeA == CENTERJUSTIFY)
231 fprintf(fd, "C");
232 else
233 fprintf(fd, "%.4f",image->info->imageJustifyOffsetA);
234 fprintf(fd, "B");
235 if (image->info->imageJustifyTypeB == CENTERJUSTIFY)
236 fprintf(fd, "C");
237 else
238 fprintf(fd, "%.4f",image->info->imageJustifyOffsetB);
239 fprintf(fd, "*%%\n");
242 /* define all apertures */
243 fprintf(fd, "G04 --Define apertures--*\n");
244 export_rs274x_write_apertures (fd, image);
246 /* write rest of image */
247 fprintf(fd, "G04 --Start main section--*\n");
248 gint currentAperture = 0;
249 gerbv_net_t *currentNet;
251 oldLayer = image->layers;
252 oldState = image->states;
253 /* skip the first net, since it's always zero due to the way we parse things */
254 for (currentNet = image->netlist->next; currentNet; currentNet = currentNet->next){
255 /* check for "layer" changes (RS274X commands) */
256 if (currentNet->layer != oldLayer)
257 export_rs274x_write_layer_change (oldLayer, currentNet->layer, fd);
259 /* check for new "netstate" (more RS274X commands) */
260 if (currentNet->state != oldState)
261 export_rs274x_write_state_change (oldState, currentNet->state, fd);
263 /* check for tool changes */
264 /* also, make sure the aperture number is a valid one, since sometimes
265 the loaded file may refer to invalid apertures */
266 if ((currentNet->aperture != currentAperture)&&
267 (image->aperture[currentNet->aperture] != NULL)) {
268 fprintf(fd, "G54D%02d*\n",currentNet->aperture);
269 currentAperture = currentNet->aperture;
272 oldLayer = currentNet->layer;
273 oldState = currentNet->state;
275 long xVal,yVal,endX,endY,centerX,centerY;
276 switch (currentNet->interpolation) {
277 case LINEARx10 :
278 case LINEARx01 :
279 case LINEARx001 :
280 case LINEARx1 :
281 /* see if we need to write an "aperture off" line to get
282 the pen to the right start point */
283 if ((!insidePolygon) && (currentNet->aperture_state == ON)) {
284 xVal = (long) round(currentNet->start_x * 1000.0);
285 yVal = (long) round(currentNet->start_y * 1000.0);
286 fprintf(fd, "G01X%05ldY%05ldD02*\n",xVal,yVal);
288 xVal = (long) round(currentNet->stop_x * 1000.0);
289 yVal = (long) round(currentNet->stop_y * 1000.0);
290 fprintf(fd, "G01X%05ldY%05ld",xVal,yVal);
291 /* and finally, write the esposure value */
292 if (currentNet->aperture_state == OFF)
293 fprintf(fd, "D02*\n");
294 else if (currentNet->aperture_state == ON)
295 fprintf(fd, "D01*\n");
296 else
297 fprintf(fd, "D03*\n");
298 break;
299 case CW_CIRCULAR :
300 case CCW_CIRCULAR :
301 /* see if we need to write an "aperture off" line to get
302 the pen to the right start point */
303 if ((!insidePolygon) && (currentNet->aperture_state == ON)) {
304 xVal = (long) round(currentNet->start_x * 1000.0);
305 yVal = (long) round(currentNet->start_y * 1000.0);
306 fprintf(fd, "G01X%05ldY%05ldD02*\n",xVal,yVal);
308 centerX= (long) round((currentNet->cirseg->cp_x - currentNet->start_x) * 1000.0);
309 centerY= (long) round((currentNet->cirseg->cp_y - currentNet->start_y) * 1000.0);
310 endX = (long) round(currentNet->stop_x * 1000.0);
311 endY = (long) round(currentNet->stop_y * 1000.0);
313 /* always use multi-quadrant, since it's much easier to export */
314 /* and most all software should support it */
315 fprintf(fd, "G75*\n");
316 /* figure out clockwise or c-clockwise */
317 if (currentNet->cirseg->angle2 > currentNet->cirseg->angle1)
318 fprintf(fd, "G03");
319 else
320 fprintf(fd, "G02");
321 /* don't write the I and J values if the exposure is off */
322 if (currentNet->aperture_state == ON)
323 fprintf(fd, "X%05ldY%05ldI%05ldJ%05ld",endX,endY,centerX,centerY);
324 else
325 fprintf(fd, "X%05ldY%05ld",endX,endY);
326 /* and finally, write the esposure value */
327 if (currentNet->aperture_state == OFF)
328 fprintf(fd, "D02*\n");
329 else if (currentNet->aperture_state == ON)
330 fprintf(fd, "D01*\n");
331 else
332 fprintf(fd, "D03*\n");
333 break;
334 case PAREA_START:
335 fprintf(fd, "G36*\n");
336 insidePolygon = TRUE;
337 break;
338 case PAREA_END:
339 fprintf(fd, "G37*\n");
340 insidePolygon = FALSE;
341 break;
342 default:
343 break;
347 /* write footer */
348 fprintf(fd, "G04 --Footer info--*\n");
349 fprintf(fd, "M02*\n");
351 fclose(fd);
352 return TRUE;