Removed two potential segfaults when running RS274D
[geda-gerbv/spe.git] / src / gerber.c
blob02f46f5c3f99ef53948c5242538227dd4a71e05a
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>
29 #include "gerber.h"
30 #include "gerb_error.h"
32 #define NOT_IMPL(fd, s) do { \
33 GERB_MESSAGE("Not Implemented:%s\n", s); \
34 while (gerb_fgetc(fd) != (int)'*'); \
35 } while(0)
38 #define A2I(a,b) (((a & 0xff) << 8) + (b & 0xff))
40 typedef struct gerb_state {
41 enum unit_t unit;
42 int curr_x;
43 int curr_y;
44 int prev_x;
45 int prev_y;
46 int delta_cp_x;
47 int delta_cp_y;
48 int curr_aperture;
49 int changed;
50 enum polarity_t layer_polarity;
51 enum aperture_state_t aperture_state;
52 enum interpolation_t interpolation;
53 enum interpolation_t prev_interpolation;
54 gerb_net_t *parea_start_node;
55 char *curr_layername;
56 int in_parea_fill;
57 int mq_on;
58 } gerb_state_t;
61 /* Local function prototypes */
62 static void parse_G_code(gerb_file_t *fd, gerb_state_t *state,
63 gerb_format_t *format);
64 static void parse_D_code(gerb_file_t *fd, gerb_state_t *state);
65 static int parse_M_code(gerb_file_t *fd);
66 static void parse_rs274x(gerb_file_t *fd, gerb_image_t *image,
67 gerb_state_t *state);
68 static int parse_aperture_definition(gerb_file_t *fd,
69 gerb_aperture_t *aperture,
70 amacro_t *amacro);
71 static void calc_cirseg_sq(struct gerb_net *net, int cw,
72 double delta_cp_x, double delta_cp_y);
73 static void calc_cirseg_mq(struct gerb_net *net, int cw,
74 double delta_cp_x, double delta_cp_y);
75 static gerb_net_t *gen_circle_segments(gerb_net_t *curr_net,
76 int cw, int *nuf_pcorners);
78 gerb_image_t *
79 parse_gerb(gerb_file_t *fd)
81 gerb_state_t *state = NULL;
82 gerb_image_t *image = NULL;
83 gerb_net_t *curr_net = NULL;
84 int read, coord, len;
85 double x_scale = 0.0, y_scale = 0.0;
86 double delta_cp_x = 0.0, delta_cp_y = 0.0;
87 double aperture_size;
88 double scale;
90 state = (gerb_state_t *)malloc(sizeof(gerb_state_t));
91 if (state == NULL)
92 GERB_FATAL_ERROR("malloc state failed\n");
95 * Set some defaults
97 memset((void *)state, 0, sizeof(gerb_state_t));
98 state->layer_polarity = DARK;
101 * "Inches are assumed if units are not specified"
102 * rs274xrevd_e.pdf, p. 39
104 state->unit = INCH;
107 * Create new image
109 image = new_gerb_image(image);
110 if (image == NULL)
111 GERB_FATAL_ERROR("malloc image failed\n");
112 curr_net = image->netlist;
115 * Start parsing
117 while ((read = gerb_fgetc(fd)) != EOF) {
118 switch ((char)(read & 0xff)) {
119 case 'G':
120 parse_G_code(fd, state, image->format);
121 break;
122 case 'D':
123 parse_D_code(fd, state);
124 break;
125 case 'M':
126 switch(parse_M_code(fd)) {
127 case 1 :
128 case 2 :
129 case 3 :
130 free(state);
131 return image;
132 break;
133 default:
134 GERB_FATAL_ERROR("Strange M code found.\n");
136 break;
137 case 'X':
138 coord = gerb_fgetint(fd, &len);
139 if (image->format && image->format->omit_zeros == TRAILING) {
141 switch ((image->format->x_int + image->format->x_dec) - len) {
142 case 5:
143 coord *= 10;
144 case 4:
145 coord *= 10;
146 case 3:
147 coord *= 10;
148 case 2:
149 coord *= 10;
150 case 1:
151 coord *= 10;
152 break;
153 default:
157 if (image->format && (image->format->coordinate==INCREMENTAL))
158 state->curr_x += coord;
159 else
160 state->curr_x = coord;
161 state->changed = 1;
162 break;
163 case 'Y':
164 coord = gerb_fgetint(fd, &len);
165 if (image->format && image->format->omit_zeros == TRAILING) {
167 switch ((image->format->y_int + image->format->y_dec) - len) {
168 case 5:
169 coord *= 10;
170 case 4:
171 coord *= 10;
172 case 3:
173 coord *= 10;
174 case 2:
175 coord *= 10;
176 case 1:
177 coord *= 10;
178 break;
179 default:
183 if (image->format && (image->format->coordinate==INCREMENTAL))
184 state->curr_y += coord;
185 else
186 state->curr_y = coord;
187 state->changed = 1;
188 break;
189 case 'I':
190 state->delta_cp_x = gerb_fgetint(fd, NULL);
191 state->changed = 1;
192 break;
193 case 'J':
194 state->delta_cp_y = gerb_fgetint(fd, NULL);
195 state->changed = 1;
196 break;
197 case '%':
198 parse_rs274x(fd, image, state);
199 while (gerb_fgetc(fd) != '%');
200 break;
201 case '*':
202 if (state->changed == 0) break;
203 state->changed = 0;
205 curr_net->next = (gerb_net_t *)malloc(sizeof(gerb_net_t));
206 curr_net = curr_net->next;
207 memset((void *)curr_net, 0, sizeof(gerb_net_t));
210 * Scale to given coordinate format
211 * XXX only "omit leading zeros".
213 if (image && image->format ){
214 x_scale = pow(10.0, (double)image->format->x_dec);
215 y_scale = pow(10.0, (double)image->format->y_dec);
218 curr_net->start_x = (double)state->prev_x / x_scale;
219 curr_net->start_y = (double)state->prev_y / y_scale;
220 curr_net->stop_x = (double)state->curr_x / x_scale;
221 curr_net->stop_y = (double)state->curr_y / y_scale;
222 delta_cp_x = (double)state->delta_cp_x / x_scale;
223 delta_cp_y = (double)state->delta_cp_y / y_scale;
226 switch (state->interpolation) {
227 case CW_CIRCULAR :
228 curr_net->cirseg = (gerb_cirseg_t *)malloc(sizeof(gerb_cirseg_t));
229 memset((void *)curr_net->cirseg, 0, sizeof(gerb_cirseg_t));
230 if (state->mq_on)
231 calc_cirseg_mq(curr_net, 1, delta_cp_x, delta_cp_y);
232 else
233 calc_cirseg_sq(curr_net, 1, delta_cp_x, delta_cp_y);
234 break;
235 case CCW_CIRCULAR :
236 curr_net->cirseg = (gerb_cirseg_t *)malloc(sizeof(gerb_cirseg_t));
237 memset((void *)curr_net->cirseg, 0, sizeof(gerb_cirseg_t));
238 if (state->mq_on)
239 calc_cirseg_mq(curr_net, 0, delta_cp_x, delta_cp_y);
240 else
241 calc_cirseg_sq(curr_net, 0, delta_cp_x, delta_cp_y);
242 break;
243 case PAREA_START :
245 * To be able to get back and fill in number of polygon corners
247 state->parea_start_node = curr_net;
248 state->in_parea_fill = 1;
249 break;
250 case PAREA_END :
251 state->parea_start_node = NULL;
252 state->in_parea_fill = 0;
253 break;
254 default :
255 break;
259 * Count number of points in Polygon Area
261 if (state->in_parea_fill && state->parea_start_node) {
262 if (state->aperture_state == OFF) {
264 * aperture state off, end current polygon and start a new one
266 curr_net->interpolation = PAREA_END;
267 curr_net->next = (gerb_net_t *)malloc(sizeof(gerb_net_t));
268 curr_net = curr_net->next;
269 memset((void *)curr_net, 0, sizeof(gerb_net_t));
271 curr_net->interpolation = PAREA_START;
272 state->parea_start_node = curr_net;
273 curr_net->next = (gerb_net_t *)malloc(sizeof(gerb_net_t));
274 curr_net = curr_net->next;
275 memset((void *)curr_net, 0, sizeof(gerb_net_t));
277 curr_net->start_x = (double)state->prev_x / x_scale;
278 curr_net->start_y = (double)state->prev_y / y_scale;
279 curr_net->stop_x = (double)state->curr_x / x_scale;
280 curr_net->stop_y = (double)state->curr_y / y_scale;
284 * if this outline is circular, approximate it with short lines
286 if (curr_net->cirseg) {
287 curr_net->interpolation = state->interpolation;
288 curr_net->layer_polarity = state->layer_polarity;
289 curr_net->unit = state->unit;
290 curr_net = gen_circle_segments(curr_net, state->interpolation == CW_CIRCULAR, &(state->parea_start_node->nuf_pcorners));
293 state->parea_start_node->nuf_pcorners++;
296 curr_net->interpolation = state->interpolation;
299 * If we detected the end of Polygon Area Fill we go back to
300 * the interpolation we had before that.
301 * Also if we detected any of the quadrant flags, since some
302 * gerbers don't reset the interpolation (EagleCad again).
304 if ((state->interpolation == PAREA_START) ||
305 (state->interpolation == PAREA_END))
306 state->interpolation = state->prev_interpolation;
309 * Save layer polarity and unit
311 curr_net->layer_polarity = state->layer_polarity;
312 curr_net->unit = state->unit;
314 state->delta_cp_x = 0.0;
315 state->delta_cp_y = 0.0;
316 curr_net->aperture = state->curr_aperture;
317 curr_net->aperture_state = state->aperture_state;
320 * Make sure we don't hit any undefined aperture
321 * In macros the first parameter could be basically anything
323 if ((curr_net->aperture != 0) &&
324 (image->aperture[curr_net->aperture] != NULL) &&
325 (image->aperture[curr_net->aperture]->type != MACRO))
326 aperture_size = image->aperture[curr_net->aperture]->parameter[0];
327 else
328 aperture_size = 0.0;
331 * Find min and max of image with compensation for mm.
333 if (curr_net->unit == MM)
334 scale = 25.4;
335 else
336 scale = 1.0;
337 if (image->info->min_x > curr_net->stop_x)
338 image->info->min_x = (curr_net->stop_x - aperture_size) / scale;
339 if (image->info->min_y > curr_net->stop_y)
340 image->info->min_y = (curr_net->stop_y - aperture_size) / scale;
341 if (image->info->max_x < curr_net->stop_x)
342 image->info->max_x = (curr_net->stop_x + aperture_size) / scale;
343 if (image->info->max_y < curr_net->stop_y)
344 image->info->max_y = (curr_net->stop_y + aperture_size) / scale;
346 state->prev_x = state->curr_x;
347 state->prev_y = state->curr_y;
349 break;
350 case 10 : /* White space */
351 case 13 :
352 case ' ' :
353 case '\t' :
354 break;
355 default:
356 GERB_COMPILE_ERROR("Found unknown character (whitespace?) %c[%d]\n", read, read);
360 GERB_COMPILE_ERROR("File is missing gerber End-Of-File\n");
362 return image;
363 } /* parse_gerb */
366 static void
367 parse_G_code(gerb_file_t *fd, gerb_state_t *state, gerb_format_t *format)
369 int op_int;
371 op_int=gerb_fgetint(fd, NULL);
373 switch(op_int) {
374 case 0: /* Move */
375 /* Is this doing anything really? */
376 break;
377 case 1: /* Linear Interpolation (1X scale) */
378 state->interpolation = LINEARx1;
379 break;
380 case 2: /* Clockwise Linear Interpolation */
381 state->interpolation = CW_CIRCULAR;
382 break;
383 case 3: /* Counter Clockwise Linear Interpolation */
384 state->interpolation = CCW_CIRCULAR;
385 break;
386 case 4: /* Ignore Data Block */
387 /* Don't do anything, just read 'til * */
388 while (gerb_fgetc(fd) != '*');
389 break;
390 case 10: /* Linear Interpolation (10X scale) */
391 state->interpolation = LINEARx10;
392 break;
393 case 11: /* Linear Interpolation (0.1X scale) */
394 state->interpolation = LINEARx01;
395 break;
396 case 12: /* Linear Interpolation (0.01X scale) */
397 state->interpolation = LINEARx001;
398 break;
399 case 36: /* Turn on Polygon Area Fill */
400 state->prev_interpolation = state->interpolation;
401 state->interpolation = PAREA_START;
402 state->changed = 1;
403 break;
404 case 37: /* Turn off Polygon Area Fill */
405 state->interpolation = PAREA_END;
406 state->changed = 1;
407 break;
408 case 54: /* Tool prepare */
409 /* XXX Maybe uneccesary??? */
410 if (gerb_fgetc(fd) == 'D')
411 state->curr_aperture = gerb_fgetint(fd, NULL);
412 else
413 GERB_COMPILE_WARNING("Strange code after G54\n");
414 break;
415 case 55: /* Prepare for flash */
416 break;
417 case 70: /* Specify inches */
418 state->unit = INCH;
419 break;
420 case 71: /* Specify millimeters */
421 state->unit = MM;
422 break;
423 case 74: /* Disable 360 circular interpolation */
424 state->mq_on = 0;
425 break;
426 case 75: /* Enable 360 circular interpolation */
427 state->mq_on = 1;
428 break;
429 case 90: /* Specify absolut format */
430 if (format) format->coordinate = ABSOLUTE;
431 break;
432 case 91: /* Specify incremental format */
433 if (format) format->coordinate = INCREMENTAL;
434 break;
435 default:
436 GERB_COMPILE_ERROR("Strange/unhandled G code : %d\n", op_int);
439 return;
440 } /* parse_G_code */
443 static void
444 parse_D_code(gerb_file_t *fd, gerb_state_t *state)
446 int a;
448 a = gerb_fgetint(fd, NULL);
449 switch(a) {
450 case 1 : /* Exposure on */
451 state->aperture_state = ON;
452 state->changed = 1;
453 break;
454 case 2 : /* Exposure off */
455 state->aperture_state = OFF;
456 state->changed = 1;
457 break;
458 case 3 : /* Flash aperture */
459 state->aperture_state = FLASH;
460 state->changed = 1;
461 break;
462 default: /* Aperture in use */
463 if ((a >= APERTURE_MIN) && (a <= APERTURE_MAX))
464 state->curr_aperture = a;
465 else
466 GERB_COMPILE_ERROR("Aperture out of bounds:%d\n", a);
467 state->changed = 0;
470 return;
471 } /* parse_D_code */
474 static int
475 parse_M_code(gerb_file_t *fd)
477 int op_int;
479 op_int=gerb_fgetint(fd, NULL);
481 switch (op_int) {
482 case 0: /* Program stop */
483 return 1;
484 case 1: /* Optional stop */
485 return 2;
486 case 2: /* End of program */
487 return 3;
488 default:
489 GERB_COMPILE_ERROR("Strange M code [%d]\n", op_int);
491 return 0;
492 } /* parse_M_code */
495 static void
496 parse_rs274x(gerb_file_t *fd, gerb_image_t *image, gerb_state_t *state)
498 int op[2];
499 char str[3];
500 int tmp;
501 gerb_aperture_t *a = NULL;
502 amacro_t *tmp_amacro;
503 int ano;
505 op[0] = gerb_fgetc(fd);
506 op[1] = gerb_fgetc(fd);
508 if ((op[0] == EOF) || (op[1] == EOF))
509 GERB_COMPILE_ERROR("Unexpected EOF found.\n");
511 switch (A2I(op[0], op[1])){
513 /* Directive parameters */
514 case A2I('A','S'): /* Axis Select */
515 op[0] = gerb_fgetc(fd);
516 op[1] = gerb_fgetc(fd);
518 if ((op[0] == EOF) || (op[1] == EOF))
519 GERB_COMPILE_ERROR("Unexpected EOF found.\n");
521 if (((op[0] == 'A') && (op[1] == 'Y')) ||
522 ((op[0] == 'B') && (op[1] == 'X'))) {
523 NOT_IMPL(fd, "%MI with reversed axis not supported%");
524 break;
527 op[0] = gerb_fgetc(fd);
528 op[1] = gerb_fgetc(fd);
530 if ((op[0] == EOF) || (op[1] == EOF))
531 GERB_COMPILE_ERROR("Unexpected EOF found.\n");
533 if (((op[0] == 'A') && (op[1] == 'Y')) ||
534 ((op[0] == 'B') && (op[1] == 'X'))) {
535 NOT_IMPL(fd, "%MI with reversed axis not supported%");
536 break;
538 break;
539 case A2I('F','S'): /* Format Statement */
540 image->format = (gerb_format_t *)malloc(sizeof(gerb_format_t));
541 if (image->format == NULL)
542 GERB_FATAL_ERROR("Failed malloc for format\n");
543 memset((void *)image->format, 0, sizeof(gerb_format_t));
545 switch (gerb_fgetc(fd)) {
546 case 'L':
547 image->format->omit_zeros = LEADING;
548 break;
549 case 'T':
550 image->format->omit_zeros = TRAILING;
551 break;
552 case 'D':
553 image->format->omit_zeros = EXPLICIT;
554 break;
555 default:
556 GERB_MESSAGE("EagleCad bug detected: Defaults to omit leading zeroes\n");
557 gerb_ungetc(fd);
558 image->format->omit_zeros = LEADING;
561 switch (gerb_fgetc(fd)) {
562 case 'A':
563 image->format->coordinate = ABSOLUTE;
564 break;
565 case 'I':
566 image->format->coordinate = INCREMENTAL;
567 break;
568 default:
569 GERB_COMPILE_ERROR("Format error: coordinate = %c\n", op[0]);
572 while((op[0] = gerb_fgetc(fd)) != '*') {
573 switch (op[0]) {
574 case 'N':
575 op[0] = (char)gerb_fgetc(fd);
576 image->format->lim_seqno = op[0] - '0';
577 break;
578 case 'G':
579 op[0] = (char)gerb_fgetc(fd);
580 image->format->lim_gf = op[0] - '0';
581 break;
582 case 'D':
583 op[0] = (char)gerb_fgetc(fd);
584 image->format->lim_pf = op[0] - '0';
585 break;
586 case 'M':
587 op[0] = (char)gerb_fgetc(fd);
588 image->format->lim_mf = op[0] - '0';
589 break;
590 case 'X' :
591 op[0] = gerb_fgetc(fd);
592 if ((op[0] < '0') || (op[0] > '6'))
593 GERB_COMPILE_ERROR("Illegal format size : %c\n", (char)op[0]);
594 image->format->x_int = op[0] - '0';
595 op[0] = gerb_fgetc(fd);
596 if ((op[0] < '0') || (op[0] > '6'))
597 GERB_COMPILE_ERROR("Illegal format size : %c\n", (char)op[0]);
598 image->format->x_dec = op[0] - '0';
599 break;
600 case 'Y':
601 op[0] = gerb_fgetc(fd);
602 if ((op[0] < '0') || (op[0] > '6'))
603 GERB_COMPILE_ERROR("Illegal format size : %c\n", (char)op[0]);
604 image->format->y_int = op[0] - '0';
605 op[0] = gerb_fgetc(fd);
606 if ((op[0] < '0') || (op[0] > '6'))
607 GERB_COMPILE_ERROR("Illegal format size : %c\n", (char)op[0]);
608 image->format->y_dec = op[0] - '0';
609 break;
610 default :
611 GERB_COMPILE_ERROR("Not handled type of format statement [%c]\n", op[0]);
614 break;
615 case A2I('M','I'): /* Mirror Image */
616 NOT_IMPL(fd, "%MI%");
617 break;
618 case A2I('M','O'): /* Mode of Units */
620 op[0] = gerb_fgetc(fd);
621 op[1] = gerb_fgetc(fd);
623 if ((op[0] == EOF) || (op[1] == EOF))
624 GERB_COMPILE_ERROR("Unexpected EOF found.\n");
626 switch (A2I(op[0],op[1])) {
627 case A2I('I','N'):
628 state->unit = INCH;
629 break;
630 case A2I('M','M'):
631 state->unit = MM;
632 break;
633 default:
634 GERB_COMPILE_ERROR("Illegal unit:%c%c\n", op[0], op[1]);
636 break;
637 case A2I('O','F'): /* Offset */
638 op[0] = gerb_fgetc(fd);
639 while (op[0] != '*') {
640 switch (op[0]) {
641 case 'A' :
642 image->info->offset_a = gerb_fgetdouble(fd);
643 break;
644 case 'B' :
645 image->info->offset_b = gerb_fgetdouble(fd);
646 break;
647 default :
648 GERB_COMPILE_ERROR("Wrong character in offset:%c\n", op[0]);
650 op[0] = gerb_fgetc(fd);
652 return;
653 case A2I('S','F'): /* Scale Factor */
654 if (gerb_fgetc(fd) == 'A')
655 image->info->scale_factor_A = gerb_fgetdouble(fd);
656 else
657 gerb_ungetc(fd);
658 if (gerb_fgetc(fd) == 'B')
659 image->info->scale_factor_B = gerb_fgetdouble(fd);
660 else
661 gerb_ungetc(fd);
662 if ((fabs(image->info->scale_factor_A - 1.0) > 0.00001) ||
663 (fabs(image->info->scale_factor_B - 1.0) > 0.00001))
664 NOT_IMPL(fd, "%SF% != 1.0");
665 break;
666 case A2I('I','C'): /* Input Code */
667 /* Thanks to Stephen Adam for providing this information. As he writes:
668 * btw, here's a logic puzzle for you. If you need to
669 * read the gerber file to see how it's encoded, then
670 * how can you read it?
672 op[0] = gerb_fgetc(fd);
673 op[1] = gerb_fgetc(fd);
675 if ((op[0] == EOF) || (op[1] == EOF))
676 GERB_COMPILE_ERROR("Unexpected EOF found.\n");
678 switch (A2I(op[0],op[1])) {
679 case A2I('A','S'):
680 image->info->encoding = ASCII;
681 break;
682 case A2I('E','B'):
683 image->info->encoding = EBCDIC;
684 break;
685 case A2I('B','C'):
686 image->info->encoding = BCD;
687 break;
688 case A2I('I','S'):
689 image->info->encoding = ISO_ASCII;
690 break;
691 case A2I('E','I'):
692 image->info->encoding = EIA;
693 break;
694 default:
695 GERB_COMPILE_ERROR("Strange inputcode : %c%c\n", op[0], op[1]);
697 break;
699 /* Image parameters */
700 case A2I('I','J'): /* Image Justify */
701 NOT_IMPL(fd, "%IJ%");
702 break;
703 case A2I('I','N'): /* Image Name */
704 image->info->name = gerb_fgetstring(fd, '*');
705 break;
706 case A2I('I','O'): /* Image Offset */
707 NOT_IMPL(fd, "%IO%");
708 break;
709 case A2I('I','P'): /* Image Polarity */
711 for (ano = 0; ano < 3; ano++) {
712 op[0] = gerb_fgetc(fd);
713 if (op[0] == EOF)
714 GERB_COMPILE_ERROR("Unexpected EOF found.\n");
715 str[ano] = (char)op[0];
718 if (strncmp(str, "POS", 3) == 0)
719 image->info->polarity = POSITIVE;
720 else if (strncmp(str, "NEG", 3) == 0)
721 image->info->polarity = NEGATIVE;
722 else
723 GERB_COMPILE_ERROR("Strange polarity : %c%c%c\n", str[0], str[1], str[2]);
725 break;
726 case A2I('I','R'): /* Image Rotation */
727 tmp = gerb_fgetint(fd, NULL);
728 if (tmp != 0)
729 NOT_IMPL(fd, "%IR%");
730 break;
731 case A2I('P','F'): /* Plotter Film */
732 NOT_IMPL(fd, "%PF%");
733 break;
735 /* Aperture parameters */
736 case A2I('A','D'): /* Aperture Description */
737 a = (gerb_aperture_t *)malloc(sizeof(gerb_aperture_t));
738 memset((void *)a, 0, sizeof(gerb_aperture_t));
739 ano = parse_aperture_definition(fd, a, image->amacro);
740 if ((ano >= APERTURE_MIN) && (ano <= APERTURE_MAX)) {
741 a->unit = state->unit;
742 image->aperture[ano] = a;
743 } else
744 GERB_COMPILE_ERROR("Aperture number out of bounds : %d\n", ano);
745 break;
746 case A2I('A','M'): /* Aperture Macro */
747 tmp_amacro = image->amacro;
748 image->amacro = parse_aperture_macro(fd);
749 image->amacro->next = tmp_amacro;
750 #ifdef AMACRO_DEBUG
751 print_program(image->amacro);
752 #endif
753 break;
755 /* Layer */
756 case A2I('L','N'): /* Layer Name */
757 state->curr_layername = gerb_fgetstring(fd, '*');
758 break;
759 case A2I('L','P'): /* Layer Polarity */
760 switch (gerb_fgetc(fd)) {
761 case 'D': /* Dark Polarity (default) */
762 state->layer_polarity = DARK;
763 break;
764 case 'C': /* Clear Polarity */
765 state->layer_polarity = CLEAR;
766 break;
767 default:
768 GERB_COMPILE_WARNING("Strange Layer Polarity: %c\n", op[0]);
770 break;
771 case A2I('K','O'): /* Knock Out */
772 NOT_IMPL(fd, "%KO%");
773 break;
774 case A2I('S','R'): /* Step and Repeat */
775 op[0] = gerb_fgetc(fd);
776 if (op[0] == '*') { /* Disable previous SR parameters */
777 image->info->step_and_repeat.X = 1;
778 image->info->step_and_repeat.Y = 1;
779 image->info->step_and_repeat.dist_X = 0.0;
780 image->info->step_and_repeat.dist_Y = 0.0;
781 break;
783 while (op[0] != '*') {
784 switch (op[0]) {
785 case 'X':
786 image->info->step_and_repeat.X = gerb_fgetint(fd, NULL);
787 break;
788 case 'Y':
789 image->info->step_and_repeat.Y = gerb_fgetint(fd, NULL);
790 break;
791 case 'I':
792 image->info->step_and_repeat.dist_X = gerb_fgetdouble(fd);
793 break;
794 case 'J':
795 image->info->step_and_repeat.dist_Y = gerb_fgetdouble(fd);
796 break;
797 default:
798 GERB_COMPILE_ERROR("Step-and-repeat parameter error\n");
800 op[0] = gerb_fgetc(fd);
802 if ((image->info->step_and_repeat.X != 1) ||
803 (image->info->step_and_repeat.Y != 1) ||
804 (fabs(image->info->step_and_repeat.dist_X) > 0.000001) ||
805 (fabs(image->info->step_and_repeat.dist_Y) > 0.000001))
806 NOT_IMPL(fd, "%SR%");
807 break;
808 case A2I('R','O'): /* Rotate */
809 NOT_IMPL(fd, "%RO%");
810 break;
811 default:
812 GERB_COMPILE_ERROR("Unknown extension found %%%c%c%%\n", op[0], op[1]);
815 return;
816 } /* parse_rs274x */
819 static int
820 parse_aperture_definition(gerb_file_t *fd, gerb_aperture_t *aperture,
821 amacro_t *amacro)
823 int ano, i;
824 char *ad;
825 char *token;
826 amacro_t *curr_amacro;
828 if (gerb_fgetc(fd) != 'D')
829 return -1;
832 * Get aperture no
834 ano = gerb_fgetint(fd, NULL);
837 * Read in the whole aperture defintion and tokenize it
839 ad = gerb_fgetstring(fd, '*');
840 token = strtok(ad, ",");
842 if (strlen(token) == 1) {
843 switch (token[0]) {
844 case 'C':
845 aperture->type = CIRCLE;
846 break;
847 case 'R' :
848 aperture->type = RECTANGLE;
849 break;
850 case 'O' :
851 aperture->type = OVAL;
852 break;
853 case 'P' :
854 aperture->type = POLYGON;
855 break;
857 /* Here a should a T be defined, but I don't know what it represents */
858 } else {
859 aperture->type = MACRO;
861 * In aperture definition, point to the aperture macro
862 * used in the defintion
864 curr_amacro = amacro;
865 while (curr_amacro) {
866 if ((strlen(curr_amacro->name) == strlen(token)) &&
867 (strcmp(curr_amacro->name, token) == 0)) {
868 aperture->amacro = curr_amacro;
869 break;
871 curr_amacro = curr_amacro->next;
876 * Parse all parameters
878 for (token = strtok(NULL, "X"), i = 0; token != NULL;
879 token = strtok(NULL, "X"), i++)
880 aperture->parameter[i] = strtod(token, NULL);
882 aperture->nuf_parameters = i;
884 gerb_ungetc(fd);
886 free(ad);
888 return ano;
889 } /* parse_aperture_definition */
892 static void
893 calc_cirseg_sq(struct gerb_net *net, int cw,
894 double delta_cp_x, double delta_cp_y)
896 double d1x, d1y, d2x, d2y;
897 double alfa, beta;
898 int quadrant = 0;
902 * Quadrant detection (based on ccw, converted below if cw)
903 * Y ^
904 * /!\
906 * ---->X
908 if (net->start_x > net->stop_x)
909 /* 1st and 2nd quadrant */
910 if (net->start_y < net->stop_y)
911 quadrant = 1;
912 else
913 quadrant = 2;
914 else
915 /* 3rd and 4th quadrant */
916 if (net->start_y > net->stop_y)
917 quadrant = 3;
918 else
919 quadrant = 4;
922 * If clockwise, rotate quadrant
924 if (cw) {
925 switch (quadrant) {
926 case 1 :
927 quadrant = 3;
928 break;
929 case 2 :
930 quadrant = 4;
931 break;
932 case 3 :
933 quadrant = 1;
934 break;
935 case 4 :
936 quadrant = 2;
937 break;
938 default :
939 GERB_COMPILE_ERROR("Unknow quadrant value while converting to cw\n");
944 * Calculate arc center point
946 switch (quadrant) {
947 case 1 :
948 net->cirseg->cp_x = net->start_x - delta_cp_x;
949 net->cirseg->cp_y = net->start_y - delta_cp_y;
950 break;
951 case 2 :
952 net->cirseg->cp_x = net->start_x + delta_cp_x;
953 net->cirseg->cp_y = net->start_y - delta_cp_y;
954 break;
955 case 3 :
956 net->cirseg->cp_x = net->start_x + delta_cp_x;
957 net->cirseg->cp_y = net->start_y + delta_cp_y;
958 break;
959 case 4 :
960 net->cirseg->cp_x = net->start_x - delta_cp_x;
961 net->cirseg->cp_y = net->start_y + delta_cp_y;
962 break;
963 default :
964 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant);
968 * Some good values
970 d1x = fabs(net->start_x - net->cirseg->cp_x);
971 d1y = fabs(net->start_y - net->cirseg->cp_y);
972 d2x = fabs(net->stop_x - net->cirseg->cp_x);
973 d2y = fabs(net->stop_y - net->cirseg->cp_y);
975 alfa = atan2(d1y, d1x);
976 beta = atan2(d2y, d2x);
979 * Avoid divide by zero when sin(0) = 0 and cos(90) = 0
981 net->cirseg->width = alfa < beta ?
982 2 * (d1x / cos(alfa)) : 2 * (d2x / cos(beta));
983 net->cirseg->height = alfa > beta ?
984 2 * (d1y / sin(alfa)) : 2 * (d2y / sin(beta));
986 if (alfa < 0.000001 && beta < 0.000001) {
987 net->cirseg->height = 0;
990 #define RAD2DEG(a) (a * 180 / M_PI)
992 switch (quadrant) {
993 case 1 :
994 net->cirseg->angle1 = RAD2DEG(alfa);
995 net->cirseg->angle2 = RAD2DEG(beta);
996 break;
997 case 2 :
998 net->cirseg->angle1 = 180.0 - RAD2DEG(alfa);
999 net->cirseg->angle2 = 180.0 - RAD2DEG(beta);
1000 break;
1001 case 3 :
1002 net->cirseg->angle1 = 180.0 + RAD2DEG(alfa);
1003 net->cirseg->angle2 = 180.0 + RAD2DEG(beta);
1004 break;
1005 case 4 :
1006 net->cirseg->angle1 = 360.0 - RAD2DEG(alfa);
1007 net->cirseg->angle2 = 360.0 - RAD2DEG(beta);
1008 break;
1009 default :
1010 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant);
1013 if (net->cirseg->width < 0.0)
1014 GERB_COMPILE_WARNING("Negative width [%f] in quadrant %d [%f][%f]\n",
1015 net->cirseg->width, quadrant, alfa, beta);
1017 if (net->cirseg->height < 0.0)
1018 GERB_COMPILE_WARNING("Negative height [%f] in quadrant %d [%f][%f]\n",
1019 net->cirseg->height, quadrant, RAD2DEG(alfa), RAD2DEG(beta));
1021 return;
1023 } /* calc_cirseg_sq */
1026 static void
1027 calc_cirseg_mq(struct gerb_net *net, int cw,
1028 double delta_cp_x, double delta_cp_y)
1030 double d1x, d1y, d2x, d2y;
1031 double alfa, beta;
1033 net->cirseg->cp_x = net->start_x + delta_cp_x;
1034 net->cirseg->cp_y = net->start_y + delta_cp_y;
1037 * Some good values
1039 d1x = net->start_x - net->cirseg->cp_x;
1040 d1y = net->start_y - net->cirseg->cp_y;
1041 d2x = net->stop_x - net->cirseg->cp_x;
1042 d2y = net->stop_y - net->cirseg->cp_y;
1044 alfa = atan2(d1y, d1x);
1045 beta = atan2(d2y, d2x);
1047 net->cirseg->width = sqrt(delta_cp_x*delta_cp_x + delta_cp_y*delta_cp_y);
1048 net->cirseg->width *= 2.0;
1049 net->cirseg->height = net->cirseg->width;
1051 net->cirseg->angle1 = RAD2DEG(alfa);
1052 net->cirseg->angle2 = RAD2DEG(beta);
1055 * Make sure it's always positive angles
1057 if (net->cirseg->angle1 < 0.0) {
1058 net->cirseg->angle1 += 360.0;
1059 net->cirseg->angle2 += 360.0;
1062 if (net->cirseg->angle2 < 0.0)
1063 net->cirseg->angle2 += 360.0;
1065 if(net->cirseg->angle2 == 0.0)
1066 net->cirseg->angle2 = 360.0;
1069 * This is a sanity check for angles after the nature of atan2.
1070 * If cw we must make sure angle1-angle2 are always positive,
1071 * If ccw we must make sure angle2-angle1 are always negative.
1072 * We should really return one angle and the difference as GTK
1073 * uses them. But what the heck, it works for me.
1075 if (cw) {
1076 if (net->cirseg->angle1 <= net->cirseg->angle2)
1077 net->cirseg->angle2 -= 360.0;
1078 } else {
1079 if (net->cirseg->angle1 >= net->cirseg->angle2)
1080 net->cirseg->angle2 += 360.0;
1083 return;
1084 } /* calc_cirseg_mq */
1087 static gerb_net_t *
1088 gen_circle_segments(gerb_net_t *curr_net, int cw, int *nuf_pcorners)
1090 double end_x, end_y;
1091 double angle, angle_diff;
1092 double cp_x, cp_y;
1093 double radius;
1094 int steps, i;
1095 gerb_net_t * new_net;
1097 radius = curr_net->cirseg->width / 2.0;
1098 cp_x = curr_net->cirseg->cp_x;
1099 cp_y = curr_net->cirseg->cp_y;
1101 end_x = curr_net->stop_x;
1102 end_y = curr_net->stop_y;
1104 angle = curr_net->cirseg->angle1;
1105 angle_diff = curr_net->cirseg->angle2 - curr_net->cirseg->angle1;
1108 * compute number of segments, each is approx 1 degree
1110 if (cw)
1111 steps = (int)(1.0 - angle_diff);
1112 else
1113 steps = (int)(1.0 + angle_diff);
1115 for (i = 1; i < steps; i++) {
1116 #define DEG2RAD(a) (((a) * M_PI) / 180.0)
1119 * calculate end point for this segment
1121 curr_net->stop_x = cp_x + radius * cos (DEG2RAD(angle + (angle_diff * i) / steps));
1122 curr_net->stop_y = cp_y + radius * sin (DEG2RAD(angle + (angle_diff * i) / steps));
1125 * create a new net, and copy current into it, (but not cirseg)
1127 new_net = (gerb_net_t *)malloc(sizeof(gerb_net_t));
1128 *new_net = *curr_net;
1129 new_net->cirseg = NULL;
1132 * set start point to be old stop
1134 new_net->start_x = curr_net->stop_x;
1135 new_net->start_y = curr_net->stop_y;
1137 curr_net->next = new_net;
1138 curr_net = new_net;
1141 * increment the polygon corner count
1143 (*nuf_pcorners)++;
1147 * ensure the last point is at the end passed in
1149 curr_net->stop_x = end_x;
1150 curr_net->stop_y = end_y;
1152 (*nuf_pcorners)++;
1154 return curr_net;
1155 } /* gen_circle_segments */