If first point in the first line didn't have an aperture defined, this line was drawn...
[geda-gerbv/spe.git] / src / gerber.c
blob20d1676029d23c4e3a2d60fe3a579a9e9107334e
1 /*
2 * gEDA - GNU Electronic Design Automation
3 * This is a part of gerbv
5 * Copyright (C) 2000-2002 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() */
28 #include "gerber.h"
31 #define NOT_IMPL(fd, s) do { \
32 fprintf(stderr, "Not Implemented:%s\n", s); \
33 while (gerb_fgetc(fd) != (int)'*'); \
34 } while(0)
37 #ifndef err
38 #define err(errcode, a...) \
39 do { \
40 fprintf(stderr, ##a); \
41 exit(errcode);\
42 } while (0)
43 #endif
45 #define A2I(a,b) (((a & 0xff) << 8) + (b & 0xff))
47 typedef struct gerb_state {
48 int curr_x;
49 int curr_y;
50 int prev_x;
51 int prev_y;
52 int delta_cp_x;
53 int delta_cp_y;
54 int curr_aperture;
55 int changed;
56 enum polarity_t layer_polarity;
57 enum aperture_state_t aperture_state;
58 enum interpolation_t interpolation;
59 enum interpolation_t prev_interpolation;
60 gerb_net_t *parea_start_node;
61 char *curr_layername;
62 int in_parea_fill;
63 int mq_on;
64 } gerb_state_t;
67 /* Local function prototypes */
68 static void parse_G_code(gerb_file_t *fd, gerb_state_t *state,
69 gerb_format_t *format);
70 static void parse_D_code(gerb_file_t *fd, gerb_state_t *state);
71 static int parse_M_code(gerb_file_t *fd);
72 static void parse_rs274x(gerb_file_t *fd, gerb_image_t *image,
73 gerb_state_t *state);
74 static int parse_aperture_definition(gerb_file_t *fd,
75 gerb_aperture_t *aperture,
76 amacro_t *amacro);
77 static void calc_cirseg_sq(struct gerb_net *net, int cw,
78 double delta_cp_x, double delta_cp_y);
79 static void calc_cirseg_mq(struct gerb_net *net, int cw,
80 double delta_cp_x, double delta_cp_y);
83 gerb_image_t *
84 parse_gerb(gerb_file_t *fd)
86 gerb_state_t *state = NULL;
87 gerb_image_t *image = NULL;
88 gerb_net_t *curr_net = NULL;
89 int read;
90 double x_scale = 0.0, y_scale = 0.0;
91 double delta_cp_x = 0.0, delta_cp_y = 0.0;
92 double aperture_size;
94 state = (gerb_state_t *)malloc(sizeof(gerb_state_t));
95 if (state == NULL)
96 err(1, "malloc state failed\n");
99 * Set some defaults
101 memset((void *)state, 0, sizeof(gerb_state_t));
102 state->layer_polarity = DARK;
105 * Create new image
107 image = new_gerb_image(image);
108 if (image == NULL)
109 err(1, "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 err(1, "Strange M code found.\n");
134 break;
135 case 'X':
136 state->curr_x = gerb_fgetint(fd);
137 state->changed = 1;
138 break;
139 case 'Y':
140 state->curr_y = gerb_fgetint(fd);
141 state->changed = 1;
142 break;
143 case 'I':
144 state->delta_cp_x = gerb_fgetint(fd);
145 state->changed = 1;
146 break;
147 case 'J':
148 state->delta_cp_y = gerb_fgetint(fd);
149 state->changed = 1;
150 break;
151 case '%':
152 parse_rs274x(fd, image, state);
153 while (gerb_fgetc(fd) != '%');
154 break;
155 case '*':
156 if (state->changed == 0) break;
157 state->changed = 0;
159 curr_net->next = (gerb_net_t *)malloc(sizeof(gerb_net_t));
160 curr_net = curr_net->next;
161 memset((void *)curr_net, 0, sizeof(gerb_net_t));
164 * Scale to given coordinate format
165 * XXX only "omit leading zeros".
167 if (image && image->format ){
168 x_scale = pow(10.0, (double)image->format->x_dec);
169 y_scale = pow(10.0, (double)image->format->y_dec);
172 curr_net->start_x = (double)state->prev_x / x_scale;
173 curr_net->start_y = (double)state->prev_y / y_scale;
174 curr_net->stop_x = (double)state->curr_x / x_scale;
175 curr_net->stop_y = (double)state->curr_y / y_scale;
176 delta_cp_x = (double)state->delta_cp_x / x_scale;
177 delta_cp_y = (double)state->delta_cp_y / y_scale;
179 switch (state->interpolation) {
180 case CW_CIRCULAR :
181 curr_net->cirseg = (gerb_cirseg_t *)malloc(sizeof(gerb_cirseg_t));
182 memset((void *)curr_net->cirseg, 0, sizeof(gerb_cirseg_t));
183 if (state->mq_on)
184 calc_cirseg_mq(curr_net, 1, delta_cp_x, delta_cp_y);
185 else
186 calc_cirseg_sq(curr_net, 1, delta_cp_x, delta_cp_y);
187 break;
188 case CCW_CIRCULAR :
189 curr_net->cirseg = (gerb_cirseg_t *)malloc(sizeof(gerb_cirseg_t));
190 memset((void *)curr_net->cirseg, 0, sizeof(gerb_cirseg_t));
191 if (state->mq_on)
192 calc_cirseg_mq(curr_net, 0, delta_cp_x, delta_cp_y);
193 else
194 calc_cirseg_sq(curr_net, 0, delta_cp_x, delta_cp_y);
195 break;
196 case PAREA_START :
198 * To be able to get back and fill in number of polygon corners
200 state->parea_start_node = curr_net;
201 state->in_parea_fill = 1;
202 break;
203 case PAREA_END :
204 state->parea_start_node = NULL;
205 state->in_parea_fill = 0;
206 break;
207 default :
211 * Count number of points in Polygon Area
213 if (state->in_parea_fill && state->parea_start_node)
214 state->parea_start_node->nuf_pcorners++;
216 curr_net->interpolation = state->interpolation;
219 * If we detected the end of Polygon Area Fill we go back to
220 * the interpolation we had before that.
221 * Also if we detected any of the quadrant flags, since some
222 * gerbers don't reset the interpolation (EagleCad again).
224 if ((state->interpolation == PAREA_END) ||
225 (state->interpolation == MQ_START) ||
226 (state->interpolation == MQ_END))
227 state->interpolation = state->prev_interpolation;
230 * Save layer polarity
232 curr_net->layer_polarity = state->layer_polarity;
234 state->delta_cp_x = 0.0;
235 state->delta_cp_y = 0.0;
236 curr_net->aperture = state->curr_aperture;
237 curr_net->aperture_state = state->aperture_state;
240 * Make sure we don't hit any undefined aperture
241 * In macros the first parameter could be basically anything
243 if ((curr_net->aperture != 0) &&
244 (image->aperture[curr_net->aperture] != NULL) &&
245 (image->aperture[curr_net->aperture]->type != MACRO))
246 aperture_size = image->aperture[curr_net->aperture]->parameter[0];
247 else
248 aperture_size = 0.0;
251 * Find min and max of image
253 if (image->info->min_x == 0.0 ||
254 image->info->min_x > curr_net->stop_x)
255 image->info->min_x = curr_net->stop_x - aperture_size;
256 if (image->info->min_y == 0.0 ||
257 image->info->min_y > curr_net->stop_y)
258 image->info->min_y = curr_net->stop_y - aperture_size;
259 if (image->info->max_x < curr_net->stop_x)
260 image->info->max_x = curr_net->stop_x + aperture_size;
261 if (image->info->max_y < curr_net->stop_y)
262 image->info->max_y = curr_net->stop_y + aperture_size;
264 state->prev_x = state->curr_x;
265 state->prev_y = state->curr_y;
267 break;
268 case 10 : /* White space */
269 case 13 :
270 case ' ' :
271 case '\t' :
272 break;
273 default:
274 fprintf(stderr, "Found unknown character (whitespace?) %c[%d]\n", read, read);
278 fprintf(stderr, "File is missing gerber End-Of-File\n");
280 return image;
281 } /* parse_gerb */
284 static void
285 parse_G_code(gerb_file_t *fd, gerb_state_t *state, gerb_format_t *format)
287 int op[2];
288 int op_int;
290 op[0] = gerb_fgetc(fd);
291 op[1] = gerb_fgetc(fd);
293 if ((op[0] == EOF) || (op[1] == EOF))
294 err(1, "Unexpected EOF found.\n");
296 if ((op[0] < (int)'0') || (op[0] > (int)'9') ||
297 (op[1] < (int)'0') || (op[1] > (int)'9'))
298 err(1, "Non numerical G opcode found [%c%c]\n", op[0], op[1]);
300 op_int = (op[0] - (int)'0');
301 op_int = op_int * 10 + (op[1] - (int)'0');
303 switch(op_int) {
304 case 0: /* Move */
305 /* Is this doing anything really? */
306 break;
307 case 1: /* Linear Interpolation (1X scale) */
308 state->interpolation = LINEARx1;
309 break;
310 case 2: /* Clockwise Linear Interpolation */
311 state->interpolation = CW_CIRCULAR;
312 break;
313 case 3: /* Counter Clockwise Linear Interpolation */
314 state->interpolation = CCW_CIRCULAR;
315 break;
316 case 4: /* Ignore Data Block */
317 /* Don't do anything, just read 'til * */
318 while (gerb_fgetc(fd) != '*');
319 break;
320 case 10: /* Linear Interpolation (10X scale) */
321 state->interpolation = LINEARx10;
322 break;
323 case 11: /* Linear Interpolation (0.1X scale) */
324 state->interpolation = LINEARx01;
325 break;
326 case 12: /* Linear Interpolation (0.01X scale) */
327 state->interpolation = LINEARx001;
328 break;
329 case 36: /* Turn on Polygon Area Fill */
330 state->prev_interpolation = state->interpolation;
331 state->interpolation = PAREA_START;
332 state->changed = 1;
333 break;
334 case 37: /* Turn off Polygon Area Fill */
335 state->interpolation = PAREA_END;
336 state->changed = 1;
337 break;
338 case 54: /* Tool prepare */
339 if (gerb_fgetc(fd) == 'D')
340 state->curr_aperture = gerb_fgetint(fd);
341 else
342 err(1, "Strange code after G54\n");
343 break;
344 case 70: /* Specify inches */
345 NOT_IMPL(fd, "G70");
346 break;
347 case 71: /* Specify millimeters */
348 NOT_IMPL(fd, "G71");
349 break;
350 case 74: /* Disable 360 circular interpolation */
351 state->prev_interpolation = state->interpolation;
352 state->interpolation = MQ_END;
353 state->mq_on = 0;
354 break;
355 case 75: /* Enable 360 circular interpolation */
356 state->prev_interpolation = state->interpolation;
357 state->interpolation = MQ_START;
358 state->mq_on = 1;
359 break;
360 case 90: /* Specify absolut format */
361 if (format) format->coordinate = ABSOLUTE;
362 break;
363 case 91: /* Specify incremental format */
364 if (format) format->coordinate = INCREMENTAL;
365 break;
366 default:
367 err(1, "Strange/unhandled G code : %c%c\n", op[0], op[1]);
370 return;
371 } /* parse_G_code */
374 static void
375 parse_D_code(gerb_file_t *fd, gerb_state_t *state)
377 int a;
379 a = gerb_fgetint(fd);
380 switch(a) {
381 case 1 : /* Exposure on */
382 state->aperture_state = ON;
383 state->changed = 1;
384 break;
385 case 2 : /* Exposure off */
386 state->aperture_state = OFF;
387 state->changed = 1;
388 break;
389 case 3 : /* Flash aperture */
390 state->aperture_state = FLASH;
391 state->changed = 1;
392 break;
393 default: /* Aperture in use */
394 if ((a >= APERTURE_MIN) && (a <= APERTURE_MAX))
395 state->curr_aperture = a;
396 else
397 err(1, "Aperture out of bounds:%d\n", a);
398 state->changed = 0;
401 return;
402 } /* parse_D_code */
405 static int
406 parse_M_code(gerb_file_t *fd)
408 int op[2];
410 op[0] = gerb_fgetc(fd);
411 op[1] = gerb_fgetc(fd);
413 if ((op[0] == EOF) || (op[1] == EOF))
414 err(1, "Unexpected EOF found.\n");
416 if (op[0] != (int)'0')
417 err(1, "Strange M code [%c%c]\n", (char)op[0], (char)op[1]);
419 switch (op[1]) {
420 case '0': /* Program stop */
421 return 1;
422 case '1': /* Optional stop */
423 return 2;
424 case '2': /* End of program */
425 return 3;
426 default:
427 err(1, "Strange M code [%c%c]\n", (char)op[0], (char)op[1]);
429 } /* parse_M_code */
432 static void
433 parse_rs274x(gerb_file_t *fd, gerb_image_t *image, gerb_state_t *state)
435 int op[2];
436 char str[3];
437 gerb_aperture_t *a = NULL;
438 amacro_t *tmp_amacro;
439 int ano;
441 op[0] = gerb_fgetc(fd);
442 op[1] = gerb_fgetc(fd);
444 if ((op[0] == EOF) || (op[1] == EOF))
445 err(1, "Unexpected EOF found.\n");
447 switch (A2I(op[0], op[1])){
449 /* Directive parameters */
450 case A2I('A','S'): /* Axis Select */
451 op[0] = gerb_fgetc(fd);
452 op[1] = gerb_fgetc(fd);
454 if ((op[0] == EOF) || (op[1] == EOF))
455 err(1, "Unexpected EOF found.\n");
457 if (((op[0] == 'A') && (op[1] == 'Y')) ||
458 ((op[0] == 'B') && (op[1] == 'X'))) {
459 NOT_IMPL(fd, "%MI with reversed axis not supported%");
460 break;
463 op[0] = gerb_fgetc(fd);
464 op[1] = gerb_fgetc(fd);
466 if ((op[0] == EOF) || (op[1] == EOF))
467 err(1, "Unexpected EOF found.\n");
469 if (((op[0] == 'A') && (op[1] == 'Y')) ||
470 ((op[0] == 'B') && (op[1] == 'X'))) {
471 NOT_IMPL(fd, "%MI with reversed axis not supported%");
472 break;
474 break;
475 case A2I('F','S'): /* Format Statement */
476 image->format = (gerb_format_t *)malloc(sizeof(gerb_format_t));
477 if (image->format == NULL)
478 err(1, "Failed malloc for format\n");
479 memset((void *)image->format, 0, sizeof(gerb_format_t));
481 switch (gerb_fgetc(fd)) {
482 case 'L':
483 image->format->omit_zeros = LEADING;
484 break;
485 case 'T':
486 image->format->omit_zeros = TRAILING;
487 break;
488 case 'D':
489 image->format->omit_zeros = EXPLICIT;
490 break;
491 default:
492 fprintf(stderr,"EagleCad bug detected: Defaults to omit leading zeroes\n");
493 gerb_ungetc(fd);
494 image->format->omit_zeros = LEADING;
497 switch (gerb_fgetc(fd)) {
498 case 'A':
499 image->format->coordinate = ABSOLUTE;
500 break;
501 case 'T':
502 image->format->coordinate = INCREMENTAL;
503 break;
504 default:
505 err(1, "Format error: coordinate = %c\n", op[0]);
508 while((op[0] = gerb_fgetc(fd)) != '*') {
509 switch (op[0]) {
510 case 'N':
511 op[0] = (char)gerb_fgetc(fd);
512 image->format->lim_seqno = op[0] - '0';
513 break;
514 case 'G':
515 op[0] = (char)gerb_fgetc(fd);
516 image->format->lim_gf = op[0] - '0';
517 break;
518 case 'D':
519 op[0] = (char)gerb_fgetc(fd);
520 image->format->lim_pf = op[0] - '0';
521 break;
522 case 'M':
523 op[0] = (char)gerb_fgetc(fd);
524 image->format->lim_mf = op[0] - '0';
525 break;
526 case 'X' :
527 op[0] = gerb_fgetc(fd);
528 if ((op[0] < '0') || (op[0] > '6'))
529 err(1, "Illegal format size : %c\n", (char)op[0]);
530 image->format->x_int = op[0] - '0';
531 op[0] = gerb_fgetc(fd);
532 if ((op[0] < '0') || (op[0] > '6'))
533 err(1, "Illegal format size : %c\n", (char)op[0]);
534 image->format->x_dec = op[0] - '0';
535 break;
536 case 'Y':
537 op[0] = gerb_fgetc(fd);
538 if ((op[0] < '0') || (op[0] > '6'))
539 err(1, "Illegal format size : %c\n", (char)op[0]);
540 image->format->y_int = op[0] - '0';
541 op[0] = gerb_fgetc(fd);
542 if ((op[0] < '0') || (op[0] > '6'))
543 err(1, "Illegal format size : %c\n", (char)op[0]);
544 image->format->y_dec = op[0] - '0';
545 break;
546 default :
547 fprintf(stderr, "Not handled type of format statement [%c]\n", op[0]);
550 break;
551 case A2I('M','I'): /* Mirror Image */
552 NOT_IMPL(fd, "%MI%");
553 break;
554 case A2I('M','O'): /* Mode of Units */
556 op[0] = gerb_fgetc(fd);
557 op[1] = gerb_fgetc(fd);
559 if ((op[0] == EOF) || (op[1] == EOF))
560 err(1, "Unexpected EOF found.\n");
562 switch (A2I(op[0],op[1])) {
563 case A2I('I','N'):
564 image->info->unit = INCH;
565 break;
566 case A2I('M','M'):
567 image->info->unit = MM;
568 break;
569 default:
570 err(1, "Illegal unit:%c%c\n", op[0], op[1]);
572 break;
573 case A2I('O','F'): /* Offset */
574 op[0] = gerb_fgetc(fd);
575 while (op[0] != '*') {
576 switch (op[0]) {
577 case 'A' :
578 image->info->offset_a = gerb_fgetdouble(fd);
579 break;
580 case 'B' :
581 image->info->offset_b = gerb_fgetdouble(fd);
582 break;
583 default :
584 err(1, "Wrong character in offset:%c\n", op[0]);
586 op[0] = gerb_fgetc(fd);
588 return;
589 case A2I('S','F'): /* Scale Factor */
590 if (gerb_fgetc(fd) == 'A')
591 image->info->scale_factor_A = gerb_fgetdouble(fd);
592 else
593 gerb_ungetc(fd);
594 if (gerb_fgetc(fd) == 'B')
595 image->info->scale_factor_B = gerb_fgetdouble(fd);
596 else
597 gerb_ungetc(fd);
598 if ((fabs(image->info->scale_factor_A - 1.0) > 0.00001) ||
599 (fabs(image->info->scale_factor_B - 1.0) > 0.00001))
600 NOT_IMPL(fd, "%SF% != 1.0");
601 break;
602 case A2I('I','C'): /* Input Code */
603 /* Thanks to Stephen Adam for providing this information. As he writes:
604 * btw, here's a logic puzzle for you. If you need to
605 * read the gerber file to see how it's encoded, then
606 * how can you read it?
608 op[0] = gerb_fgetc(fd);
609 op[1] = gerb_fgetc(fd);
611 if ((op[0] == EOF) || (op[1] == EOF))
612 err(1, "Unexpected EOF found.\n");
614 switch (A2I(op[0],op[1])) {
615 case A2I('A','S'):
616 image->info->encoding = ASCII;
617 break;
618 case A2I('E','B'):
619 image->info->encoding = EBCDIC;
620 break;
621 case A2I('B','C'):
622 image->info->encoding = BCD;
623 break;
624 case A2I('I','S'):
625 image->info->encoding = ISO_ASCII;
626 break;
627 case A2I('E','I'):
628 image->info->encoding = EIA;
629 break;
630 default:
631 err(1, "Strange inputcode : %c%c\n", op[0], op[1]);
633 break;
635 /* Image parameters */
636 case A2I('I','J'): /* Image Justify */
637 NOT_IMPL(fd, "%IJ%");
638 break;
639 case A2I('I','N'): /* Image Name */
640 image->info->name = gerb_fgetstring(fd, '*');
641 break;
642 case A2I('I','O'): /* Image Offset */
643 NOT_IMPL(fd, "%IO%");
644 break;
645 case A2I('I','P'): /* Image Polarity */
647 for (ano = 0; ano < 3; ano++) {
648 op[0] = gerb_fgetc(fd);
649 if (op[0] == EOF)
650 err(1, "Unexpected EOF found.\n");
651 str[ano] = (char)op[0];
654 if (strncmp(str, "POS", 3) == 0)
655 image->info->polarity = POSITIVE;
656 else if (strncmp(str, "NEG", 3) == 0)
657 image->info->polarity = NEGATIVE;
658 else
659 err(1, "Strange polarity : %c%c%c\n", str[0], str[1], str[2]);
661 break;
662 case A2I('I','R'): /* Image Rotation */
663 NOT_IMPL(fd, "%IR%");
664 break;
665 case A2I('P','F'): /* Plotter Film */
666 NOT_IMPL(fd, "%PF%");
667 break;
669 /* Aperture parameters */
670 case A2I('A','D'): /* Aperture Description */
671 a = (gerb_aperture_t *)malloc(sizeof(gerb_aperture_t));
672 memset((void *)a, 0, sizeof(gerb_aperture_t));
673 ano = parse_aperture_definition(fd, a, image->amacro);
674 if ((ano >= APERTURE_MIN) && (ano <= APERTURE_MAX))
675 image->aperture[ano] = a;
676 else
677 err(1, "Aperture number out of bounds : %d\n", ano);
678 break;
679 case A2I('A','M'): /* Aperture Macro */
680 tmp_amacro = image->amacro;
681 image->amacro = parse_aperture_macro(fd);
682 image->amacro->next = tmp_amacro;
683 #ifdef AMACRO_DEBUG
684 print_program(image->amacro);
685 #endif
686 break;
688 /* Layer */
689 case A2I('L','N'): /* Layer Name */
690 state->curr_layername = gerb_fgetstring(fd, '*');
691 break;
692 case A2I('L','P'): /* Layer Polarity */
693 switch (gerb_fgetc(fd)) {
694 case 'D': /* Dark Polarity (default) */
695 state->layer_polarity = DARK;
696 break;
697 case 'C': /* Clear Polarity */
698 state->layer_polarity = CLEAR;
699 break;
700 default:
701 fprintf(stderr, "Strange Layer Polarity: %c\n", op[0]);
703 break;
704 case A2I('K','O'): /* Knock Out */
705 NOT_IMPL(fd, "%KO%");
706 break;
707 case A2I('S','R'): /* Step and Repeat */
708 op[0] = gerb_fgetc(fd);
709 if (op[0] != 'X')
710 fprintf(stderr, "Step-and-repeat parameter error\n");
711 image->info->step_and_repeat_X = gerb_fgetint(fd);
713 op[0] = gerb_fgetc(fd);
714 if (op[0] != 'Y')
715 fprintf(stderr, "Step-and-repeat parameter error\n");
716 image->info->step_and_repeat_Y = gerb_fgetint(fd);
718 op[0] = gerb_fgetc(fd);
719 if (op[0] != 'I')
720 fprintf(stderr, "Step-and-repeat parameter error\n");
721 image->info->step_and_repeat_dist_X = gerb_fgetdouble(fd);
723 op[0] = gerb_fgetc(fd);
724 if (op[0] != 'J')
725 fprintf(stderr, "Step-and-repeat parameter error\n");
726 image->info->step_and_repeat_dist_Y = gerb_fgetdouble(fd);
728 if ((image->info->step_and_repeat_X != 1) ||
729 (image->info->step_and_repeat_Y != 1) ||
730 (fabs(image->info->step_and_repeat_dist_X) > 0.000001) ||
731 (fabs(image->info->step_and_repeat_dist_Y) > 0.000001))
732 NOT_IMPL(fd, "%SR%");
733 break;
734 case A2I('R','O'): /* Rotate */
735 NOT_IMPL(fd, "%RO%");
736 break;
737 default:
738 fprintf(stderr, "Unknown extension found %%%c%c%%\n", op[0], op[1]);
741 return;
742 } /* parse_rs274x */
745 static int
746 parse_aperture_definition(gerb_file_t *fd, gerb_aperture_t *aperture,
747 amacro_t *amacro)
749 int ano, i;
750 char *ad;
751 char *token;
752 amacro_t *curr_amacro;
754 if (gerb_fgetc(fd) != 'D')
755 return -1;
758 * Get aperture no
760 ano = gerb_fgetint(fd);
763 * Read in the whole aperture defintion and tokenize it
765 ad = gerb_fgetstring(fd, '*');
766 token = strtok(ad, ",");
768 if (strlen(token) == 1) {
769 switch (token[0]) {
770 case 'C':
771 aperture->type = CIRCLE;
772 break;
773 case 'R' :
774 aperture->type = RECTANGLE;
775 break;
776 case 'O' :
777 aperture->type = OVAL;
778 break;
779 case 'P' :
780 aperture->type = POLYGON;
781 break;
783 /* Here a should a T be defined, but I don't know what it represents */
784 } else {
785 aperture->type = MACRO;
787 * In aperture definition, point to the aperture macro
788 * used in the defintion
790 curr_amacro = amacro;
791 while (curr_amacro) {
792 if ((strlen(curr_amacro->name) == strlen(token)) &&
793 (strcmp(curr_amacro->name, token) == 0)) {
794 aperture->amacro = curr_amacro;
795 break;
797 curr_amacro = curr_amacro->next;
802 * Parse all parameters
804 for (token = strtok(NULL, "X"), i = 0; token != NULL;
805 token = strtok(NULL, "X"), i++)
806 aperture->parameter[i] = strtod(token, NULL);
808 aperture->nuf_parameters = i;
810 gerb_ungetc(fd);
812 free(ad);
814 return ano;
815 } /* parse_aperture_definition */
818 static void
819 calc_cirseg_sq(struct gerb_net *net, int cw,
820 double delta_cp_x, double delta_cp_y)
822 double d1x, d1y, d2x, d2y;
823 double alfa, beta;
824 int quadrant = 0;
828 * Quadrant detection (based on ccw, coverted below if cw)
829 * Y ^
830 * /!\
832 * ---->X
834 if (net->start_x > net->stop_x)
835 /* 1st and 2nd quadrant */
836 if (net->start_y < net->stop_y)
837 quadrant = 1;
838 else
839 quadrant = 2;
840 else
841 /* 3rd and 4th quadrant */
842 if (net->start_y > net->stop_y)
843 quadrant = 3;
844 else
845 quadrant = 4;
848 * If clockwise, rotate quadrant
850 if (cw) {
851 switch (quadrant) {
852 case 1 :
853 quadrant = 3;
854 break;
855 case 2 :
856 quadrant = 4;
857 break;
858 case 3 :
859 quadrant = 1;
860 break;
861 case 4 :
862 quadrant = 2;
863 break;
864 default :
865 err(1, "Unknow quadrant value while converting to cw\n");
870 * Calculate arc center point
872 switch (quadrant) {
873 case 1 :
874 net->cirseg->cp_x = net->start_x - delta_cp_x;
875 net->cirseg->cp_y = net->start_y - delta_cp_y;
876 break;
877 case 2 :
878 net->cirseg->cp_x = net->start_x + delta_cp_x;
879 net->cirseg->cp_y = net->start_y - delta_cp_y;
880 break;
881 case 3 :
882 net->cirseg->cp_x = net->start_x + delta_cp_x;
883 net->cirseg->cp_y = net->start_y + delta_cp_y;
884 break;
885 case 4 :
886 net->cirseg->cp_x = net->start_x - delta_cp_x;
887 net->cirseg->cp_y = net->start_y + delta_cp_y;
888 break;
889 default :
890 err(1, "Strange quadrant : %d\n", quadrant);
894 * Some good values
896 d1x = fabs(net->start_x - net->cirseg->cp_x);
897 d1y = fabs(net->start_y - net->cirseg->cp_y);
898 d2x = fabs(net->stop_x - net->cirseg->cp_x);
899 d2y = fabs(net->stop_y - net->cirseg->cp_y);
901 alfa = atan2(d1y, d1x);
902 beta = atan2(d2y, d2x);
905 * Avoid divide by zero when sin(0) = 0 and cos(90) = 0
907 net->cirseg->width = alfa < beta ?
908 2 * (d1x / cos(alfa)) : 2 * (d2x / cos(beta));
909 net->cirseg->height = alfa > beta ?
910 2 * (d1y / sin(alfa)) : 2 * (d2y / sin(beta));
912 if (alfa < 0.000001 && beta < 0.000001) {
913 net->cirseg->height = 0;
916 #define RAD2DEG(a) (int)ceil(a * 180 / M_PI)
918 switch (quadrant) {
919 case 1 :
920 net->cirseg->angle1 = RAD2DEG(alfa);
921 net->cirseg->angle2 = RAD2DEG(beta);
922 break;
923 case 2 :
924 net->cirseg->angle1 = 180 - RAD2DEG(alfa);
925 net->cirseg->angle2 = 180 - RAD2DEG(beta);
926 break;
927 case 3 :
928 net->cirseg->angle1 = 180 + RAD2DEG(alfa);
929 net->cirseg->angle2 = 180 + RAD2DEG(beta);
930 break;
931 case 4 :
932 net->cirseg->angle1 = 360 - RAD2DEG(alfa);
933 net->cirseg->angle2 = 360 - RAD2DEG(beta);
934 break;
935 default :
936 err(1, "Strange quadrant : %d\n", quadrant);
939 if (net->cirseg->width < 0.0)
940 fprintf(stderr, "Negative width [%f] in quadrant %d [%f][%f]\n",
941 net->cirseg->width, quadrant, alfa, beta);
943 if (net->cirseg->height < 0.0)
944 fprintf(stderr, "Negative height [%f] in quadrant %d [%d][%d]\n",
945 net->cirseg->height, quadrant, RAD2DEG(alfa), RAD2DEG(beta));
947 return;
949 } /* calc_cirseg_sq */
952 static void
953 calc_cirseg_mq(struct gerb_net *net, int cw,
954 double delta_cp_x, double delta_cp_y)
956 double d1x, d1y, d2x, d2y;
957 double alfa, beta;
959 net->cirseg->cp_x = net->start_x + delta_cp_x;
960 net->cirseg->cp_y = net->start_y + delta_cp_y;
963 * Some good values
965 d1x = net->start_x - net->cirseg->cp_x;
966 d1y = net->start_y - net->cirseg->cp_y;
967 d2x = net->stop_x - net->cirseg->cp_x;
968 d2y = net->stop_y - net->cirseg->cp_y;
970 alfa = atan2(d1y, d1x);
971 beta = atan2(d2y, d2x);
973 net->cirseg->width = sqrt(delta_cp_x*delta_cp_x + delta_cp_y*delta_cp_y);
974 net->cirseg->width *= 2.0;
975 net->cirseg->height = net->cirseg->width;
977 net->cirseg->angle1 = RAD2DEG(alfa);
978 net->cirseg->angle2 = RAD2DEG(beta);
981 * Make sure it's always positive angles
983 if (net->cirseg->angle1 < 0) {
984 net->cirseg->angle1 = 360 + net->cirseg->angle1;
985 net->cirseg->angle2 = 360 + net->cirseg->angle2;
988 if (net->cirseg->angle2 < 0)
989 net->cirseg->angle2 = 360 + net->cirseg->angle2;
991 if(net->cirseg->angle2 == 0)
992 net->cirseg->angle2 = 360;
995 * If angles are equal it should be a circle, but as gerbv
996 * currently is designed it becomes a point. Maybe I should
997 * save start angle and how many degrees to draw?
999 if ((net->cirseg->angle2 - net->cirseg->angle1) == 0)
1000 net->cirseg->angle2 = 360 + net->cirseg->angle2;
1002 return;
1003 } /* calc_cirseg_mq */