2 * gEDA - GNU Electronic Design Automation
3 * This file is a part of gerbv.
5 * Copyright (C) 2008 Julian Lamb
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
36 #include <glib/gstdio.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)
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
);
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
) {
59 int numberOfPoints
= (int) ls
->parameter
[OUTLINE_NUMBER_OF_POINTS
];
61 fprintf(fd
, "4,%d,%d,\n",(int) ls
->parameter
[OUTLINE_EXPOSURE
],
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
]);
110 /* and finally create an aperture definition to use the macro */
111 fprintf(fd
, "%%ADD%dMACRO%d*%%\n",apertureNumber
,apertureNumber
);
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
)
127 switch (currentAperture
->type
) {
129 fprintf(fd
, "%%ADD%d",i
);
131 numberOfRequiredParameters
= 1;
132 numberOfOptionalParameters
= 2;
135 fprintf(fd
, "%%ADD%d",i
);
137 numberOfRequiredParameters
= 2;
138 numberOfOptionalParameters
= 2;
141 fprintf(fd
, "%%ADD%d",i
);
143 numberOfRequiredParameters
= 2;
144 numberOfOptionalParameters
= 2;
147 fprintf(fd
, "%%ADD%d",i
);
149 numberOfRequiredParameters
= 2;
150 numberOfOptionalParameters
= 3;
153 export_rs274x_write_macro (fd
, currentAperture
, i
);
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 */
167 fprintf(fd
, "%.4f",currentAperture
->parameter
[j
]);
170 fprintf(fd
, "*%%\n");
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");
182 fprintf(fd
, "%%LPD*%%\n");
187 export_rs274x_write_state_change (gerbv_netstate_t
*oldState
, gerbv_netstate_t
*newState
, FILE *fd
) {
193 gerbv_export_rs274x_file_from_image (gchar
*filename
, gerbv_image_t
*image
) {
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
);
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 */
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
);
214 if (image
->info
->polarity
== CLEAR
)
215 fprintf(fd
, "%%IPNEG*%%\n");
217 fprintf(fd
, "%%IPPOS*%%\n");
219 if (image
->info
->name
)
220 fprintf(fd
, "%%IN%s*%%\n",image
->info
->name
);
222 if (image
->info
->plotterFilm
)
223 fprintf(fd
, "%%PF%s*%%\n",image
->info
->plotterFilm
);
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
)
233 fprintf(fd
, "%.4f",image
->info
->imageJustifyOffsetA
);
235 if (image
->info
->imageJustifyTypeB
== CENTERJUSTIFY
)
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
) {
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");
297 fprintf(fd
, "D03*\n");
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
)
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
);
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");
332 fprintf(fd
, "D03*\n");
335 fprintf(fd
, "G36*\n");
336 insidePolygon
= TRUE
;
339 fprintf(fd
, "G37*\n");
340 insidePolygon
= FALSE
;
348 fprintf(fd
, "G04 --Footer info--*\n");
349 fprintf(fd
, "M02*\n");