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
25 \brief RS274X parsing functions
31 #include <math.h> /* pow() */
39 #include "gerb_image.h"
41 #include "gerb_stats.h"
44 //#define AMACRO_DEBUG
48 /* include this for macro enums */
51 /* DEBUG printing. #define DEBUG 1 in config.h to use this fcn. */
52 #define dprintf if(DEBUG) printf
54 //#define AMACRO_DEBUG
56 #define A2I(a,b) (((a & 0xff) << 8) + (b & 0xff))
60 /* Local function prototypes */
61 static void parse_G_code(gerb_file_t
*fd
, gerb_state_t
*state
,
62 gerbv_image_t
*image
);
63 static void parse_D_code(gerb_file_t
*fd
, gerb_state_t
*state
,
64 gerbv_image_t
*image
);
65 static int parse_M_code(gerb_file_t
*fd
, gerbv_image_t
*image
);
66 static void parse_rs274x(gint levelOfRecursion
, gerb_file_t
*fd
,
67 gerbv_image_t
*image
, gerb_state_t
*state
,
68 gerbv_net_t
*curr_net
, gerbv_stats_t
*stats
,
69 gchar
*directoryPath
);
70 static int parse_aperture_definition(gerb_file_t
*fd
,
71 gerbv_aperture_t
*aperture
,
72 gerbv_image_t
*image
, gdouble scale
);
73 static void calc_cirseg_sq(struct gerbv_net
*net
, int cw
,
74 double delta_cp_x
, double delta_cp_y
);
75 static void calc_cirseg_mq(struct gerbv_net
*net
, int cw
,
76 double delta_cp_x
, double delta_cp_y
);
79 static void gerber_update_any_running_knockout_measurements(gerbv_image_t
*image
);
81 static void gerber_calculate_final_justify_effects (gerbv_image_t
*image
);
83 gboolean knockoutMeasure
= FALSE
;
84 gdouble knockoutLimitXmin
, knockoutLimitYmin
, knockoutLimitXmax
,
86 gerbv_layer_t
*knockoutLayer
= NULL
;
87 cairo_matrix_t currentMatrix
;
90 /* --------------------------------------------------------- */
92 gerber_create_new_net (gerbv_net_t
*currentNet
, gerbv_layer_t
*layer
, gerbv_netstate_t
*state
){
93 gerbv_net_t
*newNet
= g_new0 (gerbv_net_t
, 1);
95 currentNet
->next
= newNet
;
97 newNet
->layer
= layer
;
99 newNet
->layer
= currentNet
->layer
;
101 newNet
->state
= state
;
103 newNet
->state
= currentNet
->state
;
107 /* --------------------------------------------------------- */
109 gerber_create_new_aperture (gerbv_image_t
*image
, int *indexNumber
,
110 gerbv_aperture_type_t apertureType
, gdouble parameter1
, gdouble parameter2
){
113 /* search for an available aperture spot */
114 for (i
= 0; i
<= APERTURE_MAX
; i
++) {
115 if (image
->aperture
[i
] == NULL
) {
116 image
->aperture
[i
] = g_new0 (gerbv_aperture_t
, 1);
117 image
->aperture
[i
]->type
= apertureType
;
118 image
->aperture
[i
]->parameter
[0] = parameter1
;
119 image
->aperture
[i
]->parameter
[1] = parameter2
;
127 /* --------------------------------------------------------- */
128 /*! This function reads the Gerber file char by char, looking
129 * for various Gerber codes (e.g. G, D, etc). Once it reads
130 * a code, it then dispatches control to one or another
131 * bits of code which parse the individual code.
132 * It also updates the state struct, which holds info about
133 * the current state of the hypothetical photoplotter
134 * (i.e. updates whether the aperture is on or off, updates
135 * any other parameters, like units, offsets, apertures, etc.)
138 gerber_parse_file_segment (gint levelOfRecursion
, gerbv_image_t
*image
,
139 gerb_state_t
*state
, gerbv_net_t
*curr_net
,
140 gerbv_stats_t
*stats
, gerb_file_t
*fd
,
141 gchar
*directoryPath
) {
142 int read
, coord
, len
, polygonPoints
=0;
143 double x_scale
= 0.0, y_scale
= 0.0;
144 double delta_cp_x
= 0.0, delta_cp_y
= 0.0;
145 double aperture_sizeX
, aperture_sizeY
;
147 gboolean foundEOF
= FALSE
;
149 gerbv_render_size_t boundingBox
={HUGE_VAL
,-HUGE_VAL
,HUGE_VAL
,-HUGE_VAL
};
151 while ((read
= gerb_fgetc(fd
)) != EOF
) {
152 /* figure out the scale, since we need to normalize
153 all dimensions to inches */
154 if (state
->state
->unit
== GERBV_UNIT_MM
)
158 switch ((char)(read
& 0xff)) {
160 dprintf("... Found G code\n");
161 parse_G_code(fd
, state
, image
);
164 dprintf("... Found D code\n");
165 parse_D_code(fd
, state
, image
);
168 dprintf("... Found M code\n");
169 switch(parse_M_code(fd
, image
)) {
176 gerbv_stats_add_error(stats
->error_list
,
178 "Unknown M code found.\n",
179 GERBV_MESSAGE_ERROR
);
180 } /* switch(parse_M_code) */
183 dprintf("... Found X code\n");
185 coord
= gerb_fgetint(fd
, &len
);
186 if (image
->format
&& image
->format
->omit_zeros
== GERBV_OMIT_ZEROS_TRAILING
) {
188 switch ((image
->format
->x_int
+ image
->format
->x_dec
) - len
) {
208 if (image
->format
&& (image
->format
->coordinate
==GERBV_COORDINATE_INCREMENTAL
))
209 state
->curr_x
+= coord
;
211 state
->curr_x
= coord
;
215 dprintf("... Found Y code\n");
217 coord
= gerb_fgetint(fd
, &len
);
218 if (image
->format
&& image
->format
->omit_zeros
== GERBV_OMIT_ZEROS_TRAILING
) {
220 switch ((image
->format
->y_int
+ image
->format
->y_dec
) - len
) {
240 if (image
->format
&& (image
->format
->coordinate
==GERBV_COORDINATE_INCREMENTAL
))
241 state
->curr_y
+= coord
;
243 state
->curr_y
= coord
;
247 dprintf("... Found I code\n");
249 coord
= gerb_fgetint(fd
, &len
);
250 if (image
->format
&& image
->format
->omit_zeros
== GERBV_OMIT_ZEROS_TRAILING
) {
252 switch ((image
->format
->y_int
+ image
->format
->y_dec
) - len
) {
272 state
->delta_cp_x
= coord
;
276 dprintf("... Found J code\n");
278 coord
= gerb_fgetint(fd
, &len
);
279 if (image
->format
&& image
->format
->omit_zeros
== GERBV_OMIT_ZEROS_TRAILING
) {
281 switch ((image
->format
->y_int
+ image
->format
->y_dec
) - len
) {
301 state
->delta_cp_y
= coord
;
305 dprintf("... Found %% code\n");
307 parse_rs274x(levelOfRecursion
, fd
, image
, state
, curr_net
, stats
, directoryPath
);
308 /* advance past any whitespace here */
309 int c
= gerb_fgetc(fd
);
310 while ((c
== '\n')||(c
== '\r')||(c
== ' ')||(c
== '\t')||(c
== 0))
312 if(c
== EOF
|| c
== '%')
314 // loop again to catch multiple blocks on the same line (separated by * char)
319 dprintf("... Found * code\n");
321 if (state
->changed
== 0) break;
324 /* don't even bother saving the net if the aperture state is GERBV_APERTURE_STATE_OFF and we
325 aren't starting a polygon fill (where we need it to get to the start point) */
326 if ((state
->aperture_state
== GERBV_APERTURE_STATE_OFF
)&&(!state
->in_parea_fill
)&&
327 (state
->interpolation
!= GERBV_INTERPOLATION_PAREA_START
)) {
328 /* save the coordinate so the next net can use it for a start point */
329 state
->prev_x
= state
->curr_x
;
330 state
->prev_y
= state
->curr_y
;
333 curr_net
= gerber_create_new_net (curr_net
, state
->layer
, state
->state
);
335 * Scale to given coordinate format
336 * XXX only "omit leading zeros".
338 if (image
&& image
->format
){
339 x_scale
= pow(10.0, (double)image
->format
->x_dec
);
340 y_scale
= pow(10.0, (double)image
->format
->y_dec
);
344 curr_net
->start_x
= (double)state
->prev_x
/ x_scale
;
345 curr_net
->start_y
= (double)state
->prev_y
/ y_scale
;
346 curr_net
->stop_x
= (double)state
->curr_x
/ x_scale
;
347 curr_net
->stop_y
= (double)state
->curr_y
/ y_scale
;
348 delta_cp_x
= (double)state
->delta_cp_x
/ x_scale
;
349 delta_cp_y
= (double)state
->delta_cp_y
/ y_scale
;
350 switch (state
->interpolation
) {
351 case GERBV_INTERPOLATION_CW_CIRCULAR
:
352 curr_net
->cirseg
= g_new0 (gerbv_cirseg_t
,1);
354 calc_cirseg_mq(curr_net
, 1, delta_cp_x
, delta_cp_y
);
356 calc_cirseg_sq(curr_net
, 1, delta_cp_x
, delta_cp_y
);
358 case GERBV_INTERPOLATION_CCW_CIRCULAR
:
359 curr_net
->cirseg
= g_new0 (gerbv_cirseg_t
,1);
361 calc_cirseg_mq(curr_net
, 0, delta_cp_x
, delta_cp_y
);
363 calc_cirseg_sq(curr_net
, 0, delta_cp_x
, delta_cp_y
);
365 case GERBV_INTERPOLATION_PAREA_START
:
367 * To be able to get back and fill in number of polygon corners
369 state
->parea_start_node
= curr_net
;
370 state
->in_parea_fill
= 1;
372 /* reset the bounding box */
373 boundingBox
.left
= HUGE_VAL
;
374 boundingBox
.right
= -HUGE_VAL
;
375 boundingBox
.top
= -HUGE_VAL
;
376 boundingBox
.bottom
= HUGE_VAL
;
378 case GERBV_INTERPOLATION_PAREA_END
:
379 /* save the calculated bounding box to the master node */
380 state
->parea_start_node
->boundingBox
= boundingBox
;
381 /* close out the polygon */
382 state
->parea_start_node
= NULL
;
383 state
->in_parea_fill
= 0;
388 } /* switch(state->interpolation) */
391 * Count number of points in Polygon Area
393 if (state
->in_parea_fill
&& state
->parea_start_node
) {
395 * "...all lines drawn with D01 are considered edges of the
396 * polygon. D02 closes and fills the polygon."
397 * p.49 rs274xrevd_e.pdf
398 * D02 -> state->aperture_state == GERBV_APERTURE_STATE_OFF
401 /* UPDATE: only end the polygon during a D02 call if we've already
402 drawn a polygon edge (with D01) */
404 if ((state
->aperture_state
== GERBV_APERTURE_STATE_OFF
&&
405 state
->interpolation
!= GERBV_INTERPOLATION_PAREA_START
) && (polygonPoints
> 0)) {
406 curr_net
->interpolation
= GERBV_INTERPOLATION_PAREA_END
;
407 curr_net
= gerber_create_new_net (curr_net
, state
->layer
, state
->state
);
408 curr_net
->interpolation
= GERBV_INTERPOLATION_PAREA_START
;
409 state
->parea_start_node
->boundingBox
= boundingBox
;
410 state
->parea_start_node
= curr_net
;
412 curr_net
= gerber_create_new_net (curr_net
, state
->layer
, state
->state
);
413 curr_net
->start_x
= (double)state
->prev_x
/ x_scale
;
414 curr_net
->start_y
= (double)state
->prev_y
/ y_scale
;
415 curr_net
->stop_x
= (double)state
->curr_x
/ x_scale
;
416 curr_net
->stop_y
= (double)state
->curr_y
/ y_scale
;
417 /* reset the bounding box */
418 boundingBox
.left
= HUGE_VAL
;
419 boundingBox
.right
= -HUGE_VAL
;
420 boundingBox
.top
= -HUGE_VAL
;
421 boundingBox
.bottom
= HUGE_VAL
;
423 else if (state
->interpolation
!= GERBV_INTERPOLATION_PAREA_START
)
426 } /* if (state->in_parea_fill && state->parea_start_node) */
428 curr_net
->interpolation
= state
->interpolation
;
431 * Override circular interpolation if no center was given.
432 * This should be a safe hack, since a good file should always
433 * include I or J. And even if the radius is zero, the endpoint
434 * should be the same as the start point, creating no line
436 if (((state
->interpolation
== GERBV_INTERPOLATION_CW_CIRCULAR
) ||
437 (state
->interpolation
== GERBV_INTERPOLATION_CCW_CIRCULAR
)) &&
438 ((state
->delta_cp_x
== 0.0) && (state
->delta_cp_y
== 0.0)))
439 curr_net
->interpolation
= GERBV_INTERPOLATION_LINEARx1
;
442 * If we detected the end of Polygon Area Fill we go back to
443 * the interpolation we had before that.
444 * Also if we detected any of the quadrant flags, since some
445 * gerbers don't reset the interpolation (EagleCad again).
447 if ((state
->interpolation
== GERBV_INTERPOLATION_PAREA_START
) ||
448 (state
->interpolation
== GERBV_INTERPOLATION_PAREA_END
))
449 state
->interpolation
= state
->prev_interpolation
;
452 * Save layer polarity and unit
454 curr_net
->layer
= state
->layer
;
456 state
->delta_cp_x
= 0.0;
457 state
->delta_cp_y
= 0.0;
458 curr_net
->aperture
= state
->curr_aperture
;
459 curr_net
->aperture_state
= state
->aperture_state
;
462 * For next round we save the current position as
463 * the previous position
465 state
->prev_x
= state
->curr_x
;
466 state
->prev_y
= state
->curr_y
;
469 * If we have an aperture defined at the moment we find
470 * min and max of image with compensation for mm.
472 if ((curr_net
->aperture
== 0) && !state
->in_parea_fill
)
475 /* only update the min/max values and aperture stats if we are drawing */
476 if ((curr_net
->aperture_state
!= GERBV_APERTURE_STATE_OFF
)&&
477 (curr_net
->interpolation
!= GERBV_INTERPOLATION_PAREA_START
)){
478 double repeat_off_X
= 0.0, repeat_off_Y
= 0.0;
480 /* Update stats with current aperture number if not in polygon */
481 if (!state
->in_parea_fill
) {
482 dprintf(" In parse_D_code, adding 1 to D_list ...\n");
483 int retcode
= gerbv_stats_increment_D_list_count(stats
->D_code_list
,
488 string
= g_strdup_printf("Found undefined D code D%d in file \n%s\n",
491 gerbv_stats_add_error(stats
->error_list
,
494 GERBV_MESSAGE_ERROR
);
501 * If step_and_repeat (%SR%) is used, check min_x,max_y etc for
502 * the ends of the step_and_repeat lattice. This goes wrong in
503 * the case of negative dist_X or dist_Y, in which case we
504 * should compare against the startpoints of the lines, not
505 * the stoppoints, but that seems an uncommon case (and the
506 * error isn't very big any way).
508 repeat_off_X
= (state
->layer
->stepAndRepeat
.X
- 1) *
509 state
->layer
->stepAndRepeat
.dist_X
;
510 repeat_off_Y
= (state
->layer
->stepAndRepeat
.Y
- 1) *
511 state
->layer
->stepAndRepeat
.dist_Y
;
513 cairo_matrix_init (¤tMatrix
, 1, 0, 0, 1, 0, 0);
515 cairo_matrix_translate (¤tMatrix
, image
->info
->offsetA
,
516 image
->info
->offsetB
);
517 /* do image rotation */
518 cairo_matrix_rotate (¤tMatrix
, image
->info
->imageRotation
);
519 /* it's a new layer, so recalculate the new transformation
521 /* do any rotations */
522 cairo_matrix_rotate (¤tMatrix
, state
->layer
->rotation
);
524 /* calculate current layer and state transformation matrices */
525 /* apply scale factor */
526 cairo_matrix_scale (¤tMatrix
, state
->state
->scaleA
,
527 state
->state
->scaleB
);
529 cairo_matrix_translate (¤tMatrix
, state
->state
->offsetA
,
530 state
->state
->offsetB
);
532 switch (state
->state
->mirrorState
) {
533 case GERBV_MIRROR_STATE_FLIPA
:
534 cairo_matrix_scale (¤tMatrix
, -1, 1);
536 case GERBV_MIRROR_STATE_FLIPB
:
537 cairo_matrix_scale (¤tMatrix
, 1, -1);
539 case GERBV_MIRROR_STATE_FLIPAB
:
540 cairo_matrix_scale (¤tMatrix
, -1, -1);
545 /* finally, apply axis select */
546 if (state
->state
->axisSelect
== GERBV_AXIS_SELECT_SWAPAB
) {
547 /* we do this by rotating 270 (counterclockwise, then
548 * mirroring the Y axis
550 cairo_matrix_rotate (¤tMatrix
, 3 * M_PI
/ 2);
551 cairo_matrix_scale (¤tMatrix
, 1, -1);
553 /* if it's a macro, step through all the primitive components
554 and calculate the true bounding box */
555 if ((image
->aperture
[curr_net
->aperture
] != NULL
) &&
556 (image
->aperture
[curr_net
->aperture
]->type
== GERBV_APTYPE_MACRO
)) {
557 gerbv_simplified_amacro_t
*ls
= image
->aperture
[curr_net
->aperture
]->simplified
;
560 gdouble offsetx
= 0, offsety
= 0, widthx
= 0, widthy
= 0;
561 gboolean calculatedAlready
= FALSE
;
563 if (ls
->type
== GERBV_APTYPE_MACRO_CIRCLE
) {
564 offsetx
=ls
->parameter
[CIRCLE_CENTER_X
];
565 offsety
=ls
->parameter
[CIRCLE_CENTER_Y
];
566 widthx
=widthy
=ls
->parameter
[CIRCLE_DIAMETER
];
567 } else if (ls
->type
== GERBV_APTYPE_MACRO_OUTLINE
) {
568 int pointCounter
,numberOfPoints
;
569 numberOfPoints
= (int) ls
->parameter
[OUTLINE_NUMBER_OF_POINTS
];
571 for (pointCounter
= 0; pointCounter
<= numberOfPoints
; pointCounter
++) {
572 gerber_update_min_and_max (&boundingBox
,
574 ls
->parameter
[pointCounter
* 2 + OUTLINE_FIRST_X
],
576 ls
->parameter
[pointCounter
* 2 + OUTLINE_FIRST_Y
],
579 calculatedAlready
= TRUE
;
580 } else if (ls
->type
== GERBV_APTYPE_MACRO_POLYGON
) {
581 offsetx
= ls
->parameter
[POLYGON_CENTER_X
];
582 offsety
= ls
->parameter
[POLYGON_CENTER_Y
];
583 widthx
= widthy
= ls
->parameter
[POLYGON_DIAMETER
];
584 } else if (ls
->type
== GERBV_APTYPE_MACRO_MOIRE
) {
585 offsetx
= ls
->parameter
[MOIRE_CENTER_X
];
586 offsety
= ls
->parameter
[MOIRE_CENTER_Y
];
587 widthx
= widthy
= ls
->parameter
[MOIRE_OUTSIDE_DIAMETER
];
588 } else if (ls
->type
== GERBV_APTYPE_MACRO_THERMAL
) {
589 offsetx
= ls
->parameter
[THERMAL_CENTER_X
];
590 offsety
= ls
->parameter
[THERMAL_CENTER_Y
];
591 widthx
= widthy
= ls
->parameter
[THERMAL_OUTSIDE_DIAMETER
];
592 } else if (ls
->type
== GERBV_APTYPE_MACRO_LINE20
) {
593 widthx
= widthy
= ls
->parameter
[LINE20_LINE_WIDTH
];
594 gerber_update_min_and_max (&boundingBox
,
596 ls
->parameter
[LINE20_START_X
],
598 ls
->parameter
[LINE20_START_Y
],
599 widthx
/2,widthx
/2,widthy
/2,widthy
/2);
600 gerber_update_min_and_max (&boundingBox
,
602 ls
->parameter
[LINE20_END_X
],
604 ls
->parameter
[LINE20_END_Y
],
605 widthx
/2,widthx
/2,widthy
/2,widthy
/2);
606 calculatedAlready
= TRUE
;
607 } else if (ls
->type
== GERBV_APTYPE_MACRO_LINE21
) {
608 gdouble largestDimension
= sqrt (ls
->parameter
[LINE21_WIDTH
]/2 *
609 ls
->parameter
[LINE21_WIDTH
]/2 + ls
->parameter
[LINE21_HEIGHT
/2] *
610 ls
->parameter
[LINE21_HEIGHT
]/2);
612 offsetx
= ls
->parameter
[LINE21_CENTER_X
];
613 offsety
= ls
->parameter
[LINE21_CENTER_Y
];
614 widthx
= widthy
=largestDimension
;
615 } else if (ls
->type
== GERBV_APTYPE_MACRO_LINE22
) {
616 gdouble largestDimension
= sqrt (ls
->parameter
[LINE22_WIDTH
]/2 *
617 ls
->parameter
[LINE22_WIDTH
]/2 + ls
->parameter
[LINE22_HEIGHT
/2] *
618 ls
->parameter
[LINE22_HEIGHT
]/2);
620 offsetx
= ls
->parameter
[LINE22_LOWER_LEFT_X
] +
621 ls
->parameter
[LINE22_WIDTH
]/2;
622 offsety
= ls
->parameter
[LINE22_LOWER_LEFT_Y
] +
623 ls
->parameter
[LINE22_HEIGHT
]/2;
624 widthx
= widthy
=largestDimension
;
627 if (!calculatedAlready
) {
628 gerber_update_min_and_max (&boundingBox
,
629 curr_net
->stop_x
+ offsetx
,
630 curr_net
->stop_y
+ offsety
,
631 widthx
/2,widthx
/2,widthy
/2,widthy
/2);
636 if (image
->aperture
[curr_net
->aperture
] != NULL
) {
637 aperture_sizeX
= image
->aperture
[curr_net
->aperture
]->parameter
[0];
638 if ((image
->aperture
[curr_net
->aperture
]->type
== GERBV_APTYPE_RECTANGLE
) || (image
->aperture
[curr_net
->aperture
]->type
== GERBV_APTYPE_OVAL
)) {
639 aperture_sizeY
= image
->aperture
[curr_net
->aperture
]->parameter
[1];
642 aperture_sizeY
= aperture_sizeX
;
644 /* this is usually for polygon fills, where the aperture width
646 aperture_sizeX
= aperture_sizeY
= 0;
648 /* if it's an arc path, use a special calc */
649 if ((curr_net
->interpolation
== GERBV_INTERPOLATION_CW_CIRCULAR
) ||
650 (curr_net
->interpolation
== GERBV_INTERPOLATION_CCW_CIRCULAR
)) {
651 /* to calculate the arc bounding box, we chop it into 1 degree steps, calculate
652 the point at each step, and use it to figure out the bounding box */
653 gdouble angleDiff
= curr_net
->cirseg
->angle2
- curr_net
->cirseg
->angle1
;
654 gint i
, steps
= abs(angleDiff
);
655 for (i
=0; i
<=steps
; i
++){
656 gdouble tempX
= curr_net
->cirseg
->cp_x
+ curr_net
->cirseg
->width
/ 2.0 *
657 cos ((curr_net
->cirseg
->angle1
+
658 (angleDiff
* i
) / steps
)*M_PI
/180);
659 gdouble tempY
= curr_net
->cirseg
->cp_y
+ curr_net
->cirseg
->width
/ 2.0 *
660 sin ((curr_net
->cirseg
->angle1
+
661 (angleDiff
* i
) / steps
)*M_PI
/180);
662 gerber_update_min_and_max (&boundingBox
,
664 aperture_sizeX
/2,aperture_sizeX
/2,
665 aperture_sizeY
/2,aperture_sizeY
/2);
670 /* check both the start and stop of the aperture points against
671 a running min/max counter */
672 /* Note: only check start coordinate if this isn't a flash,
673 since the start point may be bogus if it is a flash */
674 if (curr_net
->aperture_state
!= GERBV_APERTURE_STATE_FLASH
) {
675 gerber_update_min_and_max (&boundingBox
,
676 curr_net
->start_x
, curr_net
->start_y
,
677 aperture_sizeX
/2,aperture_sizeX
/2,
678 aperture_sizeY
/2,aperture_sizeY
/2);
680 gerber_update_min_and_max (&boundingBox
,
681 curr_net
->stop_x
, curr_net
->stop_y
,
682 aperture_sizeX
/2,aperture_sizeX
/2,
683 aperture_sizeY
/2,aperture_sizeY
/2);
687 /* update the info bounding box with this latest bounding box */
688 gerber_update_image_min_max(&boundingBox
, repeat_off_X
, repeat_off_Y
, image
);
690 /* optionally update the knockout measurement box */
691 if (knockoutMeasure
) {
692 if (boundingBox
.left
< knockoutLimitXmin
)
693 knockoutLimitXmin
= boundingBox
.left
;
694 if (boundingBox
.right
+repeat_off_X
> knockoutLimitXmax
)
695 knockoutLimitXmax
= boundingBox
.right
+repeat_off_X
;
696 if (boundingBox
.bottom
< knockoutLimitYmin
)
697 knockoutLimitYmin
= boundingBox
.bottom
;
698 if (boundingBox
.top
+repeat_off_Y
> knockoutLimitYmax
)
699 knockoutLimitYmax
= boundingBox
.top
+repeat_off_Y
;
701 /* if we're not in a polygon fill, then update the object bounding box */
702 if (!state
->in_parea_fill
) {
703 curr_net
->boundingBox
= boundingBox
;
704 /* and reset the bounding box */
705 boundingBox
.left
= HUGE_VAL
;
706 boundingBox
.right
= -HUGE_VAL
;
707 boundingBox
.bottom
= HUGE_VAL
;
708 boundingBox
.top
= -HUGE_VAL
;
712 case 10 : /* White space */
720 string
= g_strdup_printf("Found unknown character (whitespace?) [%d]%c\n",
722 gerbv_stats_add_error(stats
->error_list
,
725 GERBV_MESSAGE_ERROR
);
727 } /* switch((char) (read & 0xff)) */
733 /* ------------------------------------------------------------------ */
734 /*! This is a wrapper which gets called from top level. It
735 * does some initialization and pre-processing, and
736 * then calls gerber_parse_file_segment
737 * which processes the actual file. Then it does final
738 * modifications to the image created.
741 parse_gerb(gerb_file_t
*fd
, gchar
*directoryPath
)
743 gerb_state_t
*state
= NULL
;
744 gerbv_image_t
*image
= NULL
;
745 gerbv_net_t
*curr_net
= NULL
;
746 gerbv_stats_t
*stats
;
747 gboolean foundEOF
= FALSE
;
750 /* added by t.motylewski@bfad.de
751 * many locales redefine "." as "," and so on,
752 * so sscanf and strtod has problems when
753 * reading files using %f format */
754 setlocale(LC_NUMERIC
, "C" );
757 * Create new state. This is used locally to keep track
758 * of the photoplotter's state as the Gerber is read in.
760 state
= g_new0 (gerb_state_t
, 1);
763 * Create new image. This will be returned.
765 image
= gerbv_create_image(image
, "RS274-X (Gerber) File");
767 GERB_FATAL_ERROR("malloc image failed\n");
768 curr_net
= image
->netlist
;
769 image
->layertype
= GERBV_LAYERTYPE_RS274X
;
770 image
->gerbv_stats
= gerbv_stats_new();
771 if (image
->gerbv_stats
== NULL
)
772 GERB_FATAL_ERROR("malloc gerbv_stats failed\n");
773 stats
= (gerbv_stats_t
*) image
->gerbv_stats
;
775 /* set active layer and netstate to point to first default one created */
776 state
->layer
= image
->layers
;
777 state
->state
= image
->states
;
778 curr_net
->layer
= state
->layer
;
779 curr_net
->state
= state
->state
;
784 dprintf("In parse_gerb, starting to parse file...\n");
785 foundEOF
= gerber_parse_file_segment (1, image
, state
, curr_net
, stats
,
789 string
= g_strdup_printf("File %s is missing Gerber EOF code.\n", fd
->filename
);
790 gerbv_stats_add_error(stats
->error_list
,
793 GERBV_MESSAGE_ERROR
);
798 dprintf(" ... done parsing Gerber file\n");
799 gerber_update_any_running_knockout_measurements (image
);
800 gerber_calculate_final_justify_effects(image
);
806 /* ------------------------------------------------------------------- */
807 /*! Checks for signs that this is a RS-274X file
808 * Returns TRUE if it is, FALSE if not.
811 gerber_is_rs274x_p(gerb_file_t
*fd
, gboolean
*returnFoundBinary
)
817 gboolean found_binary
= FALSE
;
818 gboolean found_ADD
= FALSE
;
819 gboolean found_D0
= FALSE
;
820 gboolean found_D2
= FALSE
;
821 gboolean found_M0
= FALSE
;
822 gboolean found_M2
= FALSE
;
823 gboolean found_star
= FALSE
;
824 gboolean found_X
= FALSE
;
825 gboolean found_Y
= FALSE
;
827 dprintf ("gerber_is_rs274x_p(%p, %p), fd->fd = %p\n", fd
, returnFoundBinary
, fd
->fd
);
828 buf
= (char *) g_malloc(MAXL
);
830 GERB_FATAL_ERROR("malloc buf failed while checking for rs274x.\n");
832 while (fgets(buf
, MAXL
, fd
->fd
) != NULL
) {
833 dprintf ("buf = \"%s\"\n", buf
);
836 /* First look through the file for indications of its type by
837 * checking that file is not binary (non-printing chars and white
840 for (i
= 0; i
< len
; i
++) {
841 if (!isprint((int) buf
[i
]) && (buf
[i
] != '\r') &&
842 (buf
[i
] != '\n') && (buf
[i
] != '\t')) {
844 dprintf ("found_binary (%d)\n", buf
[i
]);
847 if (g_strstr_len(buf
, len
, "%ADD")) {
849 dprintf ("found_ADD\n");
851 if (g_strstr_len(buf
, len
, "D00") || g_strstr_len(buf
, len
, "D0")) {
853 dprintf ("found_D0\n");
855 if (g_strstr_len(buf
, len
, "D02") || g_strstr_len(buf
, len
, "D2")) {
857 dprintf ("found_D2\n");
859 if (g_strstr_len(buf
, len
, "M00") || g_strstr_len(buf
, len
, "M0")) {
861 dprintf ("found_M0\n");
863 if (g_strstr_len(buf
, len
, "M02") || g_strstr_len(buf
, len
, "M2")) {
865 dprintf ("found_M2\n");
867 if (g_strstr_len(buf
, len
, "*")) {
869 dprintf ("found_star\n");
871 /* look for X<number> or Y<number> */
872 if ((letter
= g_strstr_len(buf
, len
, "X")) != NULL
) {
873 if (isdigit((int) letter
[1])) { /* grab char after X */
875 dprintf ("found_X\n");
878 if ((letter
= g_strstr_len(buf
, len
, "Y")) != NULL
) {
879 if (isdigit((int) letter
[1])) { /* grab char after Y */
881 dprintf ("found_Y\n");
888 *returnFoundBinary
= found_binary
;
890 /* Now form logical expression determining if the file is RS-274X */
891 if ((found_D0
|| found_D2
|| found_M0
|| found_M2
) &&
892 found_ADD
&& found_star
&& (found_X
|| found_Y
))
898 } /* gerber_is_rs274x */
901 /* ------------------------------------------------------------------- */
902 /*! Checks for signs that this is a RS-274D file
903 * Returns TRUE if it is, FALSE if not.
906 gerber_is_rs274d_p(gerb_file_t
*fd
)
912 gboolean found_binary
= FALSE
;
913 gboolean found_ADD
= FALSE
;
914 gboolean found_D0
= FALSE
;
915 gboolean found_D2
= FALSE
;
916 gboolean found_M0
= FALSE
;
917 gboolean found_M2
= FALSE
;
918 gboolean found_star
= FALSE
;
919 gboolean found_X
= FALSE
;
920 gboolean found_Y
= FALSE
;
924 GERB_FATAL_ERROR("malloc buf failed while checking for rs274d.\n");
926 while (fgets(buf
, MAXL
, fd
->fd
) != NULL
) {
929 /* First look through the file for indications of its type */
931 /* check that file is not binary (non-printing chars */
932 for (i
= 0; i
< len
; i
++) {
933 if (!isprint( (int) buf
[i
]) && (buf
[i
] != '\r') &&
934 (buf
[i
] != '\n') && (buf
[i
] != '\t')) {
939 if (g_strstr_len(buf
, len
, "%ADD")) {
942 if (g_strstr_len(buf
, len
, "D00") || g_strstr_len(buf
, len
, "D0")) {
945 if (g_strstr_len(buf
, len
, "D02") || g_strstr_len(buf
, len
, "D2")) {
948 if (g_strstr_len(buf
, len
, "M00") || g_strstr_len(buf
, len
, "M0")) {
951 if (g_strstr_len(buf
, len
, "M02") || g_strstr_len(buf
, len
, "M2")) {
954 if (g_strstr_len(buf
, len
, "*")) {
957 /* look for X<number> or Y<number> */
958 if ((letter
= g_strstr_len(buf
, len
, "X")) != NULL
) {
959 /* grab char after X */
960 if (isdigit( (int) letter
[1])) {
964 if ((letter
= g_strstr_len(buf
, len
, "Y")) != NULL
) {
965 /* grab char after Y */
966 if (isdigit( (int) letter
[1])) {
974 /* Now form logical expression determining if the file is RS-274D */
975 if ((found_D0
|| found_D2
|| found_M0
|| found_M2
) &&
976 !found_ADD
&& found_star
&& (found_X
|| found_Y
) &&
982 } /* gerber_is_rs274d */
985 /* ------------------------------------------------------------------- */
986 /*! This function reads a G number and updates the current
987 * state. It also updates the G stats counters
990 parse_G_code(gerb_file_t
*fd
, gerb_state_t
*state
, gerbv_image_t
*image
)
993 gerbv_format_t
*format
= image
->format
;
994 gerbv_stats_t
*stats
= image
->gerbv_stats
;
998 op_int
=gerb_fgetint(fd
, NULL
);
1002 /* Is this doing anything really? */
1005 case 1: /* Linear Interpolation (1X scale) */
1006 state
->interpolation
= GERBV_INTERPOLATION_LINEARx1
;
1009 case 2: /* Clockwise Linear Interpolation */
1010 state
->interpolation
= GERBV_INTERPOLATION_CW_CIRCULAR
;
1013 case 3: /* Counter Clockwise Linear Interpolation */
1014 state
->interpolation
= GERBV_INTERPOLATION_CCW_CIRCULAR
;
1017 case 4: /* Ignore Data Block */
1018 /* Don't do anything, just read 'til * */
1019 /* SDB asks: Should we look for other codes while reading G04 in case
1020 * user forgot to put * at end of comment block? */
1022 while ((c
!= EOF
) && (c
!= '*')) {
1027 case 10: /* Linear Interpolation (10X scale) */
1028 state
->interpolation
= GERBV_INTERPOLATION_x10
;
1031 case 11: /* Linear Interpolation (0.1X scale) */
1032 state
->interpolation
= GERBV_INTERPOLATION_LINEARx01
;
1035 case 12: /* Linear Interpolation (0.01X scale) */
1036 state
->interpolation
= GERBV_INTERPOLATION_LINEARx001
;
1039 case 36: /* Turn on Polygon Area Fill */
1040 state
->prev_interpolation
= state
->interpolation
;
1041 state
->interpolation
= GERBV_INTERPOLATION_PAREA_START
;
1045 case 37: /* Turn off Polygon Area Fill */
1046 state
->interpolation
= GERBV_INTERPOLATION_PAREA_END
;
1050 case 54: /* Tool prepare */
1051 /* XXX Maybe uneccesary??? */
1052 if (gerb_fgetc(fd
) == 'D') {
1053 int a
= gerb_fgetint(fd
, NULL
);
1054 if ((a
>= 0) && (a
<= APERTURE_MAX
)) {
1055 state
->curr_aperture
= a
;
1057 string
= g_strdup_printf("Found aperture D%d out of bounds while parsing G code in file \n%s\n",
1059 gerbv_stats_add_error(stats
->error_list
,
1062 GERBV_MESSAGE_ERROR
);
1066 string
= g_strdup_printf("Found unexpected code after G54 in file \n%s\n", fd
->filename
);
1067 gerbv_stats_add_error(stats
->error_list
,
1070 GERBV_MESSAGE_ERROR
);
1072 /* Must insert error count here */
1076 case 55: /* Prepare for flash */
1079 case 70: /* Specify inches */
1080 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1081 state
->state
->unit
= GERBV_UNIT_INCH
;
1084 case 71: /* Specify millimeters */
1085 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1086 state
->state
->unit
= GERBV_UNIT_MM
;
1089 case 74: /* Disable 360 circular interpolation */
1093 case 75: /* Enable 360 circular interpolation */
1097 case 90: /* Specify absolut format */
1098 if (format
) format
->coordinate
= GERBV_COORDINATE_ABSOLUTE
;
1101 case 91: /* Specify incremental format */
1102 if (format
) format
->coordinate
= GERBV_COORDINATE_INCREMENTAL
;
1106 string
= g_strdup_printf("Encountered unknown G code G%d in file \n%s\n", op_int
, fd
->filename
);
1107 gerbv_stats_add_error(stats
->error_list
,
1110 GERBV_MESSAGE_ERROR
);
1112 string
= g_strdup_printf("Ignorning unknown G code G%d\n", op_int
);
1113 gerbv_stats_add_error(stats
->error_list
,
1116 GERBV_MESSAGE_WARNING
);
1119 /* Enter error count here */
1124 } /* parse_G_code */
1127 /* ------------------------------------------------------------------ */
1128 /*! This function reads the numeric value of a D code and updates the
1129 * state. It also updates the D stats counters
1132 parse_D_code(gerb_file_t
*fd
, gerb_state_t
*state
, gerbv_image_t
*image
)
1135 gerbv_stats_t
*stats
= image
->gerbv_stats
;
1138 a
= gerb_fgetint(fd
, NULL
);
1139 dprintf(" In parse_D_code, found D number = %d ... \n", a
);
1141 case 0 : /* Invalid code */
1142 string
= g_strdup_printf("Found invalid D00 code in file \n%s.\n", fd
->filename
);
1143 gerbv_stats_add_error(stats
->error_list
,
1146 GERBV_MESSAGE_ERROR
);
1150 case 1 : /* Exposure on */
1151 state
->aperture_state
= GERBV_APERTURE_STATE_ON
;
1155 case 2 : /* Exposure off */
1156 state
->aperture_state
= GERBV_APERTURE_STATE_OFF
;
1160 case 3 : /* Flash aperture */
1161 state
->aperture_state
= GERBV_APERTURE_STATE_FLASH
;
1165 default: /* Aperture in use */
1166 if ((a
>= 0) && (a
<= APERTURE_MAX
)) {
1167 state
->curr_aperture
= a
;
1170 string
= g_strdup_printf("Found out of bounds aperture D%d in file \n%s\n",
1172 gerbv_stats_add_error(stats
->error_list
,
1175 GERBV_MESSAGE_ERROR
);
1184 } /* parse_D_code */
1187 /* ------------------------------------------------------------------ */
1189 parse_M_code(gerb_file_t
*fd
, gerbv_image_t
*image
)
1192 gerbv_stats_t
*stats
= image
->gerbv_stats
;
1195 op_int
=gerb_fgetint(fd
, NULL
);
1198 case 0: /* Program stop */
1201 case 1: /* Optional stop */
1204 case 2: /* End of program */
1208 string
= g_strdup_printf("Encountered unknown M code M%d in file \n%s\n",
1209 op_int
, fd
->filename
);
1210 gerbv_stats_add_error(stats
->error_list
,
1213 GERBV_MESSAGE_ERROR
);
1215 string
= g_strdup_printf("Ignorning unknown M code M%d\n", op_int
);
1216 gerbv_stats_add_error(stats
->error_list
,
1219 GERBV_MESSAGE_WARNING
);
1224 } /* parse_M_code */
1227 /* ------------------------------------------------------------------ */
1229 parse_rs274x(gint levelOfRecursion
, gerb_file_t
*fd
, gerbv_image_t
*image
,
1230 gerb_state_t
*state
, gerbv_net_t
*curr_net
, gerbv_stats_t
*stats
,
1231 gchar
*directoryPath
)
1236 gerbv_aperture_t
*a
= NULL
;
1237 gerbv_amacro_t
*tmp_amacro
;
1239 gdouble scale
= 1.0;
1242 if (state
->state
->unit
== GERBV_UNIT_MM
)
1245 op
[0] = gerb_fgetc(fd
);
1246 op
[1] = gerb_fgetc(fd
);
1248 if ((op
[0] == EOF
) || (op
[1] == EOF
)) {
1249 string
= g_strdup_printf("Unexpected EOF found in file \n%s\n", fd
->filename
);
1250 gerbv_stats_add_error(stats
->error_list
,
1253 GERBV_MESSAGE_ERROR
);
1257 switch (A2I(op
[0], op
[1])){
1260 * Directive parameters
1262 case A2I('A','S'): /* Axis Select */
1263 op
[0] = gerb_fgetc(fd
);
1264 op
[1] = gerb_fgetc(fd
);
1265 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1267 if ((op
[0] == EOF
) || (op
[1] == EOF
)) {
1268 string
= g_strdup_printf("Unexpected EOF found in file \n%s\n", fd
->filename
);
1269 gerbv_stats_add_error(stats
->error_list
,
1272 GERBV_MESSAGE_ERROR
);
1276 if (((op
[0] == 'A') && (op
[1] == 'Y')) ||
1277 ((op
[0] == 'B') && (op
[1] == 'X'))) {
1278 state
->state
->axisSelect
= GERBV_AXIS_SELECT_SWAPAB
;
1280 state
->state
->axisSelect
= GERBV_AXIS_SELECT_NOSELECT
;
1283 op
[0] = gerb_fgetc(fd
);
1284 op
[1] = gerb_fgetc(fd
);
1286 if ((op
[0] == EOF
) || (op
[1] == EOF
)) {
1287 string
= g_strdup_printf("Unexpected EOF found in file \n%s\n", fd
->filename
);
1288 gerbv_stats_add_error(stats
->error_list
,
1291 GERBV_MESSAGE_ERROR
);
1295 if (((op
[0] == 'A') && (op
[1] == 'Y')) ||
1296 ((op
[0] == 'B') && (op
[1] == 'X'))) {
1297 state
->state
->axisSelect
= GERBV_AXIS_SELECT_SWAPAB
;
1299 state
->state
->axisSelect
= GERBV_AXIS_SELECT_NOSELECT
;
1303 case A2I('F','S'): /* Format Statement */
1304 image
->format
= g_new0 (gerbv_format_t
,1);
1306 switch (gerb_fgetc(fd
)) {
1308 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_LEADING
;
1311 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_TRAILING
;
1314 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_EXPLICIT
;
1317 string
= g_strdup_printf("EagleCad bug detected: Undefined handling of zeros in format code in file \n%s\n",
1319 gerbv_stats_add_error(stats
->error_list
,
1322 GERBV_MESSAGE_ERROR
);
1324 string
= g_strdup_printf("Defaulting to omitting leading zeros.\n");
1325 gerbv_stats_add_error(stats
->error_list
,
1328 GERBV_MESSAGE_WARNING
);
1331 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_LEADING
;
1334 switch (gerb_fgetc(fd
)) {
1336 image
->format
->coordinate
= GERBV_COORDINATE_ABSOLUTE
;
1339 image
->format
->coordinate
= GERBV_COORDINATE_INCREMENTAL
;
1342 string
= g_strdup_printf("Invalid coordinate type defined in format code in file \n%s\n",
1344 gerbv_stats_add_error(stats
->error_list
,
1347 GERBV_MESSAGE_ERROR
);
1349 string
= g_strdup_printf("Defaulting to absolute coordinates.\n");
1350 gerbv_stats_add_error(stats
->error_list
,
1353 GERBV_MESSAGE_WARNING
);
1355 image
->format
->coordinate
= GERBV_COORDINATE_ABSOLUTE
;
1357 op
[0] = gerb_fgetc(fd
);
1358 while((op
[0] != '*')&&(op
[0] != EOF
)) {
1361 op
[0] = (char)gerb_fgetc(fd
);
1362 image
->format
->lim_seqno
= op
[0] - '0';
1365 op
[0] = (char)gerb_fgetc(fd
);
1366 image
->format
->lim_gf
= op
[0] - '0';
1369 op
[0] = (char)gerb_fgetc(fd
);
1370 image
->format
->lim_pf
= op
[0] - '0';
1373 op
[0] = (char)gerb_fgetc(fd
);
1374 image
->format
->lim_mf
= op
[0] - '0';
1377 op
[0] = gerb_fgetc(fd
);
1378 if ((op
[0] < '0') || (op
[0] > '6')) {
1379 string
= g_strdup_printf("Illegal format size %c in file \n%s\n",
1380 (char)op
[0], fd
->filename
);
1381 gerbv_stats_add_error(stats
->error_list
,
1384 GERBV_MESSAGE_ERROR
);
1387 image
->format
->x_int
= op
[0] - '0';
1388 op
[0] = gerb_fgetc(fd
);
1389 if ((op
[0] < '0') || (op
[0] > '6')) {
1390 string
= g_strdup_printf("Illegal format size %c in file \n%s\n",
1391 (char)op
[0], fd
->filename
);
1392 gerbv_stats_add_error(stats
->error_list
,
1395 GERBV_MESSAGE_ERROR
);
1398 image
->format
->x_dec
= op
[0] - '0';
1401 op
[0] = gerb_fgetc(fd
);
1402 if ((op
[0] < '0') || (op
[0] > '6')) {
1403 string
= g_strdup_printf("Illegal format size %c in file \n%s\n",
1404 (char)op
[0], fd
->filename
);
1405 gerbv_stats_add_error(stats
->error_list
,
1408 GERBV_MESSAGE_ERROR
);
1411 image
->format
->y_int
= op
[0] - '0';
1412 op
[0] = gerb_fgetc(fd
);
1413 if ((op
[0] < '0') || (op
[0] > '6')) {
1414 string
= g_strdup_printf("Illegal format size %c in file \n%s\n",
1415 (char)op
[0], fd
->filename
);
1416 gerbv_stats_add_error(stats
->error_list
,
1419 GERBV_MESSAGE_ERROR
);
1422 image
->format
->y_dec
= op
[0] - '0';
1425 string
= g_strdup_printf("Illegal format statement [%c] in file \n%s\n",
1426 op
[0], fd
->filename
);
1427 gerbv_stats_add_error(stats
->error_list
,
1430 GERBV_MESSAGE_ERROR
);
1432 string
= g_strdup_printf("Ignoring invalid format statement.\n");
1433 gerbv_stats_add_error(stats
->error_list
,
1436 GERBV_MESSAGE_WARNING
);
1439 op
[0] = gerb_fgetc(fd
);
1442 case A2I('M','I'): /* Mirror Image */
1443 op
[0] = gerb_fgetc(fd
);
1444 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1446 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1450 readValue
= gerb_fgetint(fd
, NULL
);
1451 if (readValue
== 1) {
1452 if (state
->state
->mirrorState
== GERBV_MIRROR_STATE_FLIPB
)
1453 state
->state
->mirrorState
=GERBV_MIRROR_STATE_FLIPAB
;
1455 state
->state
->mirrorState
=GERBV_MIRROR_STATE_FLIPA
;
1459 readValue
= gerb_fgetint(fd
, NULL
);
1460 if (readValue
== 1) {
1461 if (state
->state
->mirrorState
== GERBV_MIRROR_STATE_FLIPA
)
1462 state
->state
->mirrorState
=GERBV_MIRROR_STATE_FLIPAB
;
1464 state
->state
->mirrorState
=GERBV_MIRROR_STATE_FLIPB
;
1468 string
= g_strdup_printf("Wrong character in mirror:%c\n", op
[0]);
1469 gerbv_stats_add_error(stats
->error_list
,
1472 GERBV_MESSAGE_ERROR
);
1475 op
[0] = gerb_fgetc(fd
);
1478 case A2I('M','O'): /* Mode of Units */
1479 op
[0] = gerb_fgetc(fd
);
1480 op
[1] = gerb_fgetc(fd
);
1482 if ((op
[0] == EOF
) || (op
[1] == EOF
))
1483 gerbv_stats_add_error(stats
->error_list
,
1485 "Unexpected EOF found.\n",
1486 GERBV_MESSAGE_ERROR
);
1487 switch (A2I(op
[0],op
[1])) {
1489 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1490 state
->state
->unit
= GERBV_UNIT_INCH
;
1493 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1494 state
->state
->unit
= GERBV_UNIT_MM
;
1497 string
= g_strdup_printf("Illegal unit:%c%c\n", op
[0], op
[1]);
1498 gerbv_stats_add_error(stats
->error_list
,
1501 GERBV_MESSAGE_ERROR
);
1505 case A2I('O','F'): /* Offset */
1506 op
[0] = gerb_fgetc(fd
);
1508 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1511 state
->state
->offsetA
= gerb_fgetdouble(fd
) / scale
;
1514 state
->state
->offsetB
= gerb_fgetdouble(fd
) / scale
;
1517 string
= g_strdup_printf("Wrong character in offset:%c\n", op
[0]);
1518 gerbv_stats_add_error(stats
->error_list
,
1521 GERBV_MESSAGE_ERROR
);
1524 op
[0] = gerb_fgetc(fd
);
1527 case A2I('I','F'): /* Include file */
1529 gchar
*includeFilename
= gerb_fgetstring(fd
, '*');
1531 if (includeFilename
) {
1533 if (!g_path_is_absolute(includeFilename
)) {
1534 fullPath
= g_build_filename (directoryPath
, includeFilename
, NULL
);
1536 fullPath
= g_strdup (includeFilename
);
1538 if (levelOfRecursion
< 10) {
1539 gerb_file_t
*includefd
= NULL
;
1541 includefd
= gerb_fopen(fullPath
);
1543 gerber_parse_file_segment (levelOfRecursion
+ 1, image
, state
, curr_net
, stats
, includefd
, directoryPath
);
1544 gerb_fclose(includefd
);
1546 string
= g_strdup_printf("In file %s,\nIncluded file %s cannot be found\n",
1547 fd
->filename
, fullPath
);
1548 gerbv_stats_add_error(stats
->error_list
,
1551 GERBV_MESSAGE_ERROR
);
1556 string
= g_strdup_printf("Parser encountered more than 10 levels of include file recursion which is not allowed by the RS-274X spec\n");
1557 gerbv_stats_add_error(stats
->error_list
,
1560 GERBV_MESSAGE_ERROR
);
1567 case A2I('I','O'): /* Image offset */
1568 op
[0] = gerb_fgetc(fd
);
1570 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1573 image
->info
->offsetA
= gerb_fgetdouble(fd
) / scale
;
1576 image
->info
->offsetB
= gerb_fgetdouble(fd
) / scale
;
1579 string
= g_strdup_printf("In file %s,\nwrong character in image offset %c\n",
1580 fd
->filename
, op
[0]);
1581 gerbv_stats_add_error(stats
->error_list
,
1584 GERBV_MESSAGE_ERROR
);
1587 op
[0] = gerb_fgetc(fd
);
1590 case A2I('S','F'): /* Scale Factor */
1591 if (gerb_fgetc(fd
) == 'A')
1592 state
->state
->scaleA
= gerb_fgetdouble(fd
);
1595 if (gerb_fgetc(fd
) == 'B')
1596 state
->state
->scaleB
= gerb_fgetdouble(fd
);
1600 case A2I('I','C'): /* Input Code */
1601 /* Thanks to Stephen Adam for providing this information. As he writes:
1602 * btw, here's a logic puzzle for you. If you need to
1603 * read the gerber file to see how it's encoded, then
1604 * how can you read it?
1606 op
[0] = gerb_fgetc(fd
);
1607 op
[1] = gerb_fgetc(fd
);
1609 if ((op
[0] == EOF
) || (op
[1] == EOF
)) {
1610 string
= g_strdup_printf("Unexpected EOF found in file \n%s\n", fd
->filename
);
1611 gerbv_stats_add_error(stats
->error_list
,
1614 GERBV_MESSAGE_ERROR
);
1617 switch (A2I(op
[0],op
[1])) {
1619 image
->info
->encoding
= GERBV_ENCODING_ASCII
;
1622 image
->info
->encoding
= GERBV_ENCODING_EBCDIC
;
1625 image
->info
->encoding
= GERBV_ENCODING_BCD
;
1628 image
->info
->encoding
= GERBV_ENCODING_ISO_ASCII
;
1631 image
->info
->encoding
= GERBV_ENCODING_EIA
;
1634 string
= g_strdup_printf("In file %s, \nunknown input code (IC): %c%c\n",
1635 fd
->filename
, op
[0], op
[1]);
1636 gerbv_stats_add_error(stats
->error_list
,
1639 GERBV_MESSAGE_ERROR
);
1644 /* Image parameters */
1645 case A2I('I','J'): /* Image Justify */
1646 op
[0] = gerb_fgetc(fd
);
1647 image
->info
->imageJustifyTypeA
= GERBV_JUSTIFY_LOWERLEFT
;
1648 image
->info
->imageJustifyTypeB
= GERBV_JUSTIFY_LOWERLEFT
;
1649 image
->info
->imageJustifyOffsetA
= 0.0;
1650 image
->info
->imageJustifyOffsetB
= 0.0;
1651 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1654 op
[0] = gerb_fgetc(fd
);
1656 image
->info
->imageJustifyTypeA
= GERBV_JUSTIFY_CENTERJUSTIFY
;
1657 } else if (op
[0] == 'L') {
1658 image
->info
->imageJustifyTypeA
= GERBV_JUSTIFY_LOWERLEFT
;
1661 image
->info
->imageJustifyOffsetA
= gerb_fgetdouble(fd
) / scale
;
1665 op
[0] = gerb_fgetc(fd
);
1667 image
->info
->imageJustifyTypeB
= GERBV_JUSTIFY_CENTERJUSTIFY
;
1668 } else if (op
[0] == 'L') {
1669 image
->info
->imageJustifyTypeB
= GERBV_JUSTIFY_LOWERLEFT
;
1672 image
->info
->imageJustifyOffsetB
= gerb_fgetdouble(fd
) / scale
;
1676 string
= g_strdup_printf("In file %s,\nwrong character in image justify:%c\n",
1677 fd
->filename
, op
[0]);
1678 gerbv_stats_add_error(stats
->error_list
,
1681 GERBV_MESSAGE_ERROR
);
1684 op
[0] = gerb_fgetc(fd
);
1687 case A2I('I','N'): /* Image Name */
1688 image
->info
->name
= gerb_fgetstring(fd
, '*');
1690 case A2I('I','P'): /* Image Polarity */
1692 for (ano
= 0; ano
< 3; ano
++) {
1693 op
[0] = gerb_fgetc(fd
);
1695 string
= g_strdup_printf("In file %s,\nunexpected EOF while reading image polarity (IP)\n",
1697 gerbv_stats_add_error(stats
->error_list
,
1700 GERBV_MESSAGE_ERROR
);
1703 str
[ano
] = (char)op
[0];
1706 if (strncmp(str
, "POS", 3) == 0)
1707 image
->info
->polarity
= GERBV_POLARITY_POSITIVE
;
1708 else if (strncmp(str
, "NEG", 3) == 0)
1709 image
->info
->polarity
= GERBV_POLARITY_NEGATIVE
;
1711 string
= g_strdup_printf("Unknown polarity : %c%c%c\n", str
[0], str
[1], str
[2]);
1712 gerbv_stats_add_error(stats
->error_list
,
1715 GERBV_MESSAGE_ERROR
);
1719 case A2I('I','R'): /* Image Rotation */
1720 tmp
= gerb_fgetint(fd
, NULL
) % 360;
1722 image
->info
->imageRotation
= 0.0;
1724 image
->info
->imageRotation
= M_PI
/ 2.0;
1725 else if (tmp
== 180)
1726 image
->info
->imageRotation
= M_PI
;
1727 else if (tmp
== 270)
1728 image
->info
->imageRotation
= 3.0 * M_PI
/ 2.0;
1730 string
= g_strdup_printf("Image rotation must be 0, 90, 180 or 270 (is actually %d)\n", tmp
);
1731 gerbv_stats_add_error(stats
->error_list
,
1734 GERBV_MESSAGE_ERROR
);
1738 case A2I('P','F'): /* Plotter Film */
1739 image
->info
->plotterFilm
= gerb_fgetstring(fd
, '*');
1742 /* Aperture parameters */
1743 case A2I('A','D'): /* Aperture Description */
1744 a
= (gerbv_aperture_t
*) g_new0 (gerbv_aperture_t
,1);
1746 ano
= parse_aperture_definition(fd
, a
, image
, scale
);
1748 /* error with line parse, so just quietly ignore */
1750 else if ((ano
>= 0) && (ano
<= APERTURE_MAX
)) {
1751 a
->unit
= state
->state
->unit
;
1752 image
->aperture
[ano
] = a
;
1753 dprintf(" In parse_rs274x, adding new aperture to aperture list ...\n");
1754 gerbv_stats_add_aperture(stats
->aperture_list
,
1758 gerbv_stats_add_to_D_list(stats
->D_code_list
,
1760 if (ano
< APERTURE_MIN
) {
1761 string
= g_strdup_printf("In file %s,\naperture number out of bounds : %d\n",
1763 gerbv_stats_add_error(stats
->error_list
,-1, string
, GERBV_MESSAGE_ERROR
);
1766 string
= g_strdup_printf("In file %s,\naperture number out of bounds : %d\n",
1768 gerbv_stats_add_error(stats
->error_list
,
1771 GERBV_MESSAGE_ERROR
);
1774 /* Add aperture info to stats->aperture_list here */
1777 case A2I('A','M'): /* Aperture Macro */
1778 tmp_amacro
= image
->amacro
;
1779 image
->amacro
= parse_aperture_macro(fd
);
1780 if (image
->amacro
) {
1781 image
->amacro
->next
= tmp_amacro
;
1783 print_program(image
->amacro
);
1786 string
= g_strdup_printf("In file %s, \nfailed to parse aperture macro\n",
1788 gerbv_stats_add_error(stats
->error_list
,
1791 GERBV_MESSAGE_ERROR
);
1794 // return, since we want to skip the later back-up loop
1797 case A2I('L','N'): /* Layer Name */
1798 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1799 state
->layer
->name
= gerb_fgetstring(fd
, '*');
1801 case A2I('L','P'): /* Layer Polarity */
1802 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1803 switch (gerb_fgetc(fd
)) {
1804 case 'D': /* Dark Polarity (default) */
1805 state
->layer
->polarity
= GERBV_POLARITY_DARK
;
1807 case 'C': /* Clear Polarity */
1808 state
->layer
->polarity
= GERBV_POLARITY_CLEAR
;
1811 string
= g_strdup_printf("In file %s,\nunknown Layer Polarity: %c\n",
1812 fd
->filename
, op
[0]);
1813 gerbv_stats_add_error(stats
->error_list
,
1816 GERBV_MESSAGE_ERROR
);
1820 case A2I('K','O'): /* Knock Out */
1821 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1822 gerber_update_any_running_knockout_measurements (image
);
1823 /* reset any previous knockout measurements */
1824 knockoutMeasure
= FALSE
;
1825 op
[0] = gerb_fgetc(fd
);
1826 if (op
[0] == '*') { /* Disable previous SR parameters */
1827 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_NOKNOCKOUT
;
1829 } else if (op
[0] == 'C') {
1830 state
->layer
->knockout
.polarity
= GERBV_POLARITY_CLEAR
;
1831 } else if (op
[0] == 'D') {
1832 state
->layer
->knockout
.polarity
= GERBV_POLARITY_DARK
;
1834 string
= g_strdup_printf("In file %s,\nknockout must supply a polarity (C, D, or *)\n",
1836 gerbv_stats_add_error(stats
->error_list
,
1839 GERBV_MESSAGE_ERROR
);
1842 state
->layer
->knockout
.lowerLeftX
= 0.0;
1843 state
->layer
->knockout
.lowerLeftY
= 0.0;
1844 state
->layer
->knockout
.width
= 0.0;
1845 state
->layer
->knockout
.height
= 0.0;
1846 state
->layer
->knockout
.border
= 0.0;
1847 state
->layer
->knockout
.firstInstance
= TRUE
;
1848 op
[0] = gerb_fgetc(fd
);
1849 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1852 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_FIXEDKNOCK
;
1853 state
->layer
->knockout
.lowerLeftX
= gerb_fgetdouble(fd
) / scale
;
1856 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_FIXEDKNOCK
;
1857 state
->layer
->knockout
.lowerLeftY
= gerb_fgetdouble(fd
) / scale
;
1860 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_FIXEDKNOCK
;
1861 state
->layer
->knockout
.width
= gerb_fgetdouble(fd
) / scale
;
1864 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_FIXEDKNOCK
;
1865 state
->layer
->knockout
.height
= gerb_fgetdouble(fd
) / scale
;
1868 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_BORDER
;
1869 state
->layer
->knockout
.border
= gerb_fgetdouble(fd
) / scale
;
1870 /* this is a bordered knockout, so we need to start measuring the
1871 size of a square bordering all future components */
1872 knockoutMeasure
= TRUE
;
1873 knockoutLimitXmin
= HUGE_VAL
;
1874 knockoutLimitYmin
= HUGE_VAL
;
1875 knockoutLimitXmax
= -HUGE_VAL
;
1876 knockoutLimitYmax
= -HUGE_VAL
;
1877 knockoutLayer
= state
->layer
;
1880 string
= g_strdup_printf("In file %s, \nunknown variable in knockout",
1882 gerbv_stats_add_error(stats
->error_list
,
1885 GERBV_MESSAGE_ERROR
);
1888 op
[0] = gerb_fgetc(fd
);
1891 case A2I('S','R'): /* Step and Repeat */
1892 /* start by generating a new layer (duplicating previous layer settings */
1893 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1894 op
[0] = gerb_fgetc(fd
);
1895 if (op
[0] == '*') { /* Disable previous SR parameters */
1896 state
->layer
->stepAndRepeat
.X
= 1;
1897 state
->layer
->stepAndRepeat
.Y
= 1;
1898 state
->layer
->stepAndRepeat
.dist_X
= 0.0;
1899 state
->layer
->stepAndRepeat
.dist_Y
= 0.0;
1902 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1905 state
->layer
->stepAndRepeat
.X
= gerb_fgetint(fd
, NULL
);
1908 state
->layer
->stepAndRepeat
.Y
= gerb_fgetint(fd
, NULL
);
1911 state
->layer
->stepAndRepeat
.dist_X
= gerb_fgetdouble(fd
) / scale
;
1914 state
->layer
->stepAndRepeat
.dist_Y
= gerb_fgetdouble(fd
) / scale
;
1917 string
= g_strdup_printf("In file %s,\nstep-and-repeat parameter error\n",
1919 gerbv_stats_add_error(stats
->error_list
,
1922 GERBV_MESSAGE_ERROR
);
1927 * Repeating 0 times in any direction would disable the whole plot, and
1928 * is probably not intended. At least one other tool (viewmate) seems
1929 * to interpret 0-time repeating as repeating just once too.
1931 if(state
->layer
->stepAndRepeat
.X
== 0)
1932 state
->layer
->stepAndRepeat
.X
= 1;
1933 if(state
->layer
->stepAndRepeat
.Y
== 0)
1934 state
->layer
->stepAndRepeat
.Y
= 1;
1936 op
[0] = gerb_fgetc(fd
);
1939 /* is this an actual RS274X command?? It isn't explainined in the spec... */
1941 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1943 state
->layer
->rotation
= gerb_fgetdouble(fd
) * M_PI
/ 180;
1944 op
[0] = gerb_fgetc(fd
);
1946 string
= g_strdup_printf("In file %s,\nerror in layer rotation command\n",
1948 gerbv_stats_add_error(stats
->error_list
,
1951 GERBV_MESSAGE_ERROR
);
1956 string
= g_strdup_printf("In file %s,\nunknown RS-274X extension found %%%c%c%%\n",
1957 fd
->filename
, op
[0], op
[1]);
1958 gerbv_stats_add_error(stats
->error_list
,
1961 GERBV_MESSAGE_ERROR
);
1964 // make sure we read until the trailing * character
1965 // first, backspace once in case we already read the trailing *
1967 int c
= gerb_fgetc(fd
);
1968 while ((c
!= EOF
) && (c
!= '*'))
1971 } /* parse_rs274x */
1975 * Stack declarations and operations to be used by the simple engine that
1976 * executes the parsed aperture macros.
1984 static macro_stack_t
*
1985 new_stack(unsigned int stack_size
)
1989 s
= (macro_stack_t
*) g_new0 (macro_stack_t
,1);
1990 s
->stack
= (double *) g_new0 (double, stack_size
);
1997 free_stack(macro_stack_t
*s
)
2010 push(macro_stack_t
*s
, double val
)
2012 s
->stack
[s
->sp
++] = val
;
2018 pop(macro_stack_t
*s
, double *value
)
2020 /* Check if we try to pop an empty stack */
2025 *value
= s
->stack
[--s
->sp
];
2030 /* ------------------------------------------------------------------ */
2032 simplify_aperture_macro(gerbv_aperture_t
*aperture
, gdouble scale
)
2034 const int extra_stack_size
= 10;
2036 gerbv_instruction_t
*ip
;
2037 int handled
= 1, nuf_parameters
= 0, i
, j
, clearOperatorUsed
= FALSE
;
2038 double *lp
; /* Local copy of parameters */
2039 double tmp
[2] = {0.0, 0.0};
2040 gerbv_aperture_type_t type
= GERBV_APTYPE_NONE
;
2041 gerbv_simplified_amacro_t
*sam
;
2043 if (aperture
== NULL
)
2044 GERB_FATAL_ERROR("aperture NULL in simplify aperture macro\n");
2046 if (aperture
->amacro
== NULL
)
2047 GERB_FATAL_ERROR("aperture->amacro NULL in simplify aperture macro\n");
2049 /* Allocate stack for VM */
2050 s
= new_stack(aperture
->amacro
->nuf_push
+ extra_stack_size
);
2052 GERB_FATAL_ERROR("malloc stack failed\n");
2054 /* Make a copy of the parameter list that we can rewrite if necessary */
2055 lp
= g_new (double,APERTURE_PARAMETERS_MAX
);
2057 memcpy(lp
, aperture
->parameter
, sizeof(double) * APERTURE_PARAMETERS_MAX
);
2059 for(ip
= aperture
->amacro
->program
; ip
!= NULL
; ip
= ip
->next
) {
2060 switch(ip
->opcode
) {
2061 case GERBV_OPCODE_NOP
:
2063 case GERBV_OPCODE_PUSH
:
2064 push(s
, ip
->data
.fval
);
2066 case GERBV_OPCODE_PPUSH
:
2067 push(s
, lp
[ip
->data
.ival
- 1]);
2069 case GERBV_OPCODE_PPOP
:
2070 if (pop(s
, &tmp
[0]) < 0)
2071 GERB_FATAL_ERROR("Tried to pop an empty stack");
2072 lp
[ip
->data
.ival
- 1] = tmp
[0];
2074 case GERBV_OPCODE_ADD
:
2075 if (pop(s
, &tmp
[0]) < 0)
2076 GERB_FATAL_ERROR("Tried to pop an empty stack");
2077 if (pop(s
, &tmp
[1]) < 0)
2078 GERB_FATAL_ERROR("Tried to pop an empty stack");
2079 push(s
, tmp
[1] + tmp
[0]);
2081 case GERBV_OPCODE_SUB
:
2082 if (pop(s
, &tmp
[0]) < 0)
2083 GERB_FATAL_ERROR("Tried to pop an empty stack");
2084 if (pop(s
, &tmp
[1]) < 0)
2085 GERB_FATAL_ERROR("Tried to pop an empty stack");
2086 push(s
, tmp
[1] - tmp
[0]);
2088 case GERBV_OPCODE_MUL
:
2089 if (pop(s
, &tmp
[0]) < 0)
2090 GERB_FATAL_ERROR("Tried to pop an empty stack");
2091 if (pop(s
, &tmp
[1]) < 0)
2092 GERB_FATAL_ERROR("Tried to pop an empty stack");
2093 push(s
, tmp
[1] * tmp
[0]);
2095 case GERBV_OPCODE_DIV
:
2096 if (pop(s
, &tmp
[0]) < 0)
2097 GERB_FATAL_ERROR("Tried to pop an empty stack");
2098 if (pop(s
, &tmp
[1]) < 0)
2099 GERB_FATAL_ERROR("Tried to pop an empty stack");
2100 push(s
, tmp
[1] / tmp
[0]);
2102 case GERBV_OPCODE_PRIM
:
2104 * This handles the exposure thing in the aperture macro
2105 * The exposure is always the first element on stack independent
2106 * of aperture macro.
2108 switch(ip
->data
.ival
) {
2110 dprintf(" Aperture macro circle [1] (");
2111 type
= GERBV_APTYPE_MACRO_CIRCLE
;
2117 dprintf(" Aperture macro outline [4] (");
2118 type
= GERBV_APTYPE_MACRO_OUTLINE
;
2120 * Number of parameters are:
2121 * - number of points defined in entry 1 of the stack +
2122 * start point. Times two since it is both X and Y.
2123 * - Then three more; exposure, nuf points and rotation.
2125 nuf_parameters
= ((int)s
->stack
[1] + 1) * 2 + 3;
2128 dprintf(" Aperture macro polygon [5] (");
2129 type
= GERBV_APTYPE_MACRO_POLYGON
;
2133 dprintf(" Aperture macro moiré [6] (");
2134 type
= GERBV_APTYPE_MACRO_MOIRE
;
2138 dprintf(" Aperture macro thermal [7] (");
2139 type
= GERBV_APTYPE_MACRO_THERMAL
;
2144 dprintf(" Aperture macro line 20/2 (");
2145 type
= GERBV_APTYPE_MACRO_LINE20
;
2149 dprintf(" Aperture macro line 21 (");
2150 type
= GERBV_APTYPE_MACRO_LINE21
;
2154 dprintf(" Aperture macro line 22 (");
2155 type
= GERBV_APTYPE_MACRO_LINE22
;
2162 if (type
!= GERBV_APTYPE_NONE
) {
2163 if (nuf_parameters
> APERTURE_PARAMETERS_MAX
) {
2164 GERB_COMPILE_ERROR("Number of parameters to aperture macro are more than gerbv is able to store\n");
2168 * Create struct for simplified aperture macro and
2169 * start filling in the blanks.
2171 sam
= g_new (gerbv_simplified_amacro_t
, 1);
2174 memset(sam
->parameter
, 0,
2175 sizeof(double) * APERTURE_PARAMETERS_MAX
);
2176 memcpy(sam
->parameter
, s
->stack
,
2177 sizeof(double) * nuf_parameters
);
2179 /* convert any mm values to inches */
2181 case GERBV_APTYPE_MACRO_CIRCLE
:
2182 if (fabs(sam
->parameter
[0]) < 0.001)
2183 clearOperatorUsed
= TRUE
;
2184 sam
->parameter
[1]/=scale
;
2185 sam
->parameter
[2]/=scale
;
2186 sam
->parameter
[3]/=scale
;
2188 case GERBV_APTYPE_MACRO_OUTLINE
:
2189 if (fabs(sam
->parameter
[0]) < 0.001)
2190 clearOperatorUsed
= TRUE
;
2191 for (j
=2; j
<nuf_parameters
-1; j
++){
2192 sam
->parameter
[j
]/=scale
;
2195 case GERBV_APTYPE_MACRO_POLYGON
:
2196 if (fabs(sam
->parameter
[0]) < 0.001)
2197 clearOperatorUsed
= TRUE
;
2198 sam
->parameter
[2]/=scale
;
2199 sam
->parameter
[3]/=scale
;
2200 sam
->parameter
[4]/=scale
;
2202 case GERBV_APTYPE_MACRO_MOIRE
:
2203 sam
->parameter
[0]/=scale
;
2204 sam
->parameter
[1]/=scale
;
2205 sam
->parameter
[2]/=scale
;
2206 sam
->parameter
[3]/=scale
;
2207 sam
->parameter
[4]/=scale
;
2208 sam
->parameter
[6]/=scale
;
2209 sam
->parameter
[7]/=scale
;
2211 case GERBV_APTYPE_MACRO_THERMAL
:
2212 sam
->parameter
[0]/=scale
;
2213 sam
->parameter
[1]/=scale
;
2214 sam
->parameter
[2]/=scale
;
2215 sam
->parameter
[3]/=scale
;
2216 sam
->parameter
[4]/=scale
;
2218 case GERBV_APTYPE_MACRO_LINE20
:
2219 if (fabs(sam
->parameter
[0]) < 0.001)
2220 clearOperatorUsed
= TRUE
;
2221 sam
->parameter
[1]/=scale
;
2222 sam
->parameter
[2]/=scale
;
2223 sam
->parameter
[3]/=scale
;
2224 sam
->parameter
[4]/=scale
;
2225 sam
->parameter
[5]/=scale
;
2227 case GERBV_APTYPE_MACRO_LINE21
:
2228 case GERBV_APTYPE_MACRO_LINE22
:
2229 if (fabs(sam
->parameter
[0]) < 0.001)
2230 clearOperatorUsed
= TRUE
;
2231 sam
->parameter
[1]/=scale
;
2232 sam
->parameter
[2]/=scale
;
2233 sam
->parameter
[3]/=scale
;
2234 sam
->parameter
[4]/=scale
;
2240 * Add this simplified aperture macro to the end of the list
2241 * of simplified aperture macros. If first entry, put it
2244 if (aperture
->simplified
== NULL
) {
2245 aperture
->simplified
= sam
;
2247 gerbv_simplified_amacro_t
*tmp_sam
;
2248 tmp_sam
= aperture
->simplified
;
2249 while (tmp_sam
->next
!= NULL
) {
2250 tmp_sam
= tmp_sam
->next
;
2252 tmp_sam
->next
= sam
;
2256 for (i
= 0; i
< nuf_parameters
; i
++) {
2257 dprintf("%f, ", s
->stack
[i
]);
2264 * Here we reset the stack pointer. It's not general correct
2265 * correct to do this, but since I know how the compiler works
2266 * I can do this. The correct way to do this should be to
2267 * subtract number of used elements in each primitive operation.
2278 /* store a flag to let the renderer know if it should expect any "clear"
2280 aperture
->parameter
[0]= (gdouble
) clearOperatorUsed
;
2282 } /* simplify_aperture_macro */
2285 /* ------------------------------------------------------------------ */
2287 parse_aperture_definition(gerb_file_t
*fd
, gerbv_aperture_t
*aperture
,
2288 gerbv_image_t
*image
, gdouble scale
)
2293 gerbv_amacro_t
*curr_amacro
;
2294 gerbv_amacro_t
*amacro
= image
->amacro
;
2295 gerbv_stats_t
*stats
= image
->gerbv_stats
;
2299 if (gerb_fgetc(fd
) != 'D') {
2300 string
= g_strdup_printf("Found AD code with no following 'D' in file \n%s\n",
2302 gerbv_stats_add_error(stats
->error_list
,
2305 GERBV_MESSAGE_ERROR
);
2313 ano
= gerb_fgetint(fd
, NULL
);
2316 * Read in the whole aperture defintion and tokenize it
2318 ad
= gerb_fgetstring(fd
, '*');
2319 token
= strtok(ad
, ",");
2321 if (token
== NULL
) {
2322 string
= g_strdup_printf("Invalid aperture definition in file \n%s\n",
2324 gerbv_stats_add_error(stats
->error_list
,
2327 GERBV_MESSAGE_ERROR
);
2331 if (strlen(token
) == 1) {
2334 aperture
->type
= GERBV_APTYPE_CIRCLE
;
2337 aperture
->type
= GERBV_APTYPE_RECTANGLE
;
2340 aperture
->type
= GERBV_APTYPE_OVAL
;
2343 aperture
->type
= GERBV_APTYPE_POLYGON
;
2346 /* Here a should a T be defined, but I don't know what it represents */
2348 aperture
->type
= GERBV_APTYPE_MACRO
;
2350 * In aperture definition, point to the aperture macro
2351 * used in the defintion
2353 curr_amacro
= amacro
;
2354 while (curr_amacro
) {
2355 if ((strlen(curr_amacro
->name
) == strlen(token
)) &&
2356 (strcmp(curr_amacro
->name
, token
) == 0)) {
2357 aperture
->amacro
= curr_amacro
;
2360 curr_amacro
= curr_amacro
->next
;
2365 * Parse all parameters
2367 for (token
= strtok(NULL
, "X"), i
= 0; token
!= NULL
;
2368 token
= strtok(NULL
, "X"), i
++) {
2369 if (i
== APERTURE_PARAMETERS_MAX
) {
2370 string
= g_strdup_printf("In file %s,\nmaximum number of allowed parameters exceeded in aperture %d\n",
2372 gerbv_stats_add_error(stats
->error_list
,
2375 GERBV_MESSAGE_ERROR
);
2381 tempHolder
= strtod(token
, NULL
);
2382 /* convert any MM values to inches */
2383 /* don't scale polygon angles or side numbers, or macro parmaeters */
2384 if (!(((aperture
->type
== GERBV_APTYPE_POLYGON
) && ((i
==1) || (i
==2)))||
2385 (aperture
->type
== GERBV_APTYPE_MACRO
))) {
2386 tempHolder
/= scale
;
2389 aperture
->parameter
[i
] = tempHolder
;
2391 string
= g_strdup_printf("Failed to read all parameters exceeded in aperture %d\n", ano
);
2392 gerbv_stats_add_error(stats
->error_list
,
2395 GERBV_MESSAGE_WARNING
);
2397 aperture
->parameter
[i
] = 0.0;
2401 aperture
->nuf_parameters
= i
;
2405 if (aperture
->type
== GERBV_APTYPE_MACRO
) {
2406 dprintf("Simplifying aperture %d using aperture macro \"%s\"\n", ano
,
2407 aperture
->amacro
->name
);
2408 simplify_aperture_macro(aperture
, scale
);
2409 dprintf("Done simplifying\n");
2415 } /* parse_aperture_definition */
2418 /* ------------------------------------------------------------------ */
2420 calc_cirseg_sq(struct gerbv_net
*net
, int cw
,
2421 double delta_cp_x
, double delta_cp_y
)
2423 double d1x
, d1y
, d2x
, d2y
;
2429 * Quadrant detection (based on ccw, converted below if cw)
2435 if (net
->start_x
> net
->stop_x
)
2436 /* 1st and 2nd quadrant */
2437 if (net
->start_y
< net
->stop_y
)
2442 /* 3rd and 4th quadrant */
2443 if (net
->start_y
> net
->stop_y
)
2449 * If clockwise, rotate quadrant
2466 GERB_COMPILE_ERROR("Unknow quadrant value while converting to cw\n");
2471 * Calculate arc center point
2475 net
->cirseg
->cp_x
= net
->start_x
- delta_cp_x
;
2476 net
->cirseg
->cp_y
= net
->start_y
- delta_cp_y
;
2479 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
2480 net
->cirseg
->cp_y
= net
->start_y
- delta_cp_y
;
2483 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
2484 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
2487 net
->cirseg
->cp_x
= net
->start_x
- delta_cp_x
;
2488 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
2491 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant
);
2497 d1x
= fabs(net
->start_x
- net
->cirseg
->cp_x
);
2498 d1y
= fabs(net
->start_y
- net
->cirseg
->cp_y
);
2499 d2x
= fabs(net
->stop_x
- net
->cirseg
->cp_x
);
2500 d2y
= fabs(net
->stop_y
- net
->cirseg
->cp_y
);
2502 alfa
= atan2(d1y
, d1x
);
2503 beta
= atan2(d2y
, d2x
);
2506 * Avoid divide by zero when sin(0) = 0 and cos(90) = 0
2508 net
->cirseg
->width
= alfa
< beta
?
2509 2 * (d1x
/ cos(alfa
)) : 2 * (d2x
/ cos(beta
));
2510 net
->cirseg
->height
= alfa
> beta
?
2511 2 * (d1y
/ sin(alfa
)) : 2 * (d2y
/ sin(beta
));
2513 if (alfa
< 0.000001 && beta
< 0.000001) {
2514 net
->cirseg
->height
= 0;
2517 #define RAD2DEG(a) (a * 180 / M_PI)
2521 net
->cirseg
->angle1
= RAD2DEG(alfa
);
2522 net
->cirseg
->angle2
= RAD2DEG(beta
);
2525 net
->cirseg
->angle1
= 180.0 - RAD2DEG(alfa
);
2526 net
->cirseg
->angle2
= 180.0 - RAD2DEG(beta
);
2529 net
->cirseg
->angle1
= 180.0 + RAD2DEG(alfa
);
2530 net
->cirseg
->angle2
= 180.0 + RAD2DEG(beta
);
2533 net
->cirseg
->angle1
= 360.0 - RAD2DEG(alfa
);
2534 net
->cirseg
->angle2
= 360.0 - RAD2DEG(beta
);
2537 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant
);
2540 if (net
->cirseg
->width
< 0.0)
2541 GERB_COMPILE_WARNING("Negative width [%f] in quadrant %d [%f][%f]\n",
2542 net
->cirseg
->width
, quadrant
, alfa
, beta
);
2544 if (net
->cirseg
->height
< 0.0)
2545 GERB_COMPILE_WARNING("Negative height [%f] in quadrant %d [%f][%f]\n",
2546 net
->cirseg
->height
, quadrant
, RAD2DEG(alfa
), RAD2DEG(beta
));
2550 } /* calc_cirseg_sq */
2553 /* ------------------------------------------------------------------ */
2555 calc_cirseg_mq(struct gerbv_net
*net
, int cw
,
2556 double delta_cp_x
, double delta_cp_y
)
2558 double d1x
, d1y
, d2x
, d2y
;
2561 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
2562 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
2567 d1x
= net
->start_x
- net
->cirseg
->cp_x
;
2568 d1y
= net
->start_y
- net
->cirseg
->cp_y
;
2569 d2x
= net
->stop_x
- net
->cirseg
->cp_x
;
2570 d2y
= net
->stop_y
- net
->cirseg
->cp_y
;
2572 alfa
= atan2(d1y
, d1x
);
2573 beta
= atan2(d2y
, d2x
);
2575 net
->cirseg
->width
= sqrt(delta_cp_x
*delta_cp_x
+ delta_cp_y
*delta_cp_y
);
2576 net
->cirseg
->width
*= 2.0;
2577 net
->cirseg
->height
= net
->cirseg
->width
;
2579 net
->cirseg
->angle1
= RAD2DEG(alfa
);
2580 net
->cirseg
->angle2
= RAD2DEG(beta
);
2583 * Make sure it's always positive angles
2585 if (net
->cirseg
->angle1
< 0.0) {
2586 net
->cirseg
->angle1
+= 360.0;
2587 net
->cirseg
->angle2
+= 360.0;
2590 if (net
->cirseg
->angle2
< 0.0)
2591 net
->cirseg
->angle2
+= 360.0;
2593 if(net
->cirseg
->angle2
== 0.0)
2594 net
->cirseg
->angle2
= 360.0;
2597 * This is a sanity check for angles after the nature of atan2.
2598 * If cw we must make sure angle1-angle2 are always positive,
2599 * If ccw we must make sure angle2-angle1 are always negative.
2600 * We should really return one angle and the difference as GTK
2601 * uses them. But what the heck, it works for me.
2604 if (net
->cirseg
->angle1
<= net
->cirseg
->angle2
)
2605 net
->cirseg
->angle2
-= 360.0;
2607 if (net
->cirseg
->angle1
>= net
->cirseg
->angle2
)
2608 net
->cirseg
->angle2
+= 360.0;
2612 } /* calc_cirseg_mq */
2616 gerber_update_any_running_knockout_measurements (gerbv_image_t
*image
)
2618 if (knockoutMeasure
) {
2619 knockoutLayer
->knockout
.lowerLeftX
= knockoutLimitXmin
;
2620 knockoutLayer
->knockout
.lowerLeftY
= knockoutLimitYmin
;
2621 knockoutLayer
->knockout
.width
= knockoutLimitXmax
- knockoutLimitXmin
;
2622 knockoutLayer
->knockout
.height
= knockoutLimitYmax
- knockoutLimitYmin
;
2623 knockoutMeasure
= FALSE
;
2629 gerber_calculate_final_justify_effects(gerbv_image_t
*image
)
2631 gdouble translateA
= 0.0, translateB
= 0.0;
2633 if (image
->info
->imageJustifyTypeA
!= GERBV_JUSTIFY_NOJUSTIFY
) {
2634 if (image
->info
->imageJustifyTypeA
== GERBV_JUSTIFY_CENTERJUSTIFY
)
2635 translateA
= (image
->info
->max_x
- image
->info
->min_x
) / 2.0;
2637 translateA
= -image
->info
->min_x
;
2639 if (image
->info
->imageJustifyTypeB
!= GERBV_JUSTIFY_NOJUSTIFY
) {
2640 if (image
->info
->imageJustifyTypeB
== GERBV_JUSTIFY_CENTERJUSTIFY
)
2641 translateB
= (image
->info
->max_y
- image
->info
->min_y
) / 2.0;
2643 translateB
= -image
->info
->min_y
;
2646 /* update the min/max values so the autoscale function can correctly
2647 centered a justified image */
2648 image
->info
->min_x
+= translateA
+ image
->info
->imageJustifyOffsetA
;
2649 image
->info
->max_x
+= translateA
+ image
->info
->imageJustifyOffsetA
;
2650 image
->info
->min_y
+= translateB
+ image
->info
->imageJustifyOffsetB
;
2651 image
->info
->max_y
+= translateB
+ image
->info
->imageJustifyOffsetB
;
2653 /* store the absolute offset for the justify so we can quickly offset
2654 the rendered picture during drawing */
2655 image
->info
->imageJustifyOffsetActualA
= translateA
+
2656 image
->info
->imageJustifyOffsetA
;
2657 image
->info
->imageJustifyOffsetActualB
= translateB
+
2658 image
->info
->imageJustifyOffsetB
;
2659 } /* gerber_calculate_final_justify_effects */
2662 void gerber_update_image_min_max (gerbv_render_size_t
*boundingBox
, double repeat_off_X
,
2663 double repeat_off_Y
, gerbv_image_t
* image
) {
2664 if (boundingBox
->left
< image
->info
->min_x
)
2665 image
->info
->min_x
= boundingBox
->left
;
2666 if (boundingBox
->right
+repeat_off_X
> image
->info
->max_x
)
2667 image
->info
->max_x
= boundingBox
->right
+repeat_off_X
;
2668 if (boundingBox
->bottom
< image
->info
->min_y
)
2669 image
->info
->min_y
= boundingBox
->bottom
;
2670 if (boundingBox
->top
+repeat_off_Y
> image
->info
->max_y
)
2671 image
->info
->max_y
= boundingBox
->top
+repeat_off_Y
;
2675 gerber_update_min_and_max(gerbv_render_size_t
*boundingBox
,
2676 gdouble x
, gdouble y
, gdouble apertureSizeX1
,
2677 gdouble apertureSizeX2
,gdouble apertureSizeY1
,
2678 gdouble apertureSizeY2
)
2680 gdouble ourX1
= x
- apertureSizeX1
, ourY1
= y
- apertureSizeY1
;
2681 gdouble ourX2
= x
+ apertureSizeX2
, ourY2
= y
+ apertureSizeY2
;
2683 /* transform the point to the final rendered position, accounting
2684 for any scaling, offsets, mirroring, etc */
2685 /* NOTE: we need to already add/subtract in the aperture size since
2686 the final rendering may be scaled */
2687 cairo_matrix_transform_point (¤tMatrix
, &ourX1
, &ourY1
);
2688 cairo_matrix_transform_point (¤tMatrix
, &ourX2
, &ourY2
);
2690 /* check both points against the min/max, since depending on the rotation,
2691 mirroring, etc, either point could possibly be a min or max */
2692 if(boundingBox
->left
> ourX1
)
2693 boundingBox
->left
= ourX1
;
2694 if(boundingBox
->left
> ourX2
)
2695 boundingBox
->left
= ourX2
;
2696 if(boundingBox
->right
< ourX1
)
2697 boundingBox
->right
= ourX1
;
2698 if(boundingBox
->right
< ourX2
)
2699 boundingBox
->right
= ourX2
;
2700 if(boundingBox
->bottom
> ourY1
)
2701 boundingBox
->bottom
= ourY1
;
2702 if(boundingBox
->bottom
> ourY2
)
2703 boundingBox
->bottom
= ourY2
;
2704 if(boundingBox
->top
< ourY1
)
2705 boundingBox
->top
= ourY1
;
2706 if(boundingBox
->top
< ourY2
)
2707 boundingBox
->top
= ourY2
;
2708 } /* gerber_update_min_and_max */