2 * gEDA - GNU Electronic Design Automation
3 * This is a part of gerbv
5 * Copyright (C) 2000-2002 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() */
31 #define NOT_IMPL(fd, s) do { \
32 fprintf(stderr, "Not Implemented:%s\n", s); \
33 while (gerb_fgetc(fd) != (int)'*'); \
38 #define err(errcode, a...) \
40 fprintf(stderr, ##a); \
45 #define A2I(a,b) (((a & 0xff) << 8) + (b & 0xff))
47 typedef struct gerb_state
{
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
;
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
,
74 static int parse_aperture_definition(gerb_file_t
*fd
,
75 gerb_aperture_t
*aperture
,
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
);
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
;
90 double x_scale
= 0.0, y_scale
= 0.0;
91 double delta_cp_x
= 0.0, delta_cp_y
= 0.0;
94 state
= (gerb_state_t
*)malloc(sizeof(gerb_state_t
));
96 err(1, "malloc state failed\n");
101 memset((void *)state
, 0, sizeof(gerb_state_t
));
102 state
->layer_polarity
= DARK
;
107 image
= new_gerb_image(image
);
109 err(1, "malloc image failed\n");
110 curr_net
= image
->netlist
;
115 while ((read
= gerb_fgetc(fd
)) != EOF
) {
116 switch ((char)(read
& 0xff)) {
118 parse_G_code(fd
, state
, image
->format
);
121 parse_D_code(fd
, state
);
124 switch(parse_M_code(fd
)) {
132 err(1, "Strange M code found.\n");
136 state
->curr_x
= gerb_fgetint(fd
);
140 state
->curr_y
= gerb_fgetint(fd
);
144 state
->delta_cp_x
= gerb_fgetint(fd
);
148 state
->delta_cp_y
= gerb_fgetint(fd
);
152 parse_rs274x(fd
, image
, state
);
153 while (gerb_fgetc(fd
) != '%');
156 if (state
->changed
== 0) break;
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
) {
181 curr_net
->cirseg
= (gerb_cirseg_t
*)malloc(sizeof(gerb_cirseg_t
));
182 memset((void *)curr_net
->cirseg
, 0, sizeof(gerb_cirseg_t
));
184 calc_cirseg_mq(curr_net
, 1, delta_cp_x
, delta_cp_y
);
186 calc_cirseg_sq(curr_net
, 1, delta_cp_x
, delta_cp_y
);
189 curr_net
->cirseg
= (gerb_cirseg_t
*)malloc(sizeof(gerb_cirseg_t
));
190 memset((void *)curr_net
->cirseg
, 0, sizeof(gerb_cirseg_t
));
192 calc_cirseg_mq(curr_net
, 0, delta_cp_x
, delta_cp_y
);
194 calc_cirseg_sq(curr_net
, 0, delta_cp_x
, delta_cp_y
);
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;
204 state
->parea_start_node
= NULL
;
205 state
->in_parea_fill
= 0;
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];
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
;
268 case 10 : /* White space */
274 fprintf(stderr
, "Found unknown character (whitespace?) %c[%d]\n", read
, read
);
278 fprintf(stderr
, "File is missing gerber End-Of-File\n");
285 parse_G_code(gerb_file_t
*fd
, gerb_state_t
*state
, gerb_format_t
*format
)
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');
305 /* Is this doing anything really? */
307 case 1: /* Linear Interpolation (1X scale) */
308 state
->interpolation
= LINEARx1
;
310 case 2: /* Clockwise Linear Interpolation */
311 state
->interpolation
= CW_CIRCULAR
;
313 case 3: /* Counter Clockwise Linear Interpolation */
314 state
->interpolation
= CCW_CIRCULAR
;
316 case 4: /* Ignore Data Block */
317 /* Don't do anything, just read 'til * */
318 while (gerb_fgetc(fd
) != '*');
320 case 10: /* Linear Interpolation (10X scale) */
321 state
->interpolation
= LINEARx10
;
323 case 11: /* Linear Interpolation (0.1X scale) */
324 state
->interpolation
= LINEARx01
;
326 case 12: /* Linear Interpolation (0.01X scale) */
327 state
->interpolation
= LINEARx001
;
329 case 36: /* Turn on Polygon Area Fill */
330 state
->prev_interpolation
= state
->interpolation
;
331 state
->interpolation
= PAREA_START
;
334 case 37: /* Turn off Polygon Area Fill */
335 state
->interpolation
= PAREA_END
;
338 case 54: /* Tool prepare */
339 if (gerb_fgetc(fd
) == 'D')
340 state
->curr_aperture
= gerb_fgetint(fd
);
342 err(1, "Strange code after G54\n");
344 case 70: /* Specify inches */
347 case 71: /* Specify millimeters */
350 case 74: /* Disable 360 circular interpolation */
351 state
->prev_interpolation
= state
->interpolation
;
352 state
->interpolation
= MQ_END
;
355 case 75: /* Enable 360 circular interpolation */
356 state
->prev_interpolation
= state
->interpolation
;
357 state
->interpolation
= MQ_START
;
360 case 90: /* Specify absolut format */
361 if (format
) format
->coordinate
= ABSOLUTE
;
363 case 91: /* Specify incremental format */
364 if (format
) format
->coordinate
= INCREMENTAL
;
367 err(1, "Strange/unhandled G code : %c%c\n", op
[0], op
[1]);
375 parse_D_code(gerb_file_t
*fd
, gerb_state_t
*state
)
379 a
= gerb_fgetint(fd
);
381 case 1 : /* Exposure on */
382 state
->aperture_state
= ON
;
385 case 2 : /* Exposure off */
386 state
->aperture_state
= OFF
;
389 case 3 : /* Flash aperture */
390 state
->aperture_state
= FLASH
;
393 default: /* Aperture in use */
394 if ((a
>= APERTURE_MIN
) && (a
<= APERTURE_MAX
))
395 state
->curr_aperture
= a
;
397 err(1, "Aperture out of bounds:%d\n", a
);
406 parse_M_code(gerb_file_t
*fd
)
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]);
420 case '0': /* Program stop */
422 case '1': /* Optional stop */
424 case '2': /* End of program */
427 err(1, "Strange M code [%c%c]\n", (char)op
[0], (char)op
[1]);
433 parse_rs274x(gerb_file_t
*fd
, gerb_image_t
*image
, gerb_state_t
*state
)
437 gerb_aperture_t
*a
= NULL
;
438 amacro_t
*tmp_amacro
;
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%");
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%");
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
)) {
483 image
->format
->omit_zeros
= LEADING
;
486 image
->format
->omit_zeros
= TRAILING
;
489 image
->format
->omit_zeros
= EXPLICIT
;
492 fprintf(stderr
,"EagleCad bug detected: Defaults to omit leading zeroes\n");
494 image
->format
->omit_zeros
= LEADING
;
497 switch (gerb_fgetc(fd
)) {
499 image
->format
->coordinate
= ABSOLUTE
;
502 image
->format
->coordinate
= INCREMENTAL
;
505 err(1, "Format error: coordinate = %c\n", op
[0]);
508 while((op
[0] = gerb_fgetc(fd
)) != '*') {
511 op
[0] = (char)gerb_fgetc(fd
);
512 image
->format
->lim_seqno
= op
[0] - '0';
515 op
[0] = (char)gerb_fgetc(fd
);
516 image
->format
->lim_gf
= op
[0] - '0';
519 op
[0] = (char)gerb_fgetc(fd
);
520 image
->format
->lim_pf
= op
[0] - '0';
523 op
[0] = (char)gerb_fgetc(fd
);
524 image
->format
->lim_mf
= op
[0] - '0';
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';
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';
547 fprintf(stderr
, "Not handled type of format statement [%c]\n", op
[0]);
551 case A2I('M','I'): /* Mirror Image */
552 NOT_IMPL(fd
, "%MI%");
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])) {
564 image
->info
->unit
= INCH
;
567 image
->info
->unit
= MM
;
570 err(1, "Illegal unit:%c%c\n", op
[0], op
[1]);
573 case A2I('O','F'): /* Offset */
574 op
[0] = gerb_fgetc(fd
);
575 while (op
[0] != '*') {
578 image
->info
->offset_a
= gerb_fgetdouble(fd
);
581 image
->info
->offset_b
= gerb_fgetdouble(fd
);
584 err(1, "Wrong character in offset:%c\n", op
[0]);
586 op
[0] = gerb_fgetc(fd
);
589 case A2I('S','F'): /* Scale Factor */
590 if (gerb_fgetc(fd
) == 'A')
591 image
->info
->scale_factor_A
= gerb_fgetdouble(fd
);
594 if (gerb_fgetc(fd
) == 'B')
595 image
->info
->scale_factor_B
= gerb_fgetdouble(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");
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])) {
616 image
->info
->encoding
= ASCII
;
619 image
->info
->encoding
= EBCDIC
;
622 image
->info
->encoding
= BCD
;
625 image
->info
->encoding
= ISO_ASCII
;
628 image
->info
->encoding
= EIA
;
631 err(1, "Strange inputcode : %c%c\n", op
[0], op
[1]);
635 /* Image parameters */
636 case A2I('I','J'): /* Image Justify */
637 NOT_IMPL(fd
, "%IJ%");
639 case A2I('I','N'): /* Image Name */
640 image
->info
->name
= gerb_fgetstring(fd
, '*');
642 case A2I('I','O'): /* Image Offset */
643 NOT_IMPL(fd
, "%IO%");
645 case A2I('I','P'): /* Image Polarity */
647 for (ano
= 0; ano
< 3; ano
++) {
648 op
[0] = gerb_fgetc(fd
);
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
;
659 err(1, "Strange polarity : %c%c%c\n", str
[0], str
[1], str
[2]);
662 case A2I('I','R'): /* Image Rotation */
663 NOT_IMPL(fd
, "%IR%");
665 case A2I('P','F'): /* Plotter Film */
666 NOT_IMPL(fd
, "%PF%");
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
;
677 err(1, "Aperture number out of bounds : %d\n", ano
);
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
;
684 print_program(image
->amacro
);
689 case A2I('L','N'): /* Layer Name */
690 state
->curr_layername
= gerb_fgetstring(fd
, '*');
692 case A2I('L','P'): /* Layer Polarity */
693 switch (gerb_fgetc(fd
)) {
694 case 'D': /* Dark Polarity (default) */
695 state
->layer_polarity
= DARK
;
697 case 'C': /* Clear Polarity */
698 state
->layer_polarity
= CLEAR
;
701 fprintf(stderr
, "Strange Layer Polarity: %c\n", op
[0]);
704 case A2I('K','O'): /* Knock Out */
705 NOT_IMPL(fd
, "%KO%");
707 case A2I('S','R'): /* Step and Repeat */
708 op
[0] = gerb_fgetc(fd
);
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
);
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
);
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
);
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%");
734 case A2I('R','O'): /* Rotate */
735 NOT_IMPL(fd
, "%RO%");
738 fprintf(stderr
, "Unknown extension found %%%c%c%%\n", op
[0], op
[1]);
746 parse_aperture_definition(gerb_file_t
*fd
, gerb_aperture_t
*aperture
,
752 amacro_t
*curr_amacro
;
754 if (gerb_fgetc(fd
) != 'D')
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) {
771 aperture
->type
= CIRCLE
;
774 aperture
->type
= RECTANGLE
;
777 aperture
->type
= OVAL
;
780 aperture
->type
= POLYGON
;
783 /* Here a should a T be defined, but I don't know what it represents */
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
;
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
;
815 } /* parse_aperture_definition */
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
;
828 * Quadrant detection (based on ccw, coverted below if cw)
834 if (net
->start_x
> net
->stop_x
)
835 /* 1st and 2nd quadrant */
836 if (net
->start_y
< net
->stop_y
)
841 /* 3rd and 4th quadrant */
842 if (net
->start_y
> net
->stop_y
)
848 * If clockwise, rotate quadrant
865 err(1, "Unknow quadrant value while converting to cw\n");
870 * Calculate arc center point
874 net
->cirseg
->cp_x
= net
->start_x
- delta_cp_x
;
875 net
->cirseg
->cp_y
= net
->start_y
- delta_cp_y
;
878 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
879 net
->cirseg
->cp_y
= net
->start_y
- delta_cp_y
;
882 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
883 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
886 net
->cirseg
->cp_x
= net
->start_x
- delta_cp_x
;
887 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
890 err(1, "Strange quadrant : %d\n", quadrant
);
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)
920 net
->cirseg
->angle1
= RAD2DEG(alfa
);
921 net
->cirseg
->angle2
= RAD2DEG(beta
);
924 net
->cirseg
->angle1
= 180 - RAD2DEG(alfa
);
925 net
->cirseg
->angle2
= 180 - RAD2DEG(beta
);
928 net
->cirseg
->angle1
= 180 + RAD2DEG(alfa
);
929 net
->cirseg
->angle2
= 180 + RAD2DEG(beta
);
932 net
->cirseg
->angle1
= 360 - RAD2DEG(alfa
);
933 net
->cirseg
->angle2
= 360 - RAD2DEG(beta
);
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
));
949 } /* calc_cirseg_sq */
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
;
959 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
960 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
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
;
1003 } /* calc_cirseg_mq */