Angles are now double
[geda-gerbv/spe.git] / src / gerber.c
blob780cf8e7cdcb4cd29f08776814b39668929dd09c
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);
77 gerb_image_t *
78 parse_gerb(gerb_file_t *fd)
80 gerb_state_t *state = NULL;
81 gerb_image_t *image = NULL;
82 gerb_net_t *curr_net = NULL;
83 int read;
84 double x_scale = 0.0, y_scale = 0.0;
85 double delta_cp_x = 0.0, delta_cp_y = 0.0;
86 double aperture_size;
87 double scale;
89 state = (gerb_state_t *)malloc(sizeof(gerb_state_t));
90 if (state == NULL)
91 GERB_FATAL_ERROR("malloc state failed\n");
94 * Set some defaults
96 memset((void *)state, 0, sizeof(gerb_state_t));
97 state->layer_polarity = DARK;
98 /*
99 * "Inches are assumed if units are not specified"
100 * rs274xrevd_e.pdf, p. 39
102 state->unit = INCH;
105 * Create new image
107 image = new_gerb_image(image);
108 if (image == NULL)
109 GERB_FATAL_ERROR("malloc image failed\n");
110 curr_net = image->netlist;
113 * Start parsing
115 while ((read = gerb_fgetc(fd)) != EOF) {
116 switch ((char)(read & 0xff)) {
117 case 'G':
118 parse_G_code(fd, state, image->format);
119 break;
120 case 'D':
121 parse_D_code(fd, state);
122 break;
123 case 'M':
124 switch(parse_M_code(fd)) {
125 case 1 :
126 case 2 :
127 case 3 :
128 free(state);
129 return image;
130 break;
131 default:
132 GERB_FATAL_ERROR("Strange M code found.\n");
134 break;
135 case 'X':
136 if (image->format->coordinate==INCREMENTAL)
137 state->curr_x += gerb_fgetint(fd);
138 else
139 state->curr_x = gerb_fgetint(fd);
140 state->changed = 1;
141 break;
142 case 'Y':
143 if (image->format->coordinate==INCREMENTAL)
144 state->curr_y += gerb_fgetint(fd);
145 else
146 state->curr_y = gerb_fgetint(fd);
147 state->changed = 1;
148 break;
149 case 'I':
150 state->delta_cp_x = gerb_fgetint(fd);
151 state->changed = 1;
152 break;
153 case 'J':
154 state->delta_cp_y = gerb_fgetint(fd);
155 state->changed = 1;
156 break;
157 case '%':
158 parse_rs274x(fd, image, state);
159 while (gerb_fgetc(fd) != '%');
160 break;
161 case '*':
162 if (state->changed == 0) break;
163 state->changed = 0;
165 curr_net->next = (gerb_net_t *)malloc(sizeof(gerb_net_t));
166 curr_net = curr_net->next;
167 memset((void *)curr_net, 0, sizeof(gerb_net_t));
170 * Scale to given coordinate format
171 * XXX only "omit leading zeros".
173 if (image && image->format ){
174 x_scale = pow(10.0, (double)image->format->x_dec);
175 y_scale = pow(10.0, (double)image->format->y_dec);
178 curr_net->start_x = (double)state->prev_x / x_scale;
179 curr_net->start_y = (double)state->prev_y / y_scale;
180 curr_net->stop_x = (double)state->curr_x / x_scale;
181 curr_net->stop_y = (double)state->curr_y / y_scale;
182 delta_cp_x = (double)state->delta_cp_x / x_scale;
183 delta_cp_y = (double)state->delta_cp_y / y_scale;
186 switch (state->interpolation) {
187 case CW_CIRCULAR :
188 curr_net->cirseg = (gerb_cirseg_t *)malloc(sizeof(gerb_cirseg_t));
189 memset((void *)curr_net->cirseg, 0, sizeof(gerb_cirseg_t));
190 if (state->mq_on)
191 calc_cirseg_mq(curr_net, 1, delta_cp_x, delta_cp_y);
192 else
193 calc_cirseg_sq(curr_net, 1, delta_cp_x, delta_cp_y);
194 break;
195 case CCW_CIRCULAR :
196 curr_net->cirseg = (gerb_cirseg_t *)malloc(sizeof(gerb_cirseg_t));
197 memset((void *)curr_net->cirseg, 0, sizeof(gerb_cirseg_t));
198 if (state->mq_on)
199 calc_cirseg_mq(curr_net, 0, delta_cp_x, delta_cp_y);
200 else
201 calc_cirseg_sq(curr_net, 0, delta_cp_x, delta_cp_y);
202 break;
203 case PAREA_START :
205 * To be able to get back and fill in number of polygon corners
207 state->parea_start_node = curr_net;
208 state->in_parea_fill = 1;
209 break;
210 case PAREA_END :
211 state->parea_start_node = NULL;
212 state->in_parea_fill = 0;
213 break;
214 default :
215 break;
219 * Count number of points in Polygon Area
221 if (state->in_parea_fill && state->parea_start_node)
222 state->parea_start_node->nuf_pcorners++;
224 curr_net->interpolation = state->interpolation;
227 * If we detected the end of Polygon Area Fill we go back to
228 * the interpolation we had before that.
229 * Also if we detected any of the quadrant flags, since some
230 * gerbers don't reset the interpolation (EagleCad again).
232 if ((state->interpolation == PAREA_START) ||
233 (state->interpolation == PAREA_END) ||
234 (state->interpolation == MQ_START) ||
235 (state->interpolation == MQ_END))
236 state->interpolation = state->prev_interpolation;
239 * Save layer polarity and unit
241 curr_net->layer_polarity = state->layer_polarity;
242 curr_net->unit = state->unit;
244 state->delta_cp_x = 0.0;
245 state->delta_cp_y = 0.0;
246 curr_net->aperture = state->curr_aperture;
247 curr_net->aperture_state = state->aperture_state;
250 * Make sure we don't hit any undefined aperture
251 * In macros the first parameter could be basically anything
253 if ((curr_net->aperture != 0) &&
254 (image->aperture[curr_net->aperture] != NULL) &&
255 (image->aperture[curr_net->aperture]->type != MACRO))
256 aperture_size = image->aperture[curr_net->aperture]->parameter[0];
257 else
258 aperture_size = 0.0;
261 * Find min and max of image with compensation for mm.
263 if (curr_net->unit == MM)
264 scale = 25.4;
265 else
266 scale = 1.0;
267 if (image->info->min_x > curr_net->stop_x)
268 image->info->min_x = (curr_net->stop_x - aperture_size) / scale;
269 if (image->info->min_y > curr_net->stop_y)
270 image->info->min_y = (curr_net->stop_y - aperture_size) / scale;
271 if (image->info->max_x < curr_net->stop_x)
272 image->info->max_x = (curr_net->stop_x + aperture_size) / scale;
273 if (image->info->max_y < curr_net->stop_y)
274 image->info->max_y = (curr_net->stop_y + aperture_size) / scale;
276 state->prev_x = state->curr_x;
277 state->prev_y = state->curr_y;
279 break;
280 case 10 : /* White space */
281 case 13 :
282 case ' ' :
283 case '\t' :
284 break;
285 default:
286 GERB_COMPILE_ERROR("Found unknown character (whitespace?) %c[%d]\n", read, read);
290 GERB_COMPILE_ERROR("File is missing gerber End-Of-File\n");
292 return image;
293 } /* parse_gerb */
296 static void
297 parse_G_code(gerb_file_t *fd, gerb_state_t *state, gerb_format_t *format)
299 int op[2];
300 int op_int;
302 op[0] = gerb_fgetc(fd);
303 op[1] = gerb_fgetc(fd);
305 if ((op[0] == EOF) || (op[1] == EOF))
306 GERB_COMPILE_ERROR("Unexpected EOF found.\n");
308 if ((op[0] < (int)'0') || (op[0] > (int)'9') ||
309 (op[1] < (int)'0') || (op[1] > (int)'9'))
310 GERB_COMPILE_ERROR("Non numerical G opcode found [%c%c]\n", op[0], op[1]);
312 op_int = (op[0] - (int)'0');
313 op_int = op_int * 10 + (op[1] - (int)'0');
315 switch(op_int) {
316 case 0: /* Move */
317 /* Is this doing anything really? */
318 break;
319 case 1: /* Linear Interpolation (1X scale) */
320 state->interpolation = LINEARx1;
321 break;
322 case 2: /* Clockwise Linear Interpolation */
323 state->interpolation = CW_CIRCULAR;
324 break;
325 case 3: /* Counter Clockwise Linear Interpolation */
326 state->interpolation = CCW_CIRCULAR;
327 break;
328 case 4: /* Ignore Data Block */
329 /* Don't do anything, just read 'til * */
330 while (gerb_fgetc(fd) != '*');
331 break;
332 case 10: /* Linear Interpolation (10X scale) */
333 state->interpolation = LINEARx10;
334 break;
335 case 11: /* Linear Interpolation (0.1X scale) */
336 state->interpolation = LINEARx01;
337 break;
338 case 12: /* Linear Interpolation (0.01X scale) */
339 state->interpolation = LINEARx001;
340 break;
341 case 36: /* Turn on Polygon Area Fill */
342 state->prev_interpolation = state->interpolation;
343 state->interpolation = PAREA_START;
344 state->changed = 1;
345 break;
346 case 37: /* Turn off Polygon Area Fill */
347 state->interpolation = PAREA_END;
348 state->changed = 1;
349 break;
350 case 54: /* Tool prepare */
351 /* XXX Maybe uneccesary??? */
352 if (gerb_fgetc(fd) == 'D')
353 state->curr_aperture = gerb_fgetint(fd);
354 else
355 GERB_COMPILE_WARNING("Strange code after G54\n");
356 break;
357 case 55: /* Prepare for flash */
358 break;
359 case 70: /* Specify inches */
360 state->unit = INCH;
361 break;
362 case 71: /* Specify millimeters */
363 state->unit = MM;
364 break;
365 case 74: /* Disable 360 circular interpolation */
366 state->prev_interpolation = state->interpolation;
367 state->interpolation = MQ_END;
368 state->mq_on = 0;
369 break;
370 case 75: /* Enable 360 circular interpolation */
371 state->prev_interpolation = state->interpolation;
372 state->interpolation = MQ_START;
373 state->mq_on = 1;
374 break;
375 case 90: /* Specify absolut format */
376 if (format) format->coordinate = ABSOLUTE;
377 break;
378 case 91: /* Specify incremental format */
379 if (format) format->coordinate = INCREMENTAL;
380 break;
381 default:
382 GERB_COMPILE_ERROR("Strange/unhandled G code : %c%c\n", op[0], op[1]);
385 return;
386 } /* parse_G_code */
389 static void
390 parse_D_code(gerb_file_t *fd, gerb_state_t *state)
392 int a;
394 a = gerb_fgetint(fd);
395 switch(a) {
396 case 1 : /* Exposure on */
397 state->aperture_state = ON;
398 state->changed = 1;
399 break;
400 case 2 : /* Exposure off */
401 state->aperture_state = OFF;
402 state->changed = 1;
403 break;
404 case 3 : /* Flash aperture */
405 state->aperture_state = FLASH;
406 state->changed = 1;
407 break;
408 default: /* Aperture in use */
409 if ((a >= APERTURE_MIN) && (a <= APERTURE_MAX))
410 state->curr_aperture = a;
411 else
412 GERB_COMPILE_ERROR("Aperture out of bounds:%d\n", a);
413 state->changed = 0;
416 return;
417 } /* parse_D_code */
420 static int
421 parse_M_code(gerb_file_t *fd)
423 int op[2];
425 op[0] = gerb_fgetc(fd);
426 op[1] = gerb_fgetc(fd);
428 if ((op[0] == EOF) || (op[1] == EOF))
429 GERB_COMPILE_ERROR("Unexpected EOF found.\n");
431 if (op[0] != (int)'0')
432 GERB_COMPILE_ERROR("Strange M code [%c%c]\n", (char)op[0], (char)op[1]);
434 switch (op[1]) {
435 case '0': /* Program stop */
436 return 1;
437 case '1': /* Optional stop */
438 return 2;
439 case '2': /* End of program */
440 return 3;
441 default:
442 GERB_COMPILE_ERROR("Strange M code [%c%c]\n", (char)op[0], (char)op[1]);
444 return 0;
445 } /* parse_M_code */
448 static void
449 parse_rs274x(gerb_file_t *fd, gerb_image_t *image, gerb_state_t *state)
451 int op[2];
452 char str[3];
453 int tmp;
454 gerb_aperture_t *a = NULL;
455 amacro_t *tmp_amacro;
456 int ano;
458 op[0] = gerb_fgetc(fd);
459 op[1] = gerb_fgetc(fd);
461 if ((op[0] == EOF) || (op[1] == EOF))
462 GERB_COMPILE_ERROR("Unexpected EOF found.\n");
464 switch (A2I(op[0], op[1])){
466 /* Directive parameters */
467 case A2I('A','S'): /* Axis Select */
468 op[0] = gerb_fgetc(fd);
469 op[1] = gerb_fgetc(fd);
471 if ((op[0] == EOF) || (op[1] == EOF))
472 GERB_COMPILE_ERROR("Unexpected EOF found.\n");
474 if (((op[0] == 'A') && (op[1] == 'Y')) ||
475 ((op[0] == 'B') && (op[1] == 'X'))) {
476 NOT_IMPL(fd, "%MI with reversed axis not supported%");
477 break;
480 op[0] = gerb_fgetc(fd);
481 op[1] = gerb_fgetc(fd);
483 if ((op[0] == EOF) || (op[1] == EOF))
484 GERB_COMPILE_ERROR("Unexpected EOF found.\n");
486 if (((op[0] == 'A') && (op[1] == 'Y')) ||
487 ((op[0] == 'B') && (op[1] == 'X'))) {
488 NOT_IMPL(fd, "%MI with reversed axis not supported%");
489 break;
491 break;
492 case A2I('F','S'): /* Format Statement */
493 image->format = (gerb_format_t *)malloc(sizeof(gerb_format_t));
494 if (image->format == NULL)
495 GERB_FATAL_ERROR("Failed malloc for format\n");
496 memset((void *)image->format, 0, sizeof(gerb_format_t));
498 switch (gerb_fgetc(fd)) {
499 case 'L':
500 image->format->omit_zeros = LEADING;
501 break;
502 case 'T':
503 image->format->omit_zeros = TRAILING;
504 break;
505 case 'D':
506 image->format->omit_zeros = EXPLICIT;
507 break;
508 default:
509 GERB_MESSAGE("EagleCad bug detected: Defaults to omit leading zeroes\n");
510 gerb_ungetc(fd);
511 image->format->omit_zeros = LEADING;
514 switch (gerb_fgetc(fd)) {
515 case 'A':
516 image->format->coordinate = ABSOLUTE;
517 break;
518 case 'I':
519 image->format->coordinate = INCREMENTAL;
520 break;
521 default:
522 GERB_COMPILE_ERROR("Format error: coordinate = %c\n", op[0]);
525 while((op[0] = gerb_fgetc(fd)) != '*') {
526 switch (op[0]) {
527 case 'N':
528 op[0] = (char)gerb_fgetc(fd);
529 image->format->lim_seqno = op[0] - '0';
530 break;
531 case 'G':
532 op[0] = (char)gerb_fgetc(fd);
533 image->format->lim_gf = op[0] - '0';
534 break;
535 case 'D':
536 op[0] = (char)gerb_fgetc(fd);
537 image->format->lim_pf = op[0] - '0';
538 break;
539 case 'M':
540 op[0] = (char)gerb_fgetc(fd);
541 image->format->lim_mf = op[0] - '0';
542 break;
543 case 'X' :
544 op[0] = gerb_fgetc(fd);
545 if ((op[0] < '0') || (op[0] > '6'))
546 GERB_COMPILE_ERROR("Illegal format size : %c\n", (char)op[0]);
547 image->format->x_int = op[0] - '0';
548 op[0] = gerb_fgetc(fd);
549 if ((op[0] < '0') || (op[0] > '6'))
550 GERB_COMPILE_ERROR("Illegal format size : %c\n", (char)op[0]);
551 image->format->x_dec = op[0] - '0';
552 break;
553 case 'Y':
554 op[0] = gerb_fgetc(fd);
555 if ((op[0] < '0') || (op[0] > '6'))
556 GERB_COMPILE_ERROR("Illegal format size : %c\n", (char)op[0]);
557 image->format->y_int = op[0] - '0';
558 op[0] = gerb_fgetc(fd);
559 if ((op[0] < '0') || (op[0] > '6'))
560 GERB_COMPILE_ERROR("Illegal format size : %c\n", (char)op[0]);
561 image->format->y_dec = op[0] - '0';
562 break;
563 default :
564 GERB_COMPILE_ERROR("Not handled type of format statement [%c]\n", op[0]);
567 break;
568 case A2I('M','I'): /* Mirror Image */
569 NOT_IMPL(fd, "%MI%");
570 break;
571 case A2I('M','O'): /* Mode of Units */
573 op[0] = gerb_fgetc(fd);
574 op[1] = gerb_fgetc(fd);
576 if ((op[0] == EOF) || (op[1] == EOF))
577 GERB_COMPILE_ERROR("Unexpected EOF found.\n");
579 switch (A2I(op[0],op[1])) {
580 case A2I('I','N'):
581 state->unit = INCH;
582 break;
583 case A2I('M','M'):
584 state->unit = MM;
585 break;
586 default:
587 GERB_COMPILE_ERROR("Illegal unit:%c%c\n", op[0], op[1]);
589 break;
590 case A2I('O','F'): /* Offset */
591 op[0] = gerb_fgetc(fd);
592 while (op[0] != '*') {
593 switch (op[0]) {
594 case 'A' :
595 image->info->offset_a = gerb_fgetdouble(fd);
596 break;
597 case 'B' :
598 image->info->offset_b = gerb_fgetdouble(fd);
599 break;
600 default :
601 GERB_COMPILE_ERROR("Wrong character in offset:%c\n", op[0]);
603 op[0] = gerb_fgetc(fd);
605 return;
606 case A2I('S','F'): /* Scale Factor */
607 if (gerb_fgetc(fd) == 'A')
608 image->info->scale_factor_A = gerb_fgetdouble(fd);
609 else
610 gerb_ungetc(fd);
611 if (gerb_fgetc(fd) == 'B')
612 image->info->scale_factor_B = gerb_fgetdouble(fd);
613 else
614 gerb_ungetc(fd);
615 if ((fabs(image->info->scale_factor_A - 1.0) > 0.00001) ||
616 (fabs(image->info->scale_factor_B - 1.0) > 0.00001))
617 NOT_IMPL(fd, "%SF% != 1.0");
618 break;
619 case A2I('I','C'): /* Input Code */
620 /* Thanks to Stephen Adam for providing this information. As he writes:
621 * btw, here's a logic puzzle for you. If you need to
622 * read the gerber file to see how it's encoded, then
623 * how can you read it?
625 op[0] = gerb_fgetc(fd);
626 op[1] = gerb_fgetc(fd);
628 if ((op[0] == EOF) || (op[1] == EOF))
629 GERB_COMPILE_ERROR("Unexpected EOF found.\n");
631 switch (A2I(op[0],op[1])) {
632 case A2I('A','S'):
633 image->info->encoding = ASCII;
634 break;
635 case A2I('E','B'):
636 image->info->encoding = EBCDIC;
637 break;
638 case A2I('B','C'):
639 image->info->encoding = BCD;
640 break;
641 case A2I('I','S'):
642 image->info->encoding = ISO_ASCII;
643 break;
644 case A2I('E','I'):
645 image->info->encoding = EIA;
646 break;
647 default:
648 GERB_COMPILE_ERROR("Strange inputcode : %c%c\n", op[0], op[1]);
650 break;
652 /* Image parameters */
653 case A2I('I','J'): /* Image Justify */
654 NOT_IMPL(fd, "%IJ%");
655 break;
656 case A2I('I','N'): /* Image Name */
657 image->info->name = gerb_fgetstring(fd, '*');
658 break;
659 case A2I('I','O'): /* Image Offset */
660 NOT_IMPL(fd, "%IO%");
661 break;
662 case A2I('I','P'): /* Image Polarity */
664 for (ano = 0; ano < 3; ano++) {
665 op[0] = gerb_fgetc(fd);
666 if (op[0] == EOF)
667 GERB_COMPILE_ERROR("Unexpected EOF found.\n");
668 str[ano] = (char)op[0];
671 if (strncmp(str, "POS", 3) == 0)
672 image->info->polarity = POSITIVE;
673 else if (strncmp(str, "NEG", 3) == 0)
674 image->info->polarity = NEGATIVE;
675 else
676 GERB_COMPILE_ERROR("Strange polarity : %c%c%c\n", str[0], str[1], str[2]);
678 break;
679 case A2I('I','R'): /* Image Rotation */
680 tmp = gerb_fgetint(fd);
681 if (tmp != 0)
682 NOT_IMPL(fd, "%IR%");
683 break;
684 case A2I('P','F'): /* Plotter Film */
685 NOT_IMPL(fd, "%PF%");
686 break;
688 /* Aperture parameters */
689 case A2I('A','D'): /* Aperture Description */
690 a = (gerb_aperture_t *)malloc(sizeof(gerb_aperture_t));
691 memset((void *)a, 0, sizeof(gerb_aperture_t));
692 ano = parse_aperture_definition(fd, a, image->amacro);
693 if ((ano >= APERTURE_MIN) && (ano <= APERTURE_MAX)) {
694 a->unit = state->unit;
695 image->aperture[ano] = a;
696 } else
697 GERB_COMPILE_ERROR("Aperture number out of bounds : %d\n", ano);
698 break;
699 case A2I('A','M'): /* Aperture Macro */
700 tmp_amacro = image->amacro;
701 image->amacro = parse_aperture_macro(fd);
702 image->amacro->next = tmp_amacro;
703 #ifdef AMACRO_DEBUG
704 print_program(image->amacro);
705 #endif
706 break;
708 /* Layer */
709 case A2I('L','N'): /* Layer Name */
710 state->curr_layername = gerb_fgetstring(fd, '*');
711 break;
712 case A2I('L','P'): /* Layer Polarity */
713 switch (gerb_fgetc(fd)) {
714 case 'D': /* Dark Polarity (default) */
715 state->layer_polarity = DARK;
716 break;
717 case 'C': /* Clear Polarity */
718 state->layer_polarity = CLEAR;
719 break;
720 default:
721 GERB_COMPILE_WARNING("Strange Layer Polarity: %c\n", op[0]);
723 break;
724 case A2I('K','O'): /* Knock Out */
725 NOT_IMPL(fd, "%KO%");
726 break;
727 case A2I('S','R'): /* Step and Repeat */
728 op[0] = gerb_fgetc(fd);
729 if (op[0] == '*') { /* Disable previous SR parameters */
730 image->info->step_and_repeat.X = 1;
731 image->info->step_and_repeat.Y = 1;
732 image->info->step_and_repeat.dist_X = 0.0;
733 image->info->step_and_repeat.dist_Y = 0.0;
734 break;
736 while (op[0] != '*') {
737 switch (op[0]) {
738 case 'X':
739 image->info->step_and_repeat.X = gerb_fgetint(fd);
740 break;
741 case 'Y':
742 image->info->step_and_repeat.Y = gerb_fgetint(fd);
743 break;
744 case 'I':
745 image->info->step_and_repeat.dist_X = gerb_fgetdouble(fd);
746 break;
747 case 'J':
748 image->info->step_and_repeat.dist_Y = gerb_fgetdouble(fd);
749 break;
750 default:
751 GERB_COMPILE_ERROR("Step-and-repeat parameter error\n");
753 op[0] = gerb_fgetc(fd);
755 if ((image->info->step_and_repeat.X != 1) ||
756 (image->info->step_and_repeat.Y != 1) ||
757 (fabs(image->info->step_and_repeat.dist_X) > 0.000001) ||
758 (fabs(image->info->step_and_repeat.dist_Y) > 0.000001))
759 NOT_IMPL(fd, "%SR%");
760 break;
761 case A2I('R','O'): /* Rotate */
762 NOT_IMPL(fd, "%RO%");
763 break;
764 default:
765 GERB_COMPILE_ERROR("Unknown extension found %%%c%c%%\n", op[0], op[1]);
768 return;
769 } /* parse_rs274x */
772 static int
773 parse_aperture_definition(gerb_file_t *fd, gerb_aperture_t *aperture,
774 amacro_t *amacro)
776 int ano, i;
777 char *ad;
778 char *token;
779 amacro_t *curr_amacro;
781 if (gerb_fgetc(fd) != 'D')
782 return -1;
785 * Get aperture no
787 ano = gerb_fgetint(fd);
790 * Read in the whole aperture defintion and tokenize it
792 ad = gerb_fgetstring(fd, '*');
793 token = strtok(ad, ",");
795 if (strlen(token) == 1) {
796 switch (token[0]) {
797 case 'C':
798 aperture->type = CIRCLE;
799 break;
800 case 'R' :
801 aperture->type = RECTANGLE;
802 break;
803 case 'O' :
804 aperture->type = OVAL;
805 break;
806 case 'P' :
807 aperture->type = POLYGON;
808 break;
810 /* Here a should a T be defined, but I don't know what it represents */
811 } else {
812 aperture->type = MACRO;
814 * In aperture definition, point to the aperture macro
815 * used in the defintion
817 curr_amacro = amacro;
818 while (curr_amacro) {
819 if ((strlen(curr_amacro->name) == strlen(token)) &&
820 (strcmp(curr_amacro->name, token) == 0)) {
821 aperture->amacro = curr_amacro;
822 break;
824 curr_amacro = curr_amacro->next;
829 * Parse all parameters
831 for (token = strtok(NULL, "X"), i = 0; token != NULL;
832 token = strtok(NULL, "X"), i++)
833 aperture->parameter[i] = strtod(token, NULL);
835 aperture->nuf_parameters = i;
837 gerb_ungetc(fd);
839 free(ad);
841 return ano;
842 } /* parse_aperture_definition */
845 static void
846 calc_cirseg_sq(struct gerb_net *net, int cw,
847 double delta_cp_x, double delta_cp_y)
849 double d1x, d1y, d2x, d2y;
850 double alfa, beta;
851 int quadrant = 0;
855 * Quadrant detection (based on ccw, coverted below if cw)
856 * Y ^
857 * /!\
859 * ---->X
861 if (net->start_x > net->stop_x)
862 /* 1st and 2nd quadrant */
863 if (net->start_y < net->stop_y)
864 quadrant = 1;
865 else
866 quadrant = 2;
867 else
868 /* 3rd and 4th quadrant */
869 if (net->start_y > net->stop_y)
870 quadrant = 3;
871 else
872 quadrant = 4;
875 * If clockwise, rotate quadrant
877 if (cw) {
878 switch (quadrant) {
879 case 1 :
880 quadrant = 3;
881 break;
882 case 2 :
883 quadrant = 4;
884 break;
885 case 3 :
886 quadrant = 1;
887 break;
888 case 4 :
889 quadrant = 2;
890 break;
891 default :
892 GERB_COMPILE_ERROR("Unknow quadrant value while converting to cw\n");
897 * Calculate arc center point
899 switch (quadrant) {
900 case 1 :
901 net->cirseg->cp_x = net->start_x - delta_cp_x;
902 net->cirseg->cp_y = net->start_y - delta_cp_y;
903 break;
904 case 2 :
905 net->cirseg->cp_x = net->start_x + delta_cp_x;
906 net->cirseg->cp_y = net->start_y - delta_cp_y;
907 break;
908 case 3 :
909 net->cirseg->cp_x = net->start_x + delta_cp_x;
910 net->cirseg->cp_y = net->start_y + delta_cp_y;
911 break;
912 case 4 :
913 net->cirseg->cp_x = net->start_x - delta_cp_x;
914 net->cirseg->cp_y = net->start_y + delta_cp_y;
915 break;
916 default :
917 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant);
921 * Some good values
923 d1x = fabs(net->start_x - net->cirseg->cp_x);
924 d1y = fabs(net->start_y - net->cirseg->cp_y);
925 d2x = fabs(net->stop_x - net->cirseg->cp_x);
926 d2y = fabs(net->stop_y - net->cirseg->cp_y);
928 alfa = atan2(d1y, d1x);
929 beta = atan2(d2y, d2x);
932 * Avoid divide by zero when sin(0) = 0 and cos(90) = 0
934 net->cirseg->width = alfa < beta ?
935 2 * (d1x / cos(alfa)) : 2 * (d2x / cos(beta));
936 net->cirseg->height = alfa > beta ?
937 2 * (d1y / sin(alfa)) : 2 * (d2y / sin(beta));
939 if (alfa < 0.000001 && beta < 0.000001) {
940 net->cirseg->height = 0;
943 #define RAD2DEG(a) (a * 180 / M_PI)
945 switch (quadrant) {
946 case 1 :
947 net->cirseg->angle1 = RAD2DEG(alfa);
948 net->cirseg->angle2 = RAD2DEG(beta);
949 break;
950 case 2 :
951 net->cirseg->angle1 = 180.0 - RAD2DEG(alfa);
952 net->cirseg->angle2 = 180.0 - RAD2DEG(beta);
953 break;
954 case 3 :
955 net->cirseg->angle1 = 180.0 + RAD2DEG(alfa);
956 net->cirseg->angle2 = 180.0 + RAD2DEG(beta);
957 break;
958 case 4 :
959 net->cirseg->angle1 = 360.0 - RAD2DEG(alfa);
960 net->cirseg->angle2 = 360.0 - RAD2DEG(beta);
961 break;
962 default :
963 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant);
966 if (net->cirseg->width < 0.0)
967 GERB_COMPILE_WARNING("Negative width [%f] in quadrant %d [%f][%f]\n",
968 net->cirseg->width, quadrant, alfa, beta);
970 if (net->cirseg->height < 0.0)
971 GERB_COMPILE_WARNING("Negative height [%f] in quadrant %d [%f][%f]\n",
972 net->cirseg->height, quadrant, RAD2DEG(alfa), RAD2DEG(beta));
974 return;
976 } /* calc_cirseg_sq */
979 static void
980 calc_cirseg_mq(struct gerb_net *net, int cw,
981 double delta_cp_x, double delta_cp_y)
983 double d1x, d1y, d2x, d2y;
984 double alfa, beta;
986 net->cirseg->cp_x = net->start_x + delta_cp_x;
987 net->cirseg->cp_y = net->start_y + delta_cp_y;
990 * Some good values
992 d1x = net->start_x - net->cirseg->cp_x;
993 d1y = net->start_y - net->cirseg->cp_y;
994 d2x = net->stop_x - net->cirseg->cp_x;
995 d2y = net->stop_y - net->cirseg->cp_y;
997 alfa = atan2(d1y, d1x);
998 beta = atan2(d2y, d2x);
1000 net->cirseg->width = sqrt(delta_cp_x*delta_cp_x + delta_cp_y*delta_cp_y);
1001 net->cirseg->width *= 2.0;
1002 net->cirseg->height = net->cirseg->width;
1004 net->cirseg->angle1 = RAD2DEG(alfa);
1005 net->cirseg->angle2 = RAD2DEG(beta);
1008 * Make sure it's always positive angles
1010 if (net->cirseg->angle1 < 0) {
1011 net->cirseg->angle1 += 360.0;
1012 net->cirseg->angle2 += 360.0;
1015 if (net->cirseg->angle2 < 0.0)
1016 net->cirseg->angle2 += 360.0;
1018 if(net->cirseg->angle2 == 0.0)
1019 net->cirseg->angle2 = 360.0;
1022 * This is a sanity check for angles after the nature of atan2.
1023 * If cw we must make sure angle1-angle2 are always positive,
1024 * If ccw we must make sure angle2-angle1 are always negative.
1025 * We should really return one angle and the difference as GTK
1026 * uses them. But what the heck, it works for me.
1028 if (cw) {
1029 if (net->cirseg->angle1 < net->cirseg->angle2)
1030 net->cirseg->angle2 -= 360.0;
1031 } else {
1032 if (net->cirseg->angle1 > net->cirseg->angle2)
1033 net->cirseg->angle2 += 360.0;
1036 return;
1037 } /* calc_cirseg_mq */