2 * gEDA - GNU Electronic Design Automation
3 * This is a part of gerbv
5 * Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
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
26 #include <math.h> /* pow() */
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)'*'); \
38 #define A2I(a,b) (((a & 0xff) << 8) + (b & 0xff))
40 typedef struct gerb_state
{
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
;
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
,
68 static int parse_aperture_definition(gerb_file_t
*fd
,
69 gerb_aperture_t
*aperture
,
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
);
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
;
85 double x_scale
= 0.0, y_scale
= 0.0;
86 double delta_cp_x
= 0.0, delta_cp_y
= 0.0;
90 state
= (gerb_state_t
*)malloc(sizeof(gerb_state_t
));
92 GERB_FATAL_ERROR("malloc state failed\n");
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
109 image
= new_gerb_image(image
);
111 GERB_FATAL_ERROR("malloc image failed\n");
112 curr_net
= image
->netlist
;
117 while ((read
= gerb_fgetc(fd
)) != EOF
) {
118 switch ((char)(read
& 0xff)) {
120 parse_G_code(fd
, state
, image
->format
);
123 parse_D_code(fd
, state
);
126 switch(parse_M_code(fd
)) {
134 GERB_FATAL_ERROR("Strange M code found.\n");
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
) {
157 if (image
->format
&& (image
->format
->coordinate
==INCREMENTAL
))
158 state
->curr_x
+= coord
;
160 state
->curr_x
= coord
;
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
) {
183 if (image
->format
&& (image
->format
->coordinate
==INCREMENTAL
))
184 state
->curr_y
+= coord
;
186 state
->curr_y
= coord
;
190 state
->delta_cp_x
= gerb_fgetint(fd
, NULL
);
194 state
->delta_cp_y
= gerb_fgetint(fd
, NULL
);
198 parse_rs274x(fd
, image
, state
);
199 while (gerb_fgetc(fd
) != '%');
202 if (state
->changed
== 0) break;
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
) {
228 curr_net
->cirseg
= (gerb_cirseg_t
*)malloc(sizeof(gerb_cirseg_t
));
229 memset((void *)curr_net
->cirseg
, 0, sizeof(gerb_cirseg_t
));
231 calc_cirseg_mq(curr_net
, 1, delta_cp_x
, delta_cp_y
);
233 calc_cirseg_sq(curr_net
, 1, delta_cp_x
, delta_cp_y
);
236 curr_net
->cirseg
= (gerb_cirseg_t
*)malloc(sizeof(gerb_cirseg_t
));
237 memset((void *)curr_net
->cirseg
, 0, sizeof(gerb_cirseg_t
));
239 calc_cirseg_mq(curr_net
, 0, delta_cp_x
, delta_cp_y
);
241 calc_cirseg_sq(curr_net
, 0, delta_cp_x
, delta_cp_y
);
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;
251 state
->parea_start_node
= NULL
;
252 state
->in_parea_fill
= 0;
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];
331 * Find min and max of image with compensation for mm.
333 if (curr_net
->unit
== MM
)
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
;
350 case 10 : /* White space */
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");
367 parse_G_code(gerb_file_t
*fd
, gerb_state_t
*state
, gerb_format_t
*format
)
371 op_int
=gerb_fgetint(fd
, NULL
);
375 /* Is this doing anything really? */
377 case 1: /* Linear Interpolation (1X scale) */
378 state
->interpolation
= LINEARx1
;
380 case 2: /* Clockwise Linear Interpolation */
381 state
->interpolation
= CW_CIRCULAR
;
383 case 3: /* Counter Clockwise Linear Interpolation */
384 state
->interpolation
= CCW_CIRCULAR
;
386 case 4: /* Ignore Data Block */
387 /* Don't do anything, just read 'til * */
388 while (gerb_fgetc(fd
) != '*');
390 case 10: /* Linear Interpolation (10X scale) */
391 state
->interpolation
= LINEARx10
;
393 case 11: /* Linear Interpolation (0.1X scale) */
394 state
->interpolation
= LINEARx01
;
396 case 12: /* Linear Interpolation (0.01X scale) */
397 state
->interpolation
= LINEARx001
;
399 case 36: /* Turn on Polygon Area Fill */
400 state
->prev_interpolation
= state
->interpolation
;
401 state
->interpolation
= PAREA_START
;
404 case 37: /* Turn off Polygon Area Fill */
405 state
->interpolation
= PAREA_END
;
408 case 54: /* Tool prepare */
409 /* XXX Maybe uneccesary??? */
410 if (gerb_fgetc(fd
) == 'D')
411 state
->curr_aperture
= gerb_fgetint(fd
, NULL
);
413 GERB_COMPILE_WARNING("Strange code after G54\n");
415 case 55: /* Prepare for flash */
417 case 70: /* Specify inches */
420 case 71: /* Specify millimeters */
423 case 74: /* Disable 360 circular interpolation */
426 case 75: /* Enable 360 circular interpolation */
429 case 90: /* Specify absolut format */
430 if (format
) format
->coordinate
= ABSOLUTE
;
432 case 91: /* Specify incremental format */
433 if (format
) format
->coordinate
= INCREMENTAL
;
436 GERB_COMPILE_ERROR("Strange/unhandled G code : %d\n", op_int
);
444 parse_D_code(gerb_file_t
*fd
, gerb_state_t
*state
)
448 a
= gerb_fgetint(fd
, NULL
);
450 case 1 : /* Exposure on */
451 state
->aperture_state
= ON
;
454 case 2 : /* Exposure off */
455 state
->aperture_state
= OFF
;
458 case 3 : /* Flash aperture */
459 state
->aperture_state
= FLASH
;
462 default: /* Aperture in use */
463 if ((a
>= APERTURE_MIN
) && (a
<= APERTURE_MAX
))
464 state
->curr_aperture
= a
;
466 GERB_COMPILE_ERROR("Aperture out of bounds:%d\n", a
);
475 parse_M_code(gerb_file_t
*fd
)
479 op_int
=gerb_fgetint(fd
, NULL
);
482 case 0: /* Program stop */
484 case 1: /* Optional stop */
486 case 2: /* End of program */
489 GERB_COMPILE_ERROR("Strange M code [%d]\n", op_int
);
496 parse_rs274x(gerb_file_t
*fd
, gerb_image_t
*image
, gerb_state_t
*state
)
501 gerb_aperture_t
*a
= NULL
;
502 amacro_t
*tmp_amacro
;
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%");
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%");
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
)) {
547 image
->format
->omit_zeros
= LEADING
;
550 image
->format
->omit_zeros
= TRAILING
;
553 image
->format
->omit_zeros
= EXPLICIT
;
556 GERB_MESSAGE("EagleCad bug detected: Defaults to omit leading zeroes\n");
558 image
->format
->omit_zeros
= LEADING
;
561 switch (gerb_fgetc(fd
)) {
563 image
->format
->coordinate
= ABSOLUTE
;
566 image
->format
->coordinate
= INCREMENTAL
;
569 GERB_COMPILE_ERROR("Format error: coordinate = %c\n", op
[0]);
572 while((op
[0] = gerb_fgetc(fd
)) != '*') {
575 op
[0] = (char)gerb_fgetc(fd
);
576 image
->format
->lim_seqno
= op
[0] - '0';
579 op
[0] = (char)gerb_fgetc(fd
);
580 image
->format
->lim_gf
= op
[0] - '0';
583 op
[0] = (char)gerb_fgetc(fd
);
584 image
->format
->lim_pf
= op
[0] - '0';
587 op
[0] = (char)gerb_fgetc(fd
);
588 image
->format
->lim_mf
= op
[0] - '0';
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';
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';
611 GERB_COMPILE_ERROR("Not handled type of format statement [%c]\n", op
[0]);
615 case A2I('M','I'): /* Mirror Image */
616 NOT_IMPL(fd
, "%MI%");
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])) {
634 GERB_COMPILE_ERROR("Illegal unit:%c%c\n", op
[0], op
[1]);
637 case A2I('O','F'): /* Offset */
638 op
[0] = gerb_fgetc(fd
);
639 while (op
[0] != '*') {
642 image
->info
->offset_a
= gerb_fgetdouble(fd
);
645 image
->info
->offset_b
= gerb_fgetdouble(fd
);
648 GERB_COMPILE_ERROR("Wrong character in offset:%c\n", op
[0]);
650 op
[0] = gerb_fgetc(fd
);
653 case A2I('S','F'): /* Scale Factor */
654 if (gerb_fgetc(fd
) == 'A')
655 image
->info
->scale_factor_A
= gerb_fgetdouble(fd
);
658 if (gerb_fgetc(fd
) == 'B')
659 image
->info
->scale_factor_B
= gerb_fgetdouble(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");
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])) {
680 image
->info
->encoding
= ASCII
;
683 image
->info
->encoding
= EBCDIC
;
686 image
->info
->encoding
= BCD
;
689 image
->info
->encoding
= ISO_ASCII
;
692 image
->info
->encoding
= EIA
;
695 GERB_COMPILE_ERROR("Strange inputcode : %c%c\n", op
[0], op
[1]);
699 /* Image parameters */
700 case A2I('I','J'): /* Image Justify */
701 NOT_IMPL(fd
, "%IJ%");
703 case A2I('I','N'): /* Image Name */
704 image
->info
->name
= gerb_fgetstring(fd
, '*');
706 case A2I('I','O'): /* Image Offset */
707 NOT_IMPL(fd
, "%IO%");
709 case A2I('I','P'): /* Image Polarity */
711 for (ano
= 0; ano
< 3; ano
++) {
712 op
[0] = gerb_fgetc(fd
);
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
;
723 GERB_COMPILE_ERROR("Strange polarity : %c%c%c\n", str
[0], str
[1], str
[2]);
726 case A2I('I','R'): /* Image Rotation */
727 tmp
= gerb_fgetint(fd
, NULL
);
729 NOT_IMPL(fd
, "%IR%");
731 case A2I('P','F'): /* Plotter Film */
732 NOT_IMPL(fd
, "%PF%");
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
;
744 GERB_COMPILE_ERROR("Aperture number out of bounds : %d\n", ano
);
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
;
751 print_program(image
->amacro
);
756 case A2I('L','N'): /* Layer Name */
757 state
->curr_layername
= gerb_fgetstring(fd
, '*');
759 case A2I('L','P'): /* Layer Polarity */
760 switch (gerb_fgetc(fd
)) {
761 case 'D': /* Dark Polarity (default) */
762 state
->layer_polarity
= DARK
;
764 case 'C': /* Clear Polarity */
765 state
->layer_polarity
= CLEAR
;
768 GERB_COMPILE_WARNING("Strange Layer Polarity: %c\n", op
[0]);
771 case A2I('K','O'): /* Knock Out */
772 NOT_IMPL(fd
, "%KO%");
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;
783 while (op
[0] != '*') {
786 image
->info
->step_and_repeat
.X
= gerb_fgetint(fd
, NULL
);
789 image
->info
->step_and_repeat
.Y
= gerb_fgetint(fd
, NULL
);
792 image
->info
->step_and_repeat
.dist_X
= gerb_fgetdouble(fd
);
795 image
->info
->step_and_repeat
.dist_Y
= gerb_fgetdouble(fd
);
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%");
808 case A2I('R','O'): /* Rotate */
809 NOT_IMPL(fd
, "%RO%");
812 GERB_COMPILE_ERROR("Unknown extension found %%%c%c%%\n", op
[0], op
[1]);
820 parse_aperture_definition(gerb_file_t
*fd
, gerb_aperture_t
*aperture
,
826 amacro_t
*curr_amacro
;
828 if (gerb_fgetc(fd
) != 'D')
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) {
845 aperture
->type
= CIRCLE
;
848 aperture
->type
= RECTANGLE
;
851 aperture
->type
= OVAL
;
854 aperture
->type
= POLYGON
;
857 /* Here a should a T be defined, but I don't know what it represents */
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
;
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
;
889 } /* parse_aperture_definition */
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
;
902 * Quadrant detection (based on ccw, converted below if cw)
908 if (net
->start_x
> net
->stop_x
)
909 /* 1st and 2nd quadrant */
910 if (net
->start_y
< net
->stop_y
)
915 /* 3rd and 4th quadrant */
916 if (net
->start_y
> net
->stop_y
)
922 * If clockwise, rotate quadrant
939 GERB_COMPILE_ERROR("Unknow quadrant value while converting to cw\n");
944 * Calculate arc center point
948 net
->cirseg
->cp_x
= net
->start_x
- delta_cp_x
;
949 net
->cirseg
->cp_y
= net
->start_y
- delta_cp_y
;
952 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
953 net
->cirseg
->cp_y
= net
->start_y
- delta_cp_y
;
956 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
957 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
960 net
->cirseg
->cp_x
= net
->start_x
- delta_cp_x
;
961 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
964 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant
);
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)
994 net
->cirseg
->angle1
= RAD2DEG(alfa
);
995 net
->cirseg
->angle2
= RAD2DEG(beta
);
998 net
->cirseg
->angle1
= 180.0 - RAD2DEG(alfa
);
999 net
->cirseg
->angle2
= 180.0 - RAD2DEG(beta
);
1002 net
->cirseg
->angle1
= 180.0 + RAD2DEG(alfa
);
1003 net
->cirseg
->angle2
= 180.0 + RAD2DEG(beta
);
1006 net
->cirseg
->angle1
= 360.0 - RAD2DEG(alfa
);
1007 net
->cirseg
->angle2
= 360.0 - RAD2DEG(beta
);
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
));
1023 } /* calc_cirseg_sq */
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
;
1033 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
1034 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
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.
1076 if (net
->cirseg
->angle1
<= net
->cirseg
->angle2
)
1077 net
->cirseg
->angle2
-= 360.0;
1079 if (net
->cirseg
->angle1
>= net
->cirseg
->angle2
)
1080 net
->cirseg
->angle2
+= 360.0;
1084 } /* calc_cirseg_mq */
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
;
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
1111 steps
= (int)(1.0 - angle_diff
);
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
;
1141 * increment the polygon corner count
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
;
1155 } /* gen_circle_segments */