Restructure the way deleted nets are handled.
[geda-gerbv.git] / src / gerber.c
blob8592efc6acb10743971dac8dd1708afa5c7d1d04
1 /*
2 * gEDA - GNU Electronic Design Automation
3 * This is a part of gerbv
5 * Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
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 #include <stdlib.h>
25 #include <string.h>
26 #include <math.h> /* pow() */
27 #include <glib.h>
28 #include <locale.h>
29 #include <errno.h>
30 #include <ctype.h>
33 #include "config.h"
34 #include "gerber.h"
35 #include "gerb_error.h"
36 #include "gerb_stats.h"
38 //#define AMACRO_DEBUG
40 #ifndef RENDER_USING_GDK
41 #include <cairo.h>
42 #endif
44 /* include this for macro enums */
45 #include "draw-gdk.h"
47 /* DEBUG printing. #define DEBUG 1 in config.h to use this fcn. */
48 #define dprintf if(DEBUG) printf
50 //#define AMACRO_DEBUG
52 #define A2I(a,b) (((a & 0xff) << 8) + (b & 0xff))
54 #define MAXL 200
56 typedef struct gerb_state {
57 int curr_x;
58 int curr_y;
59 int prev_x;
60 int prev_y;
61 int delta_cp_x;
62 int delta_cp_y;
63 int curr_aperture;
64 int changed;
65 enum aperture_state_t aperture_state;
66 enum interpolation_t interpolation;
67 enum interpolation_t prev_interpolation;
68 gerb_net_t *parea_start_node;
69 gerb_layer_t *layer;
70 gerb_netstate_t *state;
71 int in_parea_fill;
72 int mq_on;
73 } gerb_state_t;
76 /* Local function prototypes */
77 static void parse_G_code(gerb_file_t *fd, gerb_state_t *state,
78 gerb_image_t *image);
79 static void parse_D_code(gerb_file_t *fd, gerb_state_t *state,
80 gerb_image_t *image);
81 static int parse_M_code(gerb_file_t *fd, gerb_image_t *image);
82 static void parse_rs274x(gint levelOfRecursion, gerb_file_t *fd,
83 gerb_image_t *image, gerb_state_t *state,
84 gerb_net_t *curr_net, gerb_stats_t *stats,
85 gchar *directoryPath);
86 static int parse_aperture_definition(gerb_file_t *fd,
87 gerb_aperture_t *aperture,
88 gerb_image_t *image, gdouble scale);
89 static void calc_cirseg_sq(struct gerb_net *net, int cw,
90 double delta_cp_x, double delta_cp_y);
91 static void calc_cirseg_mq(struct gerb_net *net, int cw,
92 double delta_cp_x, double delta_cp_y);
94 static void
95 gerber_update_min_and_max(gerb_image_info_t *info, gdouble repeatX, gdouble repeatY,
96 gdouble x, gdouble y, gdouble apertureSizeX1,
97 gdouble apertureSizeX2,gdouble apertureSizeY1,
98 gdouble apertureSizeY2);
101 static void gerber_update_any_running_knockout_measurements(gerb_image_t *image);
103 static void gerber_calculate_final_justify_effects (gerb_image_t *image);
105 gboolean knockoutMeasure = FALSE;
106 gdouble knockoutLimitXmin, knockoutLimitYmin, knockoutLimitXmax,
107 knockoutLimitYmax;
108 gerb_layer_t *knockoutLayer = NULL;
110 #ifndef RENDER_USING_GDK
111 cairo_matrix_t currentMatrix;
112 #endif
114 gboolean
115 gerber_parse_file_segment (gint levelOfRecursion, gerb_image_t *image,
116 gerb_state_t *state, gerb_net_t *curr_net,
117 gerb_stats_t *stats, gerb_file_t *fd,
118 gchar *directoryPath) {
119 int read, coord, len;
120 double x_scale = 0.0, y_scale = 0.0;
121 double delta_cp_x = 0.0, delta_cp_y = 0.0;
122 double aperture_size;
123 double scale;
124 gboolean foundEOF = FALSE;
126 while ((read = gerb_fgetc(fd)) != EOF) {
127 /* figure out the scale, since we need to normalize
128 all dimensions to inches */
129 if (state->state->unit == MM)
130 scale = 25.4;
131 else
132 scale = 1.0;
133 switch ((char)(read & 0xff)) {
134 case 'G':
135 dprintf("... Found G code\n");
136 parse_G_code(fd, state, image);
137 break;
138 case 'D':
139 dprintf("... Found D code\n");
140 parse_D_code(fd, state, image);
141 break;
142 case 'M':
143 dprintf("... Found M code\n");
144 switch(parse_M_code(fd, image)) {
145 case 1 :
146 case 2 :
147 case 3 :
148 foundEOF = TRUE;
149 break;
150 default:
151 gerb_stats_add_error(stats->error_list,
153 "Unknown M code found.\n",
154 GRB_ERROR);
155 } /* switch(parse_M_code) */
156 break;
157 case 'X':
158 dprintf("... Found X code\n");
159 stats->X++;
160 coord = gerb_fgetint(fd, &len);
161 if (image->format && image->format->omit_zeros == TRAILING) {
163 switch ((image->format->x_int + image->format->x_dec) - len) {
164 case 5:
165 coord *= 10;
166 case 4:
167 coord *= 10;
168 case 3:
169 coord *= 10;
170 case 2:
171 coord *= 10;
172 case 1:
173 coord *= 10;
174 break;
175 default:
179 if (image->format && (image->format->coordinate==INCREMENTAL))
180 state->curr_x += coord;
181 else
182 state->curr_x = coord;
183 state->changed = 1;
184 break;
185 case 'Y':
186 dprintf("... Found Y code\n");
187 stats->Y++;
188 coord = gerb_fgetint(fd, &len);
189 if (image->format && image->format->omit_zeros == TRAILING) {
191 switch ((image->format->y_int + image->format->y_dec) - len) {
192 case 5:
193 coord *= 10;
194 case 4:
195 coord *= 10;
196 case 3:
197 coord *= 10;
198 case 2:
199 coord *= 10;
200 case 1:
201 coord *= 10;
202 break;
203 default:
207 if (image->format && (image->format->coordinate==INCREMENTAL))
208 state->curr_y += coord;
209 else
210 state->curr_y = coord;
211 state->changed = 1;
212 break;
213 case 'I':
214 dprintf("... Found I code\n");
215 stats->I++;
216 state->delta_cp_x = gerb_fgetint(fd, NULL);
217 state->changed = 1;
218 break;
219 case 'J':
220 dprintf("... Found J code\n");
221 stats->J++;
222 state->delta_cp_y = gerb_fgetint(fd, NULL);
223 state->changed = 1;
224 break;
225 case '%':
226 dprintf("... Found %% code\n");
227 parse_rs274x(levelOfRecursion, fd, image, state, curr_net, stats, directoryPath);
228 while (1) {
229 int c = gerb_fgetc(fd);
230 if(c == EOF || c == '%')
231 break;
233 break;
234 case '*':
235 dprintf("... Found * code\n");
236 stats->star++;
237 if (state->changed == 0) break;
238 state->changed = 0;
240 curr_net->next = (gerb_net_t *)g_malloc(sizeof(gerb_net_t));
241 if (curr_net->next == NULL)
242 GERB_FATAL_ERROR("malloc curr_net->next failed\n");
243 curr_net = curr_net->next;
244 memset((void *)curr_net, 0, sizeof(gerb_net_t));
245 curr_net->layer = state->layer;
246 curr_net->state = state->state;
248 * Scale to given coordinate format
249 * XXX only "omit leading zeros".
251 if (image && image->format ){
252 x_scale = pow(10.0, (double)image->format->x_dec);
253 y_scale = pow(10.0, (double)image->format->y_dec);
255 x_scale *= scale;
256 y_scale *= scale;
257 curr_net->start_x = (double)state->prev_x / x_scale;
258 curr_net->start_y = (double)state->prev_y / y_scale;
259 curr_net->stop_x = (double)state->curr_x / x_scale;
260 curr_net->stop_y = (double)state->curr_y / y_scale;
261 delta_cp_x = (double)state->delta_cp_x / x_scale;
262 delta_cp_y = (double)state->delta_cp_y / y_scale;
265 switch (state->interpolation) {
266 case CW_CIRCULAR :
267 curr_net->cirseg = (gerb_cirseg_t *)g_malloc(sizeof(gerb_cirseg_t));
268 if (curr_net->cirseg == NULL)
269 GERB_FATAL_ERROR("malloc curr_net->cirseg failed\n");
270 memset((void *)curr_net->cirseg, 0, sizeof(gerb_cirseg_t));
271 if (state->mq_on)
272 calc_cirseg_mq(curr_net, 1, delta_cp_x, delta_cp_y);
273 else
274 calc_cirseg_sq(curr_net, 1, delta_cp_x, delta_cp_y);
275 break;
276 case CCW_CIRCULAR :
277 curr_net->cirseg = (gerb_cirseg_t *)g_malloc(sizeof(gerb_cirseg_t));
278 if (curr_net->cirseg == NULL)
279 GERB_FATAL_ERROR("malloc curr_net->cirseg failed\n");
280 memset((void *)curr_net->cirseg, 0, sizeof(gerb_cirseg_t));
281 if (state->mq_on)
282 calc_cirseg_mq(curr_net, 0, delta_cp_x, delta_cp_y);
283 else
284 calc_cirseg_sq(curr_net, 0, delta_cp_x, delta_cp_y);
285 break;
286 case PAREA_START :
288 * To be able to get back and fill in number of polygon corners
290 state->parea_start_node = curr_net;
291 state->in_parea_fill = 1;
292 break;
293 case PAREA_END :
294 state->parea_start_node = NULL;
295 state->in_parea_fill = 0;
296 break;
297 default :
298 break;
299 } /* switch(state->interpolation) */
302 * Count number of points in Polygon Area
304 if (state->in_parea_fill && state->parea_start_node) {
306 * "...all lines drawn with D01 are considered edges of the
307 * polygon. D02 closes and fills the polygon."
308 * p.49 rs274xrevd_e.pdf
309 * D02 -> state->aperture_state == OFF
312 /* UPDATE: temporarily disabling, since I suspect this is a typo
313 in the manual...D02 shouldn't end the polygon. This code
314 was adding many spurious polygon starts and ends to the render
315 image, making polygon element handling very tough
316 if (state->aperture_state == OFF &&
317 state->interpolation != PAREA_START) {
318 curr_net->interpolation = PAREA_END;
320 curr_net->next = (gerb_net_t *)g_malloc(sizeof(gerb_net_t));
321 if (curr_net->next == NULL)
322 GERB_FATAL_ERROR("malloc curr_net->next failed\n");
323 curr_net = curr_net->next;
324 memset((void *)curr_net, 0, sizeof(gerb_net_t));
325 curr_net->layer = state->layer;
326 curr_net->state = state->state;
328 curr_net->interpolation = PAREA_START;
329 state->parea_start_node = curr_net;
330 curr_net->next = (gerb_net_t *)g_malloc(sizeof(gerb_net_t));
331 if (curr_net->next == NULL)
332 GERB_FATAL_ERROR("malloc curr_net->next failed\n");
333 curr_net = curr_net->next;
334 memset((void *)curr_net, 0, sizeof(gerb_net_t));
335 curr_net->layer = state->layer;
336 curr_net->state = state->state;
338 curr_net->start_x = (double)state->prev_x / x_scale;
339 curr_net->start_y = (double)state->prev_y / y_scale;
340 curr_net->stop_x = (double)state->curr_x / x_scale;
341 curr_net->stop_y = (double)state->curr_y / y_scale;
344 } /* if (state->in_parea_fill && state->parea_start_node) */
346 curr_net->interpolation = state->interpolation;
349 * Override circular interpolation if no center was given.
350 * This should be a safe hack, since a good file should always
351 * include I or J. And even if the radius is zero, the endpoint
352 * should be the same as the start point, creating no line
354 if (((state->interpolation == CW_CIRCULAR) ||
355 (state->interpolation == CCW_CIRCULAR)) &&
356 ((state->delta_cp_x == 0.0) && (state->delta_cp_y == 0.0)))
357 curr_net->interpolation = LINEARx1;
360 * If we detected the end of Polygon Area Fill we go back to
361 * the interpolation we had before that.
362 * Also if we detected any of the quadrant flags, since some
363 * gerbers don't reset the interpolation (EagleCad again).
365 if ((state->interpolation == PAREA_START) ||
366 (state->interpolation == PAREA_END))
367 state->interpolation = state->prev_interpolation;
370 * Save layer polarity and unit
372 curr_net->layer = state->layer;
374 state->delta_cp_x = 0.0;
375 state->delta_cp_y = 0.0;
376 curr_net->aperture = state->curr_aperture;
377 curr_net->aperture_state = state->aperture_state;
380 * For next round we save the current position as
381 * the previous position
383 state->prev_x = state->curr_x;
384 state->prev_y = state->curr_y;
387 * If we have an aperture defined at the moment we find
388 * min and max of image with compensation for mm.
390 if ((curr_net->aperture == 0) && !state->in_parea_fill)
391 break;
393 /* only update the min/max values if we are drawing */
394 if ((curr_net->aperture_state != OFF)){
395 double repeat_off_X = 0.0, repeat_off_Y = 0.0;
398 * If step_and_repeat (%SR%) is used, check min_x,max_y etc for
399 * the ends of the step_and_repeat lattice. This goes wrong in
400 * the case of negative dist_X or dist_Y, in which case we
401 * should compare against the startpoints of the lines, not
402 * the stoppoints, but that seems an uncommon case (and the
403 * error isn't very big any way).
405 repeat_off_X = (state->layer->stepAndRepeat.X - 1) *
406 state->layer->stepAndRepeat.dist_X;
407 repeat_off_Y = (state->layer->stepAndRepeat.Y - 1) *
408 state->layer->stepAndRepeat.dist_Y;
411 #ifndef RENDER_USING_GDK
412 cairo_matrix_init (&currentMatrix, 1, 0, 0, 1, 0, 0);
413 /* offset image */
414 cairo_matrix_translate (&currentMatrix, image->info->offsetA,
415 image->info->offsetB);
416 /* do image rotation */
417 cairo_matrix_rotate (&currentMatrix, image->info->imageRotation);
418 /* it's a new layer, so recalculate the new transformation
419 * matrix for it */
420 /* do any rotations */
421 cairo_matrix_rotate (&currentMatrix, state->layer->rotation);
423 /* calculate current layer and state transformation matrices */
424 /* apply scale factor */
425 cairo_matrix_scale (&currentMatrix, state->state->scaleA,
426 state->state->scaleB);
427 /* apply offset */
428 cairo_matrix_translate (&currentMatrix, state->state->offsetA,
429 state->state->offsetB);
430 /* apply mirror */
431 switch (state->state->mirrorState) {
432 case FLIPA:
433 cairo_matrix_scale (&currentMatrix, -1, 1);
434 break;
435 case FLIPB:
436 cairo_matrix_scale (&currentMatrix, 1, -1);
437 break;
438 case FLIPAB:
439 cairo_matrix_scale (&currentMatrix, -1, -1);
440 break;
441 default:
442 break;
444 /* finally, apply axis select */
445 if (state->state->axisSelect == SWAPAB) {
446 /* we do this by rotating 270 (counterclockwise, then
447 * mirroring the Y axis
449 cairo_matrix_rotate (&currentMatrix, 3 * M_PI / 2);
450 cairo_matrix_scale (&currentMatrix, 1, -1);
452 #endif
453 /* if it's a macro, step through all the primitive components
454 and calculate the true bounding box */
455 if ((image->aperture[curr_net->aperture] != NULL) &&
456 (image->aperture[curr_net->aperture]->type == MACRO)) {
457 gerb_simplified_amacro_t *ls = image->aperture[curr_net->aperture]->simplified;
459 while (ls != NULL) {
460 gdouble offsetx = 0, offsety = 0, widthx = 0, widthy = 0;
461 gboolean calculatedAlready = FALSE;
463 if (ls->type == MACRO_CIRCLE) {
464 offsetx=ls->parameter[CIRCLE_CENTER_X];
465 offsety=ls->parameter[CIRCLE_CENTER_Y];
466 widthx=widthy=ls->parameter[CIRCLE_DIAMETER];
467 } else if (ls->type == MACRO_OUTLINE) {
468 int pointCounter,numberOfPoints;
469 numberOfPoints = (int) ls->parameter[OUTLINE_NUMBER_OF_POINTS];
471 for (pointCounter = 0; pointCounter < numberOfPoints; pointCounter++) {
472 gerber_update_min_and_max (image->info, repeat_off_X, repeat_off_Y,
473 ls->parameter[pointCounter * 2 + OUTLINE_FIRST_X],
474 ls->parameter[pointCounter * 2 + OUTLINE_FIRST_Y],
475 0,0,0,0);
477 calculatedAlready = TRUE;
478 } else if (ls->type == MACRO_POLYGON) {
479 offsetx = ls->parameter[POLYGON_CENTER_X];
480 offsety = ls->parameter[POLYGON_CENTER_Y];
481 widthx = widthy = ls->parameter[POLYGON_DIAMETER];
482 } else if (ls->type == MACRO_MOIRE) {
483 offsetx = ls->parameter[MOIRE_CENTER_X];
484 offsety = ls->parameter[MOIRE_CENTER_Y];
485 widthx = widthy = ls->parameter[MOIRE_OUTSIDE_DIAMETER];
486 } else if (ls->type == MACRO_THERMAL) {
487 offsetx = ls->parameter[THERMAL_CENTER_X];
488 offsety = ls->parameter[THERMAL_CENTER_Y];
489 widthx = widthy = ls->parameter[THERMAL_OUTSIDE_DIAMETER];
490 } else if (ls->type == MACRO_LINE20) {
491 widthx = widthy = ls->parameter[LINE20_LINE_WIDTH];
492 gerber_update_min_and_max (image->info, repeat_off_X, repeat_off_Y,
493 ls->parameter[LINE20_START_X] + offsetx,
494 ls->parameter[LINE20_START_Y] + offsety,
495 widthx/2,widthx/2,widthy/2,widthy/2);
496 gerber_update_min_and_max (image->info, repeat_off_X, repeat_off_Y,
497 ls->parameter[LINE20_END_X] + offsetx,
498 ls->parameter[LINE20_END_Y] + offsety,
499 widthx/2,widthx/2,widthy/2,widthy/2);
500 calculatedAlready = TRUE;
501 } else if (ls->type == MACRO_LINE21) {
502 gdouble largestDimension = sqrt (ls->parameter[LINE21_WIDTH]/2 *
503 ls->parameter[LINE21_WIDTH]/2 + ls->parameter[LINE21_HEIGHT/2] *
504 ls->parameter[LINE21_HEIGHT]/2);
506 offsetx = ls->parameter[LINE21_CENTER_X];
507 offsety = ls->parameter[LINE21_CENTER_Y];
508 widthx = widthy=largestDimension;
509 } else if (ls->type == MACRO_LINE22) {
510 gdouble largestDimension = sqrt (ls->parameter[LINE22_WIDTH]/2 *
511 ls->parameter[LINE22_WIDTH]/2 + ls->parameter[LINE22_HEIGHT/2] *
512 ls->parameter[LINE22_HEIGHT]/2);
514 offsetx = ls->parameter[LINE22_LOWER_LEFT_X] +
515 ls->parameter[LINE22_WIDTH]/2;
516 offsety = ls->parameter[LINE22_LOWER_LEFT_Y] +
517 ls->parameter[LINE22_HEIGHT]/2;
518 widthx = widthy=largestDimension;
521 if (!calculatedAlready) {
522 gerber_update_min_and_max (image->info, repeat_off_X, repeat_off_Y,
523 curr_net->stop_x + offsetx,
524 curr_net->stop_y + offsety,
525 widthx/2,widthx/2,widthy/2,widthy/2);
527 ls = ls->next;
529 } else {
530 if (image->aperture[curr_net->aperture] != NULL) {
531 aperture_size = image->aperture[curr_net->aperture]->parameter[0];
532 } else {
533 /* this is usually for polygon fills, where the aperture width
534 if "zero" */
535 aperture_size = 0;
538 /* check both the start and stop of the aperture points against
539 a running min/max counter */
540 /* Note: only check start coordinate if this isn't a flash,
541 since the start point may be bogus if it is a flash */
542 if (curr_net->aperture_state != FLASH) {
543 gerber_update_min_and_max (image->info, repeat_off_X, repeat_off_Y,
544 curr_net->start_x, curr_net->start_y,
545 aperture_size/2,aperture_size/2,
546 aperture_size/2,aperture_size/2);
548 gerber_update_min_and_max (image->info, repeat_off_X, repeat_off_Y,
549 curr_net->stop_x, curr_net->stop_y,
550 aperture_size/2,aperture_size/2,
551 aperture_size/2,aperture_size/2);
554 break;
555 case 10 : /* White space */
556 case 13 :
557 case ' ' :
558 case '\t' :
559 case 0 :
560 break;
561 default:
562 stats->unknown++;
563 gerb_stats_add_error(stats->error_list,
565 g_strdup_printf("Found unknown character (whitespace?) [%d]%c\n",
566 read, read),
567 GRB_ERROR);
568 } /* switch((char) (read & 0xff)) */
570 return foundEOF;
574 /* ------------------------------------------------------------------ */
575 gerb_image_t *
576 parse_gerb(gerb_file_t *fd, gchar *directoryPath)
578 gerb_state_t *state = NULL;
579 gerb_image_t *image = NULL;
580 gerb_net_t *curr_net = NULL;
581 gerb_stats_t *stats;
582 gboolean foundEOF = FALSE;
584 /* added by t.motylewski@bfad.de
585 * many locales redefine "." as "," and so on,
586 * so sscanf and strtod has problems when
587 * reading files using %f format */
588 setlocale(LC_NUMERIC, "C" );
591 * Create new state. This is used locally to keep track
592 * of the photoplotter's state as the Gerber is read in.
594 state = (gerb_state_t *)g_malloc(sizeof(gerb_state_t));
595 if (state == NULL)
596 GERB_FATAL_ERROR("malloc state failed\n");
599 * Set some defaults
601 memset((void *)state, 0, sizeof(gerb_state_t));
604 * Create new image. This will be returned.
606 image = new_gerb_image(image, "RS274-X (Gerber) File");
607 if (image == NULL)
608 GERB_FATAL_ERROR("malloc image failed\n");
609 curr_net = image->netlist;
610 image->layertype = GERBER;
611 image->gerb_stats = gerb_stats_new();
612 if (image->gerb_stats == NULL)
613 GERB_FATAL_ERROR("malloc gerb_stats failed\n");
614 stats = (gerb_stats_t *) image->gerb_stats;
616 /* set active layer and netstate to point to first default one created */
617 state->layer = image->layers;
618 state->state = image->states;
619 curr_net->layer = state->layer;
620 curr_net->state = state->state;
623 * Start parsing
625 dprintf("In parse_gerb, starting to parse file...\n");
626 foundEOF = gerber_parse_file_segment (1, image, state, curr_net, stats,
627 fd, directoryPath);
629 if (!foundEOF) {
630 gerb_stats_add_error(stats->error_list,
632 "File is missing Gerber EOF code.\n",
633 GRB_ERROR);
635 g_free(state);
637 dprintf(" ... done parsing Gerber file\n");
638 gerber_update_any_running_knockout_measurements (image);
639 gerber_calculate_final_justify_effects(image);
641 return image;
642 } /* parse_gerb */
645 /* ------------------------------------------------------------------- */
647 * Checks for signs that this is a RS-274X file
648 * Returns TRUE if it is, FALSE if not.
650 gboolean
651 gerber_is_rs274x_p(gerb_file_t *fd, gboolean *returnFoundBinary)
653 char *buf;
654 int len = 0;
655 char *letter;
656 int i;
657 gboolean found_binary = FALSE;
658 gboolean found_ADD = FALSE;
659 gboolean found_D0 = FALSE;
660 gboolean found_D2 = FALSE;
661 gboolean found_M0 = FALSE;
662 gboolean found_M2 = FALSE;
663 gboolean found_star = FALSE;
664 gboolean found_X = FALSE;
665 gboolean found_Y = FALSE;
667 dprintf ("gerber_is_rs274x_p(%p, %p), fd->fd = %p\n", fd, returnFoundBinary, fd->fd);
668 buf = (char *) g_malloc(MAXL);
669 if (buf == NULL)
670 GERB_FATAL_ERROR("malloc buf failed while checking for rs274x.\n");
672 while (fgets(buf, MAXL, fd->fd) != NULL) {
673 dprintf ("buf = \"%s\"\n", buf);
674 len = strlen(buf);
676 /* First look through the file for indications of its type by
677 * checking that file is not binary (non-printing chars and white
678 * spaces)
680 for (i = 0; i < len; i++) {
681 if (!isprint((int) buf[i]) && (buf[i] != '\r') &&
682 (buf[i] != '\n') && (buf[i] != '\t')) {
683 found_binary = TRUE;
684 dprintf ("found_binary (%d)\n", buf[i]);
687 if (g_strstr_len(buf, len, "%ADD")) {
688 found_ADD = TRUE;
689 dprintf ("found_ADD\n");
691 if (g_strstr_len(buf, len, "D00")) {
692 found_D0 = TRUE;
693 dprintf ("found_D0\n");
695 if (g_strstr_len(buf, len, "D02")) {
696 found_D2 = TRUE;
697 dprintf ("found_D2\n");
699 if (g_strstr_len(buf, len, "M0")) {
700 found_M0 = TRUE;
701 dprintf ("found_M0\n");
703 if (g_strstr_len(buf, len, "M00")) {
704 found_M0 = TRUE;
705 dprintf ("found_M0\n");
707 if (g_strstr_len(buf, len, "M2")) {
708 found_M2 = TRUE;
709 dprintf ("found_M2\n");
711 if (g_strstr_len(buf, len, "M02")) {
712 found_M2 = TRUE;
713 dprintf ("found_M2\n");
715 if (g_strstr_len(buf, len, "*")) {
716 found_star = TRUE;
717 dprintf ("found_star\n");
719 /* look for X<number> or Y<number> */
720 if ((letter = g_strstr_len(buf, len, "X")) != NULL) {
721 if (isdigit((int) letter[1])) { /* grab char after X */
722 found_X = TRUE;
723 dprintf ("found_X\n");
726 if ((letter = g_strstr_len(buf, len, "Y")) != NULL) {
727 if (isdigit((int) letter[1])) { /* grab char after Y */
728 found_Y = TRUE;
729 dprintf ("found_Y\n");
733 rewind(fd->fd);
734 free(buf);
736 *returnFoundBinary = found_binary;
738 /* Now form logical expression determining if the file is RS-274X */
739 if ((found_D0 || found_D2 || found_M0 || found_M2) &&
740 found_ADD && found_star && (found_X || found_Y))
741 return TRUE;
744 return FALSE;
746 } /* gerber_is_rs274x */
749 /* ------------------------------------------------------------------- */
751 * Checks for signs that this is a RS-274D file
752 * Returns TRUE if it is, FALSE if not.
754 gboolean
755 gerber_is_rs274d_p(gerb_file_t *fd)
757 char *buf;
758 int len = 0;
759 char *letter;
760 int i;
761 gboolean found_binary = FALSE;
762 gboolean found_ADD = FALSE;
763 gboolean found_D0 = FALSE;
764 gboolean found_D2 = FALSE;
765 gboolean found_M0 = FALSE;
766 gboolean found_M2 = FALSE;
767 gboolean found_star = FALSE;
768 gboolean found_X = FALSE;
769 gboolean found_Y = FALSE;
771 buf = malloc(MAXL);
772 if (buf == NULL)
773 GERB_FATAL_ERROR("malloc buf failed while checking for rs274d.\n");
775 while (fgets(buf, MAXL, fd->fd) != NULL) {
776 len = strlen(buf);
778 /* First look through the file for indications of its type */
780 /* check that file is not binary (non-printing chars */
781 for (i = 0; i < len; i++) {
782 if (!isprint( (int) buf[i]) && (buf[i] != '\r') &&
783 (buf[i] != '\n') && (buf[i] != '\t')) {
784 found_binary = TRUE;
788 if (g_strstr_len(buf, len, "%ADD")) {
789 found_ADD = TRUE;
791 if (g_strstr_len(buf, len, "D00")) {
792 found_D0 = TRUE;
794 if (g_strstr_len(buf, len, "D02")) {
795 found_D2 = TRUE;
797 if (g_strstr_len(buf, len, "M0")) {
798 found_M0 = TRUE;
800 if (g_strstr_len(buf, len, "M00")) {
801 found_M0 = TRUE;
803 if (g_strstr_len(buf, len, "M02")) {
804 found_M2 = TRUE;
806 if (g_strstr_len(buf, len, "*")) {
807 found_star = TRUE;
809 /* look for X<number> or Y<number> */
810 if ((letter = g_strstr_len(buf, len, "X")) != NULL) {
811 /* grab char after X */
812 if (isdigit( (int) letter[1])) {
813 found_X = TRUE;
816 if ((letter = g_strstr_len(buf, len, "Y")) != NULL) {
817 /* grab char after Y */
818 if (isdigit( (int) letter[1])) {
819 found_Y = TRUE;
823 rewind(fd->fd);
824 free(buf);
826 /* Now form logical expression determining if the file is RS-274D */
827 if ((found_D0 || found_D2 || found_M0 || found_M2) &&
828 !found_ADD && found_star && (found_X || found_Y) &&
829 !found_binary)
830 return TRUE;
832 return FALSE;
834 } /* gerber_is_rs274d */
837 /* ------------------------------------------------------------------- */
838 static void
839 parse_G_code(gerb_file_t *fd, gerb_state_t *state, gerb_image_t *image)
841 int op_int;
842 gerb_format_t *format = image->format;
843 gerb_stats_t *stats = image->gerb_stats;
844 int c;
846 op_int=gerb_fgetint(fd, NULL);
848 switch(op_int) {
849 case 0: /* Move */
850 /* Is this doing anything really? */
851 stats->G0++;
852 break;
853 case 1: /* Linear Interpolation (1X scale) */
854 state->interpolation = LINEARx1;
855 stats->G1++;
856 break;
857 case 2: /* Clockwise Linear Interpolation */
858 state->interpolation = CW_CIRCULAR;
859 stats->G2++;
860 break;
861 case 3: /* Counter Clockwise Linear Interpolation */
862 state->interpolation = CCW_CIRCULAR;
863 stats->G3++;
864 break;
865 case 4: /* Ignore Data Block */
866 /* Don't do anything, just read 'til * */
867 c = gerb_fgetc(fd);
868 while ((c != EOF) && (c != '*')) {
869 c = gerb_fgetc(fd);
871 stats->G4++;
872 break;
873 case 10: /* Linear Interpolation (10X scale) */
874 state->interpolation = LINEARx10;
875 stats->G10++;
876 break;
877 case 11: /* Linear Interpolation (0.1X scale) */
878 state->interpolation = LINEARx01;
879 stats->G11++;
880 break;
881 case 12: /* Linear Interpolation (0.01X scale) */
882 state->interpolation = LINEARx001;
883 stats->G12++;
884 break;
885 case 36: /* Turn on Polygon Area Fill */
886 state->prev_interpolation = state->interpolation;
887 state->interpolation = PAREA_START;
888 state->changed = 1;
889 stats->G36++;
890 break;
891 case 37: /* Turn off Polygon Area Fill */
892 state->interpolation = PAREA_END;
893 state->changed = 1;
894 stats->G37++;
895 break;
896 case 54: /* Tool prepare */
897 /* XXX Maybe uneccesary??? */
898 if (gerb_fgetc(fd) == 'D') {
899 int a = gerb_fgetint(fd, NULL);
900 if ((a >= APERTURE_MIN) && (a <= APERTURE_MAX)) {
901 state->curr_aperture = a;
902 dprintf(" In parse_G_code, case 54, found D and adding 1 to no %d in D_list ...\n", a);
903 gerb_stats_increment_D_list_count(stats->D_code_list,
906 stats->error_list);
907 } else {
908 gerb_stats_add_error(stats->error_list,
910 g_strdup_printf("Found aperture out of bounds while parsing G code: %d\n", a),
911 GRB_ERROR);
913 } else {
914 gerb_stats_add_error(stats->error_list,
916 "Found unexpected code after G54\n",
917 GRB_ERROR);
918 /* Must insert error count here */
920 stats->G54++;
921 break;
922 case 55: /* Prepare for flash */
923 stats->G55++;
924 break;
925 case 70: /* Specify inches */
926 state->state = gerb_image_return_new_netstate (state->state);
927 state->state->unit = INCH;
928 stats->G70++;
929 break;
930 case 71: /* Specify millimeters */
931 state->state = gerb_image_return_new_netstate (state->state);
932 state->state->unit = MM;
933 stats->G71++;
934 break;
935 case 74: /* Disable 360 circular interpolation */
936 state->mq_on = 0;
937 stats->G74++;
938 break;
939 case 75: /* Enable 360 circular interpolation */
940 state->mq_on = 1;
941 stats->G75++;
942 break;
943 case 90: /* Specify absolut format */
944 if (format) format->coordinate = ABSOLUTE;
945 stats->G90++;
946 break;
947 case 91: /* Specify incremental format */
948 if (format) format->coordinate = INCREMENTAL;
949 stats->G91++;
950 break;
951 default:
952 gerb_stats_add_error(stats->error_list,
954 g_strdup_printf("Encountered unknown G code : G%d\n", op_int),
955 GRB_ERROR);
956 gerb_stats_add_error(stats->error_list,
958 g_strdup_printf("Ignorning unknown G code\n"),
959 WARNING);
961 stats->G_unknown++;
962 /* Enter error count here */
963 break;
966 return;
967 } /* parse_G_code */
970 /* ------------------------------------------------------------------ */
971 static void
972 parse_D_code(gerb_file_t *fd, gerb_state_t *state, gerb_image_t *image)
974 int a;
975 gerb_stats_t *stats = image->gerb_stats;
977 a = gerb_fgetint(fd, NULL);
978 dprintf(" In parse_D_code, found D number = %d ... \n", a);
979 switch(a) {
980 case 1 : /* Exposure on */
981 state->aperture_state = ON;
982 state->changed = 1;
983 stats->D1++;
984 break;
985 case 2 : /* Exposure off */
986 state->aperture_state = OFF;
987 state->changed = 1;
988 stats->D2++;
989 break;
990 case 3 : /* Flash aperture */
991 state->aperture_state = FLASH;
992 state->changed = 1;
993 stats->D3++;
994 break;
995 default: /* Aperture in use */
996 if ((a >= APERTURE_MIN) && (a <= APERTURE_MAX)) {
997 state->curr_aperture = a;
999 dprintf(" In parse_D_code, adding 1 to D_list ...\n");
1000 int retcode = gerb_stats_increment_D_list_count(stats->D_code_list,
1003 stats->error_list);
1004 if (retcode == -1) {
1005 gerb_stats_add_error(stats->error_list,
1007 g_strdup_printf("Found undefined D code: D%d\n", a),
1008 GRB_ERROR);
1009 stats->D_unknown++;
1011 } else {
1012 gerb_stats_add_error(stats->error_list,
1014 g_strdup_printf("Found aperture number out of bounds while parsing D code: %d\n", a),
1015 GRB_ERROR);
1016 stats->D_error++;
1018 state->changed = 0;
1019 break;
1022 return;
1023 } /* parse_D_code */
1026 /* ------------------------------------------------------------------ */
1027 static int
1028 parse_M_code(gerb_file_t *fd, gerb_image_t *image)
1030 int op_int;
1031 gerb_stats_t *stats = image->gerb_stats;
1033 op_int=gerb_fgetint(fd, NULL);
1035 switch (op_int) {
1036 case 0: /* Program stop */
1037 stats->M0++;
1038 return 1;
1039 case 1: /* Optional stop */
1040 stats->M1++;
1041 return 2;
1042 case 2: /* End of program */
1043 stats->M2++;
1044 return 3;
1045 default:
1046 gerb_stats_add_error(stats->error_list,
1048 g_strdup_printf("Encountered unknown M code : M%d\n", op_int),
1049 GRB_ERROR);
1050 gerb_stats_add_error(stats->error_list,
1052 g_strdup_printf("Ignorning unknown M code\n"),
1053 WARNING);
1054 stats->M_unknown++;
1056 return 0;
1057 } /* parse_M_code */
1060 /* ------------------------------------------------------------------ */
1061 static void
1062 parse_rs274x(gint levelOfRecursion, gerb_file_t *fd, gerb_image_t *image,
1063 gerb_state_t *state, gerb_net_t *curr_net, gerb_stats_t *stats,
1064 gchar *directoryPath)
1066 int op[2];
1067 char str[3];
1068 int tmp;
1069 gerb_aperture_t *a = NULL;
1070 amacro_t *tmp_amacro;
1071 int ano;
1072 gdouble scale = 1.0;
1074 if (state->state->unit == MM)
1075 scale = 25.4;
1077 op[0] = gerb_fgetc(fd);
1078 op[1] = gerb_fgetc(fd);
1080 if ((op[0] == EOF) || (op[1] == EOF))
1081 gerb_stats_add_error(stats->error_list,
1083 "Unexpected EOF found.\n",
1084 GRB_ERROR);
1086 switch (A2I(op[0], op[1])){
1089 * Directive parameters
1091 case A2I('A','S'): /* Axis Select */
1092 op[0] = gerb_fgetc(fd);
1093 op[1] = gerb_fgetc(fd);
1094 state->state = gerb_image_return_new_netstate (state->state);
1096 if ((op[0] == EOF) || (op[1] == EOF))
1097 gerb_stats_add_error(stats->error_list,
1099 "Unexpected EOF found.\n",
1100 GRB_ERROR);
1102 if (((op[0] == 'A') && (op[1] == 'Y')) ||
1103 ((op[0] == 'B') && (op[1] == 'X'))) {
1104 state->state->axisSelect = SWAPAB;
1105 } else {
1106 state->state->axisSelect = NOSELECT;
1109 op[0] = gerb_fgetc(fd);
1110 op[1] = gerb_fgetc(fd);
1112 if ((op[0] == EOF) || (op[1] == EOF))
1113 gerb_stats_add_error(stats->error_list,
1115 "Unexpected EOF found.\n",
1116 GRB_ERROR);
1118 if (((op[0] == 'A') && (op[1] == 'Y')) ||
1119 ((op[0] == 'B') && (op[1] == 'X'))) {
1120 state->state->axisSelect = SWAPAB;
1121 } else {
1122 state->state->axisSelect = NOSELECT;
1124 break;
1126 case A2I('F','S'): /* Format Statement */
1127 image->format = (gerb_format_t *)g_malloc(sizeof(gerb_format_t));
1128 if (image->format == NULL)
1129 GERB_FATAL_ERROR("Failed malloc for format\n");
1130 memset((void *)image->format, 0, sizeof(gerb_format_t));
1132 switch (gerb_fgetc(fd)) {
1133 case 'L':
1134 image->format->omit_zeros = LEADING;
1135 break;
1136 case 'T':
1137 image->format->omit_zeros = TRAILING;
1138 break;
1139 case 'D':
1140 image->format->omit_zeros = EXPLICIT;
1141 break;
1142 default:
1143 gerb_stats_add_error(stats->error_list,
1145 "EagleCad bug detected: Undefined handling of zeros in format code\n",
1146 GRB_ERROR);
1147 gerb_stats_add_error(stats->error_list,
1149 "Defaulting to omitting leading zeros.\n",
1150 WARNING);
1151 gerb_ungetc(fd);
1152 image->format->omit_zeros = LEADING;
1155 switch (gerb_fgetc(fd)) {
1156 case 'A':
1157 image->format->coordinate = ABSOLUTE;
1158 break;
1159 case 'I':
1160 image->format->coordinate = INCREMENTAL;
1161 break;
1162 default:
1163 gerb_stats_add_error(stats->error_list,
1165 "Invalid coordinate type defined in format code.\n",
1166 GRB_ERROR);
1167 gerb_stats_add_error(stats->error_list,
1169 "Defaulting to absolute.\n",
1170 WARNING);
1171 image->format->coordinate = ABSOLUTE;
1173 op[0] = gerb_fgetc(fd);
1174 while((op[0] != '*')&&(op[0] != EOF)) {
1175 switch (op[0]) {
1176 case 'N':
1177 op[0] = (char)gerb_fgetc(fd);
1178 image->format->lim_seqno = op[0] - '0';
1179 break;
1180 case 'G':
1181 op[0] = (char)gerb_fgetc(fd);
1182 image->format->lim_gf = op[0] - '0';
1183 break;
1184 case 'D':
1185 op[0] = (char)gerb_fgetc(fd);
1186 image->format->lim_pf = op[0] - '0';
1187 break;
1188 case 'M':
1189 op[0] = (char)gerb_fgetc(fd);
1190 image->format->lim_mf = op[0] - '0';
1191 break;
1192 case 'X' :
1193 op[0] = gerb_fgetc(fd);
1194 if ((op[0] < '0') || (op[0] > '6'))
1195 gerb_stats_add_error(stats->error_list,
1197 g_strdup_printf("Illegal format size : %c\n", (char)op[0]),
1198 GRB_ERROR);
1199 image->format->x_int = op[0] - '0';
1200 op[0] = gerb_fgetc(fd);
1201 if ((op[0] < '0') || (op[0] > '6'))
1202 gerb_stats_add_error(stats->error_list,
1204 g_strdup_printf("Illegal format size : %c\n", (char)op[0]),
1205 GRB_ERROR);
1206 image->format->x_dec = op[0] - '0';
1207 break;
1208 case 'Y':
1209 op[0] = gerb_fgetc(fd);
1210 if ((op[0] < '0') || (op[0] > '6'))
1211 gerb_stats_add_error(stats->error_list,
1213 g_strdup_printf("Illegal format size : %c\n", (char)op[0]),
1214 GRB_ERROR);
1215 image->format->y_int = op[0] - '0';
1216 op[0] = gerb_fgetc(fd);
1217 if ((op[0] < '0') || (op[0] > '6'))
1218 gerb_stats_add_error(stats->error_list,
1220 g_strdup_printf("Illegal format size : %c\n", (char)op[0]),
1221 GRB_ERROR);
1222 image->format->y_dec = op[0] - '0';
1223 break;
1224 default :
1225 gerb_stats_add_error(stats->error_list,
1227 g_strdup_printf("Invalid format statement [%c]\n", op[0]),
1228 GRB_ERROR);
1229 gerb_stats_add_error(stats->error_list,
1231 "Ignoring invalid format statement.\n",
1232 WARNING);
1234 op[0] = gerb_fgetc(fd);
1236 break;
1237 case A2I('M','I'): /* Mirror Image */
1238 op[0] = gerb_fgetc(fd);
1239 state->state = gerb_image_return_new_netstate (state->state);
1241 while ((op[0] != '*')&&(op[0] != EOF)) {
1242 gint readValue=0;
1243 switch (op[0]) {
1244 case 'A' :
1245 readValue = gerb_fgetint(fd, NULL);
1246 if (readValue == 1) {
1247 if (state->state->mirrorState == FLIPB)
1248 state->state->mirrorState=FLIPAB;
1249 else
1250 state->state->mirrorState=FLIPA;
1252 break;
1253 case 'B' :
1254 readValue = gerb_fgetint(fd, NULL);
1255 if (readValue == 1) {
1256 if (state->state->mirrorState == FLIPA)
1257 state->state->mirrorState=FLIPAB;
1258 else
1259 state->state->mirrorState=FLIPB;
1261 break;
1262 default :
1263 gerb_stats_add_error(stats->error_list,
1265 g_strdup_printf("Wrong character in mirror:%c\n", op[0]),
1266 GRB_ERROR);
1268 op[0] = gerb_fgetc(fd);
1270 break;
1271 case A2I('M','O'): /* Mode of Units */
1272 op[0] = gerb_fgetc(fd);
1273 op[1] = gerb_fgetc(fd);
1275 if ((op[0] == EOF) || (op[1] == EOF))
1276 gerb_stats_add_error(stats->error_list,
1278 "Unexpected EOF found.\n",
1279 GRB_ERROR);
1280 switch (A2I(op[0],op[1])) {
1281 case A2I('I','N'):
1282 state->state = gerb_image_return_new_netstate (state->state);
1283 state->state->unit = INCH;
1284 break;
1285 case A2I('M','M'):
1286 state->state = gerb_image_return_new_netstate (state->state);
1287 state->state->unit = MM;
1288 break;
1289 default:
1290 gerb_stats_add_error(stats->error_list,
1292 g_strdup_printf("Illegal unit:%c%c\n", op[0], op[1]),
1293 GRB_ERROR);
1295 break;
1296 case A2I('O','F'): /* Offset */
1297 op[0] = gerb_fgetc(fd);
1299 while ((op[0] != '*')&&(op[0] != EOF)) {
1300 switch (op[0]) {
1301 case 'A' :
1302 state->state->offsetA = gerb_fgetdouble(fd) / scale;
1303 break;
1304 case 'B' :
1305 state->state->offsetB = gerb_fgetdouble(fd) / scale;
1306 break;
1307 default :
1308 gerb_stats_add_error(stats->error_list,
1310 g_strdup_printf("Wrong character in offset:%c\n", op[0]),
1311 GRB_ERROR);
1313 op[0] = gerb_fgetc(fd);
1315 break;
1316 case A2I('I','F'): /* Include file */
1318 gchar *includeFilename = gerb_fgetstring(fd, '*');
1320 if (includeFilename) {
1321 gchar *fullPath;
1322 if (!g_path_is_absolute(includeFilename)) {
1323 fullPath = g_build_filename (directoryPath, includeFilename, NULL);
1324 } else {
1325 fullPath = g_strdup (includeFilename);
1327 if (levelOfRecursion < 10) {
1328 gerb_file_t *includefd = NULL;
1330 includefd = gerb_fopen(fullPath);
1331 if (includefd) {
1332 gerber_parse_file_segment (levelOfRecursion + 1, image, state, curr_net, stats, includefd, directoryPath);
1333 gerb_fclose(includefd);
1334 } else {
1335 gerb_stats_add_error(stats->error_list, -1,
1336 g_strdup_printf("Included file cannot be found:%s\n",fullPath), GRB_ERROR);
1338 g_free (fullPath);
1339 } else {
1340 gerb_stats_add_error(stats->error_list, -1,
1341 g_strdup_printf("Parser encountered more than 10 levels of include file recursion, which is not allowed by the RS-274X spec\n"), GRB_ERROR);
1346 break;
1347 case A2I('I','O'): /* Image offset */
1348 op[0] = gerb_fgetc(fd);
1350 while ((op[0] != '*')&&(op[0] != EOF)) {
1351 switch (op[0]) {
1352 case 'A' :
1353 image->info->offsetA = gerb_fgetdouble(fd) / scale;
1354 break;
1355 case 'B' :
1356 image->info->offsetB = gerb_fgetdouble(fd) / scale;
1357 break;
1358 default :
1359 gerb_stats_add_error(stats->error_list,
1361 g_strdup_printf("Wrong character in offset:%c\n", op[0]),
1362 GRB_ERROR);
1364 op[0] = gerb_fgetc(fd);
1366 break;
1367 case A2I('S','F'): /* Scale Factor */
1368 if (gerb_fgetc(fd) == 'A')
1369 state->state->scaleA = gerb_fgetdouble(fd);
1370 else
1371 gerb_ungetc(fd);
1372 if (gerb_fgetc(fd) == 'B')
1373 state->state->scaleB = gerb_fgetdouble(fd);
1374 else
1375 gerb_ungetc(fd);
1376 break;
1377 case A2I('I','C'): /* Input Code */
1378 /* Thanks to Stephen Adam for providing this information. As he writes:
1379 * btw, here's a logic puzzle for you. If you need to
1380 * read the gerber file to see how it's encoded, then
1381 * how can you read it?
1383 op[0] = gerb_fgetc(fd);
1384 op[1] = gerb_fgetc(fd);
1386 if ((op[0] == EOF) || (op[1] == EOF))
1387 gerb_stats_add_error(stats->error_list,
1389 "Unexpected EOF found.\n",
1390 GRB_ERROR);
1391 switch (A2I(op[0],op[1])) {
1392 case A2I('A','S'):
1393 image->info->encoding = ASCII;
1394 break;
1395 case A2I('E','B'):
1396 image->info->encoding = EBCDIC;
1397 break;
1398 case A2I('B','C'):
1399 image->info->encoding = BCD;
1400 break;
1401 case A2I('I','S'):
1402 image->info->encoding = ISO_ASCII;
1403 break;
1404 case A2I('E','I'):
1405 image->info->encoding = EIA;
1406 break;
1407 default:
1408 gerb_stats_add_error(stats->error_list,
1410 g_strdup_printf("Unknown input code (IC): %c%c\n", op[0], op[1]),
1411 GRB_ERROR);
1413 break;
1415 /* Image parameters */
1416 case A2I('I','J'): /* Image Justify */
1417 op[0] = gerb_fgetc(fd);
1418 image->info->imageJustifyTypeA = LOWERLEFT;
1419 image->info->imageJustifyTypeB = LOWERLEFT;
1420 image->info->imageJustifyOffsetA = 0.0;
1421 image->info->imageJustifyOffsetB = 0.0;
1422 while ((op[0] != '*')&&(op[0] != EOF)) {
1423 switch (op[0]) {
1424 case 'A' :
1425 op[0] = gerb_fgetc(fd);
1426 if (op[0] == 'C') {
1427 image->info->imageJustifyTypeA = CENTERJUSTIFY;
1428 } else if (op[0] == 'L') {
1429 image->info->imageJustifyTypeA = LOWERLEFT;
1430 } else {
1431 gerb_ungetc (fd);
1432 image->info->imageJustifyOffsetA = gerb_fgetdouble(fd) / scale;
1434 break;
1435 case 'B' :
1436 op[0] = gerb_fgetc(fd);
1437 if (op[0] == 'C') {
1438 image->info->imageJustifyTypeB = CENTERJUSTIFY;
1439 } else if (op[0] == 'L') {
1440 image->info->imageJustifyTypeB = LOWERLEFT;
1441 } else {
1442 gerb_ungetc (fd);
1443 image->info->imageJustifyOffsetB = gerb_fgetdouble(fd) / scale;
1445 break;
1446 default :
1447 gerb_stats_add_error(stats->error_list,
1449 g_strdup_printf("Wrong character in image justify:%c\n", op[0]),
1450 GRB_ERROR);
1452 op[0] = gerb_fgetc(fd);
1454 break;
1455 case A2I('I','N'): /* Image Name */
1456 image->info->name = gerb_fgetstring(fd, '*');
1457 break;
1458 case A2I('I','P'): /* Image Polarity */
1460 for (ano = 0; ano < 3; ano++) {
1461 op[0] = gerb_fgetc(fd);
1462 if (op[0] == EOF)
1463 gerb_stats_add_error(stats->error_list,
1465 "Unexpected EOF while reading image polarity (IP)\n",
1466 GRB_ERROR);
1467 str[ano] = (char)op[0];
1470 if (strncmp(str, "POS", 3) == 0)
1471 image->info->polarity = POSITIVE;
1472 else if (strncmp(str, "NEG", 3) == 0)
1473 image->info->polarity = NEGATIVE;
1474 else
1475 gerb_stats_add_error(stats->error_list,
1477 g_strdup_printf("Unknown polarity : %c%c%c\n", str[0], str[1], str[2]),
1478 GRB_ERROR);
1479 break;
1480 case A2I('I','R'): /* Image Rotation */
1481 tmp = gerb_fgetint(fd, NULL);
1482 if (tmp == 90)
1483 image->info->imageRotation = M_PI / 2.0;
1484 else if (tmp == 180)
1485 image->info->imageRotation = M_PI;
1486 else if (tmp == 270)
1487 image->info->imageRotation = 3.0 * M_PI / 2.0;
1488 else
1489 gerb_stats_add_error(stats->error_list,
1491 g_strdup_printf("Image rotation must be 0, 90, 180 or 270 (is actually %d)\n", tmp),
1492 GRB_ERROR);
1493 break;
1494 case A2I('P','F'): /* Plotter Film */
1495 image->info->plotterFilm = gerb_fgetstring(fd, '*');
1496 break;
1498 /* Aperture parameters */
1499 case A2I('A','D'): /* Aperture Description */
1500 a = (gerb_aperture_t *)g_malloc(sizeof(gerb_aperture_t));
1501 if (a == NULL)
1502 GERB_FATAL_ERROR("malloc aperture failed\n");
1503 memset((void *)a, 0, sizeof(gerb_aperture_t));
1504 ano = parse_aperture_definition(fd, a, image, scale);
1505 if ((ano >= APERTURE_MIN) && (ano <= APERTURE_MAX)) {
1506 a->unit = state->state->unit;
1507 image->aperture[ano] = a;
1508 dprintf(" In parse_rs274x, adding new aperture to aperture list ...\n");
1509 gerb_stats_add_aperture(stats->aperture_list,
1510 -1, ano,
1511 a->type,
1512 a->parameter);
1513 gerb_stats_add_to_D_list(stats->D_code_list,
1514 ano);
1515 } else {
1516 gerb_stats_add_error(stats->error_list,
1518 g_strdup_printf("Aperture number out of bounds : %d\n", ano),
1519 GRB_ERROR);
1521 /* Add aperture info to stats->aperture_list here */
1523 break;
1524 case A2I('A','M'): /* Aperture Macro */
1525 tmp_amacro = image->amacro;
1526 image->amacro = parse_aperture_macro(fd);
1527 if (image->amacro) {
1528 image->amacro->next = tmp_amacro;
1529 #ifdef AMACRO_DEBUG
1530 print_program(image->amacro);
1531 #endif
1532 } else {
1533 gerb_stats_add_error(stats->error_list,
1535 "Failed to parse aperture macro\n",
1536 GRB_ERROR);
1538 break;
1539 /* Layer */
1540 case A2I('L','N'): /* Layer Name */
1541 state->layer = gerb_image_return_new_layer (state->layer);
1542 state->layer->name = gerb_fgetstring(fd, '*');
1543 break;
1544 case A2I('L','P'): /* Layer Polarity */
1545 state->layer = gerb_image_return_new_layer (state->layer);
1546 switch (gerb_fgetc(fd)) {
1547 case 'D': /* Dark Polarity (default) */
1548 state->layer->polarity = DARK;
1549 break;
1550 case 'C': /* Clear Polarity */
1551 state->layer->polarity = CLEAR;
1552 break;
1553 default:
1554 gerb_stats_add_error(stats->error_list,
1556 g_strdup_printf("Unknown Layer Polarity: %c\n", op[0]),
1557 GRB_ERROR);
1559 break;
1560 case A2I('K','O'): /* Knock Out */
1561 state->layer = gerb_image_return_new_layer (state->layer);
1562 gerber_update_any_running_knockout_measurements (image);
1563 /* reset any previous knockout measurements */
1564 knockoutMeasure = FALSE;
1565 op[0] = gerb_fgetc(fd);
1566 if (op[0] == '*') { /* Disable previous SR parameters */
1567 state->layer->knockout.type = NOKNOCKOUT;
1568 break;
1569 } else if (op[0] == 'C') {
1570 state->layer->knockout.polarity = CLEAR;
1571 } else if (op[0] == 'D') {
1572 state->layer->knockout.polarity = DARK;
1573 } else {
1574 gerb_stats_add_error(stats->error_list,
1576 "Knockout must supply a polarity (C, D, or *)\n",
1577 GRB_ERROR);
1579 state->layer->knockout.lowerLeftX = 0.0;
1580 state->layer->knockout.lowerLeftY = 0.0;
1581 state->layer->knockout.width = 0.0;
1582 state->layer->knockout.height = 0.0;
1583 state->layer->knockout.border = 0.0;
1584 state->layer->knockout.firstInstance = TRUE;
1585 op[0] = gerb_fgetc(fd);
1586 while ((op[0] != '*')&&(op[0] != EOF)) {
1587 switch (op[0]) {
1588 case 'X':
1589 state->layer->knockout.type = FIXEDKNOCK;
1590 state->layer->knockout.lowerLeftX = gerb_fgetdouble(fd) / scale;
1591 break;
1592 case 'Y':
1593 state->layer->knockout.type = FIXEDKNOCK;
1594 state->layer->knockout.lowerLeftY = gerb_fgetdouble(fd) / scale;
1595 break;
1596 case 'I':
1597 state->layer->knockout.type = FIXEDKNOCK;
1598 state->layer->knockout.width = gerb_fgetdouble(fd) / scale;
1599 break;
1600 case 'J':
1601 state->layer->knockout.type = FIXEDKNOCK;
1602 state->layer->knockout.height = gerb_fgetdouble(fd) / scale;
1603 break;
1604 case 'K':
1605 state->layer->knockout.type = BORDER;
1606 state->layer->knockout.border = gerb_fgetdouble(fd) / scale;
1607 /* this is a bordered knockout, so we need to start measuring the
1608 size of a square bordering all future components */
1609 knockoutMeasure = TRUE;
1610 knockoutLimitXmin = HUGE_VAL;
1611 knockoutLimitYmin = HUGE_VAL;
1612 knockoutLimitXmax = -HUGE_VAL;
1613 knockoutLimitYmax = -HUGE_VAL;
1614 knockoutLayer = state->layer;
1615 break;
1616 default:
1617 gerb_stats_add_error(stats->error_list,
1619 "Unknown variable in knockout",
1620 GRB_ERROR);
1622 op[0] = gerb_fgetc(fd);
1624 break;
1625 case A2I('S','R'): /* Step and Repeat */
1626 /* start by generating a new layer (duplicating previous layer settings */
1627 state->layer = gerb_image_return_new_layer (state->layer);
1628 op[0] = gerb_fgetc(fd);
1629 if (op[0] == '*') { /* Disable previous SR parameters */
1630 state->layer->stepAndRepeat.X = 1;
1631 state->layer->stepAndRepeat.Y = 1;
1632 state->layer->stepAndRepeat.dist_X = 0.0;
1633 state->layer->stepAndRepeat.dist_Y = 0.0;
1634 break;
1636 while ((op[0] != '*')&&(op[0] != EOF)) {
1637 switch (op[0]) {
1638 case 'X':
1639 state->layer->stepAndRepeat.X = gerb_fgetint(fd, NULL);
1640 break;
1641 case 'Y':
1642 state->layer->stepAndRepeat.Y = gerb_fgetint(fd, NULL);
1643 break;
1644 case 'I':
1645 state->layer->stepAndRepeat.dist_X = gerb_fgetdouble(fd) / scale;
1646 break;
1647 case 'J':
1648 state->layer->stepAndRepeat.dist_Y = gerb_fgetdouble(fd) / scale;
1649 break;
1650 default:
1651 gerb_stats_add_error(stats->error_list,
1653 "Step-and-repeat parameter error\n",
1654 GRB_ERROR);
1658 * Repeating 0 times in any direction would disable the whole plot, and
1659 * is probably not intended. At least one other tool (viewmate) seems
1660 * to interpret 0-time repeating as repeating just once too.
1662 if(state->layer->stepAndRepeat.X == 0)
1663 state->layer->stepAndRepeat.X = 1;
1664 if(state->layer->stepAndRepeat.Y == 0)
1665 state->layer->stepAndRepeat.Y = 1;
1667 op[0] = gerb_fgetc(fd);
1669 break;
1670 /* is this an actual RS274X command?? It isn't explainined in the spec... */
1671 case A2I('R','O'):
1672 state->layer = gerb_image_return_new_layer (state->layer);
1674 state->layer->rotation = gerb_fgetdouble(fd) * M_PI / 180;
1675 op[0] = gerb_fgetc(fd);
1676 if (op[0] != '*') {
1677 gerb_stats_add_error(stats->error_list,
1679 "Error in layer rotation comman\n",
1680 GRB_ERROR);
1682 break;
1683 default:
1684 gerb_stats_add_error(stats->error_list,
1686 g_strdup_printf("Unknown RS-274X extension found %%%c%c%%\n", op[0], op[1]),
1687 GRB_ERROR);
1690 return;
1691 } /* parse_rs274x */
1695 * Stack declarations and operations to be used by the simple engine that
1696 * executes the parsed aperture macros.
1698 typedef struct {
1699 double *stack;
1700 int sp;
1701 } macro_stack_t;
1704 static macro_stack_t *
1705 new_stack(unsigned int stack_size)
1707 macro_stack_t *s;
1709 s = (macro_stack_t *)malloc(sizeof(macro_stack_t));
1710 if (!s) {
1711 free(s);
1712 return NULL;
1714 memset(s, 0, sizeof(macro_stack_t));
1716 s->stack = (double *)malloc(sizeof(double) * stack_size);
1717 if (!s->stack) {
1718 free(s->stack);
1719 return NULL;
1722 memset(s->stack, 0, sizeof(double) * stack_size);
1723 s->sp = 0;
1725 return s;
1726 } /* new_stack */
1729 static void
1730 free_stack(macro_stack_t *s)
1732 if (s && s->stack)
1733 free(s->stack);
1735 if (s)
1736 free(s);
1738 return;
1739 } /* free_stack */
1742 static void
1743 push(macro_stack_t *s, double val)
1745 s->stack[s->sp++] = val;
1746 return;
1747 } /* push */
1750 static int
1751 pop(macro_stack_t *s, double *value)
1753 /* Check if we try to pop an empty stack */
1754 if (s->sp == 0) {
1755 return -1;
1758 *value = s->stack[--s->sp];
1759 return 0;
1760 } /* pop */
1763 /* ------------------------------------------------------------------ */
1764 static int
1765 simplify_aperture_macro(gerb_aperture_t *aperture, gdouble scale)
1767 const int extra_stack_size = 10;
1768 macro_stack_t *s;
1769 instruction_t *ip;
1770 int handled = 1, nuf_parameters = 0, i, j, clearOperatorUsed = FALSE;
1771 double *lp; /* Local copy of parameters */
1772 double tmp[2] = {0.0, 0.0};
1773 enum aperture_t type = APERTURE_NONE;
1774 gerb_simplified_amacro_t *sam;
1776 if (aperture == NULL)
1777 GERB_FATAL_ERROR("aperture NULL in simplify aperture macro\n");
1779 if (aperture->amacro == NULL)
1780 GERB_FATAL_ERROR("aperture->amacro NULL in simplify aperture macro\n");
1782 /* Allocate stack for VM */
1783 s = new_stack(aperture->amacro->nuf_push + extra_stack_size);
1784 if (s == NULL)
1785 GERB_FATAL_ERROR("malloc stack failed\n");
1787 /* Make a copy of the parameter list that we can rewrite if necessary */
1788 lp = (double *)malloc(sizeof(double) * APERTURE_PARAMETERS_MAX);
1789 if (lp == NULL)
1790 GERB_FATAL_ERROR("malloc local parameter storage failed\n");
1792 memcpy(lp, aperture->parameter, sizeof(double) * APERTURE_PARAMETERS_MAX);
1794 for(ip = aperture->amacro->program; ip != NULL; ip = ip->next) {
1795 switch(ip->opcode) {
1796 case NOP:
1797 break;
1798 case PUSH :
1799 push(s, ip->data.fval);
1800 break;
1801 case PPUSH :
1802 push(s, lp[ip->data.ival - 1]);
1803 break;
1804 case PPOP:
1805 if (pop(s, &tmp[0]) < 0)
1806 GERB_FATAL_ERROR("Tried to pop an empty stack");
1807 lp[ip->data.ival - 1] = tmp[0];
1808 break;
1809 case ADD :
1810 if (pop(s, &tmp[0]) < 0)
1811 GERB_FATAL_ERROR("Tried to pop an empty stack");
1812 if (pop(s, &tmp[1]) < 0)
1813 GERB_FATAL_ERROR("Tried to pop an empty stack");
1814 push(s, tmp[1] + tmp[0]);
1815 break;
1816 case SUB :
1817 if (pop(s, &tmp[0]) < 0)
1818 GERB_FATAL_ERROR("Tried to pop an empty stack");
1819 if (pop(s, &tmp[1]) < 0)
1820 GERB_FATAL_ERROR("Tried to pop an empty stack");
1821 push(s, tmp[1] - tmp[0]);
1822 break;
1823 case MUL :
1824 if (pop(s, &tmp[0]) < 0)
1825 GERB_FATAL_ERROR("Tried to pop an empty stack");
1826 if (pop(s, &tmp[1]) < 0)
1827 GERB_FATAL_ERROR("Tried to pop an empty stack");
1828 push(s, tmp[1] * tmp[0]);
1829 break;
1830 case DIV :
1831 if (pop(s, &tmp[0]) < 0)
1832 GERB_FATAL_ERROR("Tried to pop an empty stack");
1833 if (pop(s, &tmp[1]) < 0)
1834 GERB_FATAL_ERROR("Tried to pop an empty stack");
1835 push(s, tmp[1] / tmp[0]);
1836 break;
1837 case PRIM :
1839 * This handles the exposure thing in the aperture macro
1840 * The exposure is always the first element on stack independent
1841 * of aperture macro.
1843 switch(ip->data.ival) {
1844 case 1:
1845 dprintf(" Aperture macro circle [1] (");
1846 type = MACRO_CIRCLE;
1847 nuf_parameters = 4;
1848 break;
1849 case 3:
1850 break;
1851 case 4 :
1852 dprintf(" Aperture macro outline [4] (");
1853 type = MACRO_OUTLINE;
1855 * Number of parameters are:
1856 * - number of points defined in entry 1 of the stack +
1857 * start point. Times two since it is both X and Y.
1858 * - Then three more; exposure, nuf points and rotation.
1860 nuf_parameters = ((int)s->stack[1] + 1) * 2 + 3;
1861 break;
1862 case 5 :
1863 dprintf(" Aperture macro polygon [5] (");
1864 type = MACRO_POLYGON;
1865 nuf_parameters = 6;
1866 break;
1867 case 6 :
1868 dprintf(" Aperture macro moiré [6] (");
1869 type = MACRO_MOIRE;
1870 nuf_parameters = 9;
1871 break;
1872 case 7 :
1873 dprintf(" Aperture macro thermal [7] (");
1874 type = MACRO_THERMAL;
1875 nuf_parameters = 6;
1876 break;
1877 case 2 :
1878 case 20 :
1879 dprintf(" Aperture macro line 20/2 (");
1880 type = MACRO_LINE20;
1881 nuf_parameters = 7;
1882 break;
1883 case 21 :
1884 dprintf(" Aperture macro line 21 (");
1885 type = MACRO_LINE21;
1886 nuf_parameters = 6;
1887 break;
1888 case 22 :
1889 dprintf(" Aperture macro line 22 (");
1890 type = MACRO_LINE22;
1891 nuf_parameters = 6;
1892 break;
1893 default :
1894 handled = 0;
1897 if (type != APERTURE_NONE) {
1898 if (nuf_parameters > APERTURE_PARAMETERS_MAX) {
1899 GERB_COMPILE_ERROR("Number of parameters to aperture macro are more than gerbv is able to store\n");
1903 * Create struct for simplified aperture macro and
1904 * start filling in the blanks.
1906 sam = (gerb_simplified_amacro_t *)malloc(sizeof(gerb_simplified_amacro_t));
1907 if (sam == NULL)
1908 GERB_FATAL_ERROR("Failed to malloc simplified aperture macro\n");
1909 sam->type = type;
1910 sam->next = NULL;
1911 memset(sam->parameter, 0,
1912 sizeof(double) * APERTURE_PARAMETERS_MAX);
1913 memcpy(sam->parameter, s->stack,
1914 sizeof(double) * nuf_parameters);
1916 /* convert any mm values to inches */
1917 switch (type) {
1918 case MACRO_CIRCLE:
1919 if (fabs(sam->parameter[0]) < 0.001)
1920 clearOperatorUsed = TRUE;
1921 sam->parameter[1]/=scale;
1922 sam->parameter[2]/=scale;
1923 sam->parameter[3]/=scale;
1924 break;
1925 case MACRO_OUTLINE:
1926 if (fabs(sam->parameter[0]) < 0.001)
1927 clearOperatorUsed = TRUE;
1928 for (j=2; j<nuf_parameters-1; j++){
1929 sam->parameter[j]/=scale;
1931 break;
1932 case MACRO_POLYGON:
1933 if (fabs(sam->parameter[0]) < 0.001)
1934 clearOperatorUsed = TRUE;
1935 sam->parameter[2]/=scale;
1936 sam->parameter[3]/=scale;
1937 sam->parameter[4]/=scale;
1938 break;
1939 case MACRO_MOIRE:
1940 sam->parameter[0]/=scale;
1941 sam->parameter[1]/=scale;
1942 sam->parameter[2]/=scale;
1943 sam->parameter[3]/=scale;
1944 sam->parameter[4]/=scale;
1945 sam->parameter[6]/=scale;
1946 sam->parameter[7]/=scale;
1947 break;
1948 case MACRO_THERMAL:
1949 sam->parameter[0]/=scale;
1950 sam->parameter[1]/=scale;
1951 sam->parameter[2]/=scale;
1952 sam->parameter[3]/=scale;
1953 sam->parameter[4]/=scale;
1954 break;
1955 case MACRO_LINE20:
1956 if (fabs(sam->parameter[0]) < 0.001)
1957 clearOperatorUsed = TRUE;
1958 sam->parameter[1]/=scale;
1959 sam->parameter[2]/=scale;
1960 sam->parameter[3]/=scale;
1961 sam->parameter[4]/=scale;
1962 sam->parameter[5]/=scale;
1963 break;
1964 case MACRO_LINE21:
1965 case MACRO_LINE22:
1966 if (fabs(sam->parameter[0]) < 0.001)
1967 clearOperatorUsed = TRUE;
1968 sam->parameter[1]/=scale;
1969 sam->parameter[2]/=scale;
1970 sam->parameter[3]/=scale;
1971 sam->parameter[4]/=scale;
1972 break;
1973 default:
1974 break;
1977 * Add this simplified aperture macro to the end of the list
1978 * of simplified aperture macros. If first entry, put it
1979 * in the top.
1981 if (aperture->simplified == NULL) {
1982 aperture->simplified = sam;
1983 } else {
1984 gerb_simplified_amacro_t *tmp_sam;
1985 tmp_sam = aperture->simplified;
1986 while (tmp_sam->next != NULL) {
1987 tmp_sam = tmp_sam->next;
1989 tmp_sam->next = sam;
1992 #ifdef DEBUG
1993 for (i = 0; i < nuf_parameters; i++) {
1994 dprintf("%f, ", s->stack[i]);
1996 #endif /* DEBUG */
1997 dprintf(")\n");
2001 * Here we reset the stack pointer. It's not general correct
2002 * correct to do this, but since I know how the compiler works
2003 * I can do this. The correct way to do this should be to
2004 * subtract number of used elements in each primitive operation.
2006 s->sp = 0;
2007 break;
2008 default :
2009 break;
2012 free_stack(s);
2014 /* store a flag to let the renderer know if it should expect any "clear"
2015 primatives */
2016 aperture->parameter[0]= (gdouble) clearOperatorUsed;
2017 return handled;
2018 } /* simplify_aperture_macro */
2021 /* ------------------------------------------------------------------ */
2022 static int
2023 parse_aperture_definition(gerb_file_t *fd, gerb_aperture_t *aperture,
2024 gerb_image_t *image, gdouble scale)
2026 int ano, i;
2027 char *ad;
2028 char *token;
2029 amacro_t *curr_amacro;
2030 amacro_t *amacro = image->amacro;
2031 gerb_stats_t *stats = image->gerb_stats;
2032 gdouble tempHolder;
2034 if (gerb_fgetc(fd) != 'D') {
2035 gerb_stats_add_error(stats->error_list,
2037 g_strdup_printf("Found AD code with no following 'D'.\n"),
2038 GRB_ERROR);
2039 return -1;
2043 * Get aperture no
2045 ano = gerb_fgetint(fd, NULL);
2048 * Read in the whole aperture defintion and tokenize it
2050 ad = gerb_fgetstring(fd, '*');
2051 token = strtok(ad, ",");
2053 if (strlen(token) == 1) {
2054 switch (token[0]) {
2055 case 'C':
2056 aperture->type = CIRCLE;
2057 break;
2058 case 'R' :
2059 aperture->type = RECTANGLE;
2060 break;
2061 case 'O' :
2062 aperture->type = OVAL;
2063 break;
2064 case 'P' :
2065 aperture->type = POLYGON;
2066 break;
2068 /* Here a should a T be defined, but I don't know what it represents */
2069 } else {
2070 aperture->type = MACRO;
2072 * In aperture definition, point to the aperture macro
2073 * used in the defintion
2075 curr_amacro = amacro;
2076 while (curr_amacro) {
2077 if ((strlen(curr_amacro->name) == strlen(token)) &&
2078 (strcmp(curr_amacro->name, token) == 0)) {
2079 aperture->amacro = curr_amacro;
2080 break;
2082 curr_amacro = curr_amacro->next;
2087 * Parse all parameters
2089 for (token = strtok(NULL, "X"), i = 0; token != NULL;
2090 token = strtok(NULL, "X"), i++) {
2091 if (i == APERTURE_PARAMETERS_MAX) {
2092 gerb_stats_add_error(stats->error_list,
2094 g_strdup_printf("Maximum number of allowed parameters exceeded in aperture %d\n", ano),
2095 GRB_ERROR);
2096 break;
2098 errno = 0;
2100 tempHolder = strtod(token, NULL);
2101 /* convert any MM values to inches */
2102 /* don't scale polygon angles or side numbers, or macro parmaeters */
2103 if (!(((aperture->type == POLYGON) && ((i==1) || (i==2)))||
2104 (aperture->type == MACRO))) {
2105 tempHolder /= scale;
2108 aperture->parameter[i] = tempHolder;
2109 if (errno) {
2110 gerb_stats_add_error(stats->error_list,
2112 g_strdup_printf("Failed to read all parameters exceeded in aperture %d\n", ano),
2113 WARNING);
2114 aperture->parameter[i] = 0.0;
2118 aperture->nuf_parameters = i;
2120 gerb_ungetc(fd);
2122 if (aperture->type == MACRO) {
2123 dprintf("Simplifying aperture %d using aperture macro \"%s\"\n", ano,
2124 aperture->amacro->name);
2125 simplify_aperture_macro(aperture, scale);
2126 dprintf("Done simplifying\n");
2129 g_free(ad);
2131 return ano;
2132 } /* parse_aperture_definition */
2135 /* ------------------------------------------------------------------ */
2136 static void
2137 calc_cirseg_sq(struct gerb_net *net, int cw,
2138 double delta_cp_x, double delta_cp_y)
2140 double d1x, d1y, d2x, d2y;
2141 double alfa, beta;
2142 int quadrant = 0;
2146 * Quadrant detection (based on ccw, converted below if cw)
2147 * Y ^
2148 * /!\
2150 * ---->X
2152 if (net->start_x > net->stop_x)
2153 /* 1st and 2nd quadrant */
2154 if (net->start_y < net->stop_y)
2155 quadrant = 1;
2156 else
2157 quadrant = 2;
2158 else
2159 /* 3rd and 4th quadrant */
2160 if (net->start_y > net->stop_y)
2161 quadrant = 3;
2162 else
2163 quadrant = 4;
2166 * If clockwise, rotate quadrant
2168 if (cw) {
2169 switch (quadrant) {
2170 case 1 :
2171 quadrant = 3;
2172 break;
2173 case 2 :
2174 quadrant = 4;
2175 break;
2176 case 3 :
2177 quadrant = 1;
2178 break;
2179 case 4 :
2180 quadrant = 2;
2181 break;
2182 default :
2183 GERB_COMPILE_ERROR("Unknow quadrant value while converting to cw\n");
2188 * Calculate arc center point
2190 switch (quadrant) {
2191 case 1 :
2192 net->cirseg->cp_x = net->start_x - delta_cp_x;
2193 net->cirseg->cp_y = net->start_y - delta_cp_y;
2194 break;
2195 case 2 :
2196 net->cirseg->cp_x = net->start_x + delta_cp_x;
2197 net->cirseg->cp_y = net->start_y - delta_cp_y;
2198 break;
2199 case 3 :
2200 net->cirseg->cp_x = net->start_x + delta_cp_x;
2201 net->cirseg->cp_y = net->start_y + delta_cp_y;
2202 break;
2203 case 4 :
2204 net->cirseg->cp_x = net->start_x - delta_cp_x;
2205 net->cirseg->cp_y = net->start_y + delta_cp_y;
2206 break;
2207 default :
2208 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant);
2212 * Some good values
2214 d1x = fabs(net->start_x - net->cirseg->cp_x);
2215 d1y = fabs(net->start_y - net->cirseg->cp_y);
2216 d2x = fabs(net->stop_x - net->cirseg->cp_x);
2217 d2y = fabs(net->stop_y - net->cirseg->cp_y);
2219 alfa = atan2(d1y, d1x);
2220 beta = atan2(d2y, d2x);
2223 * Avoid divide by zero when sin(0) = 0 and cos(90) = 0
2225 net->cirseg->width = alfa < beta ?
2226 2 * (d1x / cos(alfa)) : 2 * (d2x / cos(beta));
2227 net->cirseg->height = alfa > beta ?
2228 2 * (d1y / sin(alfa)) : 2 * (d2y / sin(beta));
2230 if (alfa < 0.000001 && beta < 0.000001) {
2231 net->cirseg->height = 0;
2234 #define RAD2DEG(a) (a * 180 / M_PI)
2236 switch (quadrant) {
2237 case 1 :
2238 net->cirseg->angle1 = RAD2DEG(alfa);
2239 net->cirseg->angle2 = RAD2DEG(beta);
2240 break;
2241 case 2 :
2242 net->cirseg->angle1 = 180.0 - RAD2DEG(alfa);
2243 net->cirseg->angle2 = 180.0 - RAD2DEG(beta);
2244 break;
2245 case 3 :
2246 net->cirseg->angle1 = 180.0 + RAD2DEG(alfa);
2247 net->cirseg->angle2 = 180.0 + RAD2DEG(beta);
2248 break;
2249 case 4 :
2250 net->cirseg->angle1 = 360.0 - RAD2DEG(alfa);
2251 net->cirseg->angle2 = 360.0 - RAD2DEG(beta);
2252 break;
2253 default :
2254 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant);
2257 if (net->cirseg->width < 0.0)
2258 GERB_COMPILE_WARNING("Negative width [%f] in quadrant %d [%f][%f]\n",
2259 net->cirseg->width, quadrant, alfa, beta);
2261 if (net->cirseg->height < 0.0)
2262 GERB_COMPILE_WARNING("Negative height [%f] in quadrant %d [%f][%f]\n",
2263 net->cirseg->height, quadrant, RAD2DEG(alfa), RAD2DEG(beta));
2265 return;
2267 } /* calc_cirseg_sq */
2270 /* ------------------------------------------------------------------ */
2271 static void
2272 calc_cirseg_mq(struct gerb_net *net, int cw,
2273 double delta_cp_x, double delta_cp_y)
2275 double d1x, d1y, d2x, d2y;
2276 double alfa, beta;
2278 net->cirseg->cp_x = net->start_x + delta_cp_x;
2279 net->cirseg->cp_y = net->start_y + delta_cp_y;
2282 * Some good values
2284 d1x = net->start_x - net->cirseg->cp_x;
2285 d1y = net->start_y - net->cirseg->cp_y;
2286 d2x = net->stop_x - net->cirseg->cp_x;
2287 d2y = net->stop_y - net->cirseg->cp_y;
2289 alfa = atan2(d1y, d1x);
2290 beta = atan2(d2y, d2x);
2292 net->cirseg->width = sqrt(delta_cp_x*delta_cp_x + delta_cp_y*delta_cp_y);
2293 net->cirseg->width *= 2.0;
2294 net->cirseg->height = net->cirseg->width;
2296 net->cirseg->angle1 = RAD2DEG(alfa);
2297 net->cirseg->angle2 = RAD2DEG(beta);
2300 * Make sure it's always positive angles
2302 if (net->cirseg->angle1 < 0.0) {
2303 net->cirseg->angle1 += 360.0;
2304 net->cirseg->angle2 += 360.0;
2307 if (net->cirseg->angle2 < 0.0)
2308 net->cirseg->angle2 += 360.0;
2310 if(net->cirseg->angle2 == 0.0)
2311 net->cirseg->angle2 = 360.0;
2314 * This is a sanity check for angles after the nature of atan2.
2315 * If cw we must make sure angle1-angle2 are always positive,
2316 * If ccw we must make sure angle2-angle1 are always negative.
2317 * We should really return one angle and the difference as GTK
2318 * uses them. But what the heck, it works for me.
2320 if (cw) {
2321 if (net->cirseg->angle1 <= net->cirseg->angle2)
2322 net->cirseg->angle2 -= 360.0;
2323 } else {
2324 if (net->cirseg->angle1 >= net->cirseg->angle2)
2325 net->cirseg->angle2 += 360.0;
2328 return;
2329 } /* calc_cirseg_mq */
2332 static void
2333 gerber_update_any_running_knockout_measurements (gerb_image_t *image)
2335 if (knockoutMeasure) {
2336 knockoutLayer->knockout.lowerLeftX = knockoutLimitXmin;
2337 knockoutLayer->knockout.lowerLeftY = knockoutLimitYmin;
2338 knockoutLayer->knockout.width = knockoutLimitXmax - knockoutLimitXmin;
2339 knockoutLayer->knockout.height = knockoutLimitYmax - knockoutLimitYmin;
2340 knockoutMeasure = FALSE;
2345 static void
2346 gerber_calculate_final_justify_effects(gerb_image_t *image)
2348 gdouble translateA = 0.0, translateB = 0.0;
2350 if (image->info->imageJustifyTypeA != NOJUSTIFY) {
2351 if (image->info->imageJustifyTypeA == CENTERJUSTIFY)
2352 translateA = (image->info->max_x - image->info->min_x) / 2.0;
2353 else
2354 translateA = -image->info->min_x;
2356 if (image->info->imageJustifyTypeB != NOJUSTIFY) {
2357 if (image->info->imageJustifyTypeB == CENTERJUSTIFY)
2358 translateB = (image->info->max_y - image->info->min_y) / 2.0;
2359 else
2360 translateB = -image->info->min_y;
2363 /* update the min/max values so the autoscale function can correctly
2364 centered a justified image */
2365 image->info->min_x += translateA+ image->info->imageJustifyOffsetA;
2366 image->info->max_x += translateA+ image->info->imageJustifyOffsetA;
2367 image->info->min_y += translateB+ image->info->imageJustifyOffsetB;
2368 image->info->max_y += translateB+ image->info->imageJustifyOffsetB;
2370 /* store the absolute offset for the justify so we can quickly offset
2371 the rendered picture during drawing */
2372 image->info->imageJustifyOffsetActualA = translateA +
2373 image->info->imageJustifyOffsetA;
2374 image->info->imageJustifyOffsetActualB = translateB +
2375 image->info->imageJustifyOffsetB;
2376 } /* gerber_calculate_final_justify_effects */
2379 static void
2380 gerber_update_min_and_max(gerb_image_info_t *info, gdouble repeatX, gdouble repeatY,
2381 gdouble x, gdouble y, gdouble apertureSizeX1,
2382 gdouble apertureSizeX2,gdouble apertureSizeY1,
2383 gdouble apertureSizeY2)
2385 gdouble ourX1 = x - apertureSizeX1, ourY1 = y - apertureSizeY1;
2386 gdouble ourX2 = x + apertureSizeX2, ourY2 = y + apertureSizeY2;
2388 if (repeatX > 0)
2389 ourX2 += repeatX;
2390 if (repeatY > 0)
2391 ourY2 += repeatY;
2393 #ifndef RENDER_USING_GDK
2394 /* transform the point to the final rendered position, accounting
2395 for any scaling, offsets, mirroring, etc */
2396 /* NOTE: we need to already add/subtract in the aperture size since
2397 the final rendering may be scaled */
2398 cairo_matrix_transform_point (&currentMatrix, &ourX1, &ourY1);
2399 cairo_matrix_transform_point (&currentMatrix, &ourX2, &ourY2);
2400 #endif
2402 /* check both points against the min/max, since depending on the rotation,
2403 mirroring, etc, either point could possibly be a min or max */
2404 if(info->min_x > ourX1)
2405 info->min_x = ourX1;
2406 if(info->min_x > ourX2)
2407 info->min_x = ourX2;
2408 if(info->max_x < ourX1)
2409 info->max_x = ourX1;
2410 if(info->max_x < ourX2)
2411 info->max_x = ourX2;
2412 if(info->min_y > ourY1)
2413 info->min_y = ourY1;
2414 if(info->min_y > ourY2)
2415 info->min_y = ourY2;
2416 if(info->max_y < ourY1)
2417 info->max_y = ourY1;
2418 if(info->max_y < ourY2)
2419 info->max_y = ourY2;
2421 if (knockoutMeasure) {
2422 if(knockoutLimitXmin > ourX1)
2423 knockoutLimitXmin = ourX1;
2424 if(knockoutLimitXmin > ourX2)
2425 knockoutLimitXmin = ourX2;
2426 if(knockoutLimitXmax < ourX1)
2427 knockoutLimitXmax = ourX1;
2428 if(knockoutLimitXmax < ourX2)
2429 knockoutLimitXmax = ourX2;
2430 if(knockoutLimitYmin > ourY1)
2431 knockoutLimitYmin = ourY1;
2432 if(knockoutLimitYmin > ourY2)
2433 knockoutLimitYmin = ourY2;
2434 if(knockoutLimitYmax < ourY1)
2435 knockoutLimitYmax = ourY1;
2436 if(knockoutLimitYmax < ourY2)
2437 knockoutLimitYmax = ourY2;
2439 } /* gerber_update_min_and_max */