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 /* don't change the bounding box if the polarity is clear */
689 if (state
->layer
->polarity
!= GERBV_POLARITY_CLEAR
){
690 gerber_update_image_min_max(&boundingBox
, repeat_off_X
, repeat_off_Y
, image
);
692 /* optionally update the knockout measurement box */
693 if (knockoutMeasure
) {
694 if (boundingBox
.left
< knockoutLimitXmin
)
695 knockoutLimitXmin
= boundingBox
.left
;
696 if (boundingBox
.right
+repeat_off_X
> knockoutLimitXmax
)
697 knockoutLimitXmax
= boundingBox
.right
+repeat_off_X
;
698 if (boundingBox
.bottom
< knockoutLimitYmin
)
699 knockoutLimitYmin
= boundingBox
.bottom
;
700 if (boundingBox
.top
+repeat_off_Y
> knockoutLimitYmax
)
701 knockoutLimitYmax
= boundingBox
.top
+repeat_off_Y
;
703 /* if we're not in a polygon fill, then update the object bounding box */
704 if (!state
->in_parea_fill
) {
705 curr_net
->boundingBox
= boundingBox
;
706 /* and reset the bounding box */
707 boundingBox
.left
= HUGE_VAL
;
708 boundingBox
.right
= -HUGE_VAL
;
709 boundingBox
.bottom
= HUGE_VAL
;
710 boundingBox
.top
= -HUGE_VAL
;
714 case 10 : /* White space */
722 string
= g_strdup_printf("Found unknown character (whitespace?) [%d]%c\n",
724 gerbv_stats_add_error(stats
->error_list
,
727 GERBV_MESSAGE_ERROR
);
729 } /* switch((char) (read & 0xff)) */
735 /* ------------------------------------------------------------------ */
736 /*! This is a wrapper which gets called from top level. It
737 * does some initialization and pre-processing, and
738 * then calls gerber_parse_file_segment
739 * which processes the actual file. Then it does final
740 * modifications to the image created.
743 parse_gerb(gerb_file_t
*fd
, gchar
*directoryPath
)
745 gerb_state_t
*state
= NULL
;
746 gerbv_image_t
*image
= NULL
;
747 gerbv_net_t
*curr_net
= NULL
;
748 gerbv_stats_t
*stats
;
749 gboolean foundEOF
= FALSE
;
752 /* added by t.motylewski@bfad.de
753 * many locales redefine "." as "," and so on,
754 * so sscanf and strtod has problems when
755 * reading files using %f format */
756 setlocale(LC_NUMERIC
, "C" );
759 * Create new state. This is used locally to keep track
760 * of the photoplotter's state as the Gerber is read in.
762 state
= g_new0 (gerb_state_t
, 1);
765 * Create new image. This will be returned.
767 image
= gerbv_create_image(image
, "RS274-X (Gerber) File");
769 GERB_FATAL_ERROR("malloc image failed\n");
770 curr_net
= image
->netlist
;
771 image
->layertype
= GERBV_LAYERTYPE_RS274X
;
772 image
->gerbv_stats
= gerbv_stats_new();
773 if (image
->gerbv_stats
== NULL
)
774 GERB_FATAL_ERROR("malloc gerbv_stats failed\n");
775 stats
= (gerbv_stats_t
*) image
->gerbv_stats
;
777 /* set active layer and netstate to point to first default one created */
778 state
->layer
= image
->layers
;
779 state
->state
= image
->states
;
780 curr_net
->layer
= state
->layer
;
781 curr_net
->state
= state
->state
;
786 dprintf("In parse_gerb, starting to parse file...\n");
787 foundEOF
= gerber_parse_file_segment (1, image
, state
, curr_net
, stats
,
791 string
= g_strdup_printf("File %s is missing Gerber EOF code.\n", fd
->filename
);
792 gerbv_stats_add_error(stats
->error_list
,
795 GERBV_MESSAGE_ERROR
);
800 dprintf(" ... done parsing Gerber file\n");
801 gerber_update_any_running_knockout_measurements (image
);
802 gerber_calculate_final_justify_effects(image
);
808 /* ------------------------------------------------------------------- */
809 /*! Checks for signs that this is a RS-274X file
810 * Returns TRUE if it is, FALSE if not.
813 gerber_is_rs274x_p(gerb_file_t
*fd
, gboolean
*returnFoundBinary
)
819 gboolean found_binary
= FALSE
;
820 gboolean found_ADD
= FALSE
;
821 gboolean found_D0
= FALSE
;
822 gboolean found_D2
= FALSE
;
823 gboolean found_M0
= FALSE
;
824 gboolean found_M2
= FALSE
;
825 gboolean found_star
= FALSE
;
826 gboolean found_X
= FALSE
;
827 gboolean found_Y
= FALSE
;
829 dprintf ("gerber_is_rs274x_p(%p, %p), fd->fd = %p\n", fd
, returnFoundBinary
, fd
->fd
);
830 buf
= (char *) g_malloc(MAXL
);
832 GERB_FATAL_ERROR("malloc buf failed while checking for rs274x.\n");
834 while (fgets(buf
, MAXL
, fd
->fd
) != NULL
) {
835 dprintf ("buf = \"%s\"\n", buf
);
838 /* First look through the file for indications of its type by
839 * checking that file is not binary (non-printing chars and white
842 for (i
= 0; i
< len
; i
++) {
843 if (!isprint((int) buf
[i
]) && (buf
[i
] != '\r') &&
844 (buf
[i
] != '\n') && (buf
[i
] != '\t')) {
846 dprintf ("found_binary (%d)\n", buf
[i
]);
849 if (g_strstr_len(buf
, len
, "%ADD")) {
851 dprintf ("found_ADD\n");
853 if (g_strstr_len(buf
, len
, "D00") || g_strstr_len(buf
, len
, "D0")) {
855 dprintf ("found_D0\n");
857 if (g_strstr_len(buf
, len
, "D02") || g_strstr_len(buf
, len
, "D2")) {
859 dprintf ("found_D2\n");
861 if (g_strstr_len(buf
, len
, "M00") || g_strstr_len(buf
, len
, "M0")) {
863 dprintf ("found_M0\n");
865 if (g_strstr_len(buf
, len
, "M02") || g_strstr_len(buf
, len
, "M2")) {
867 dprintf ("found_M2\n");
869 if (g_strstr_len(buf
, len
, "*")) {
871 dprintf ("found_star\n");
873 /* look for X<number> or Y<number> */
874 if ((letter
= g_strstr_len(buf
, len
, "X")) != NULL
) {
875 if (isdigit((int) letter
[1])) { /* grab char after X */
877 dprintf ("found_X\n");
880 if ((letter
= g_strstr_len(buf
, len
, "Y")) != NULL
) {
881 if (isdigit((int) letter
[1])) { /* grab char after Y */
883 dprintf ("found_Y\n");
890 *returnFoundBinary
= found_binary
;
892 /* Now form logical expression determining if the file is RS-274X */
893 if ((found_D0
|| found_D2
|| found_M0
|| found_M2
) &&
894 found_ADD
&& found_star
&& (found_X
|| found_Y
))
900 } /* gerber_is_rs274x */
903 /* ------------------------------------------------------------------- */
904 /*! Checks for signs that this is a RS-274D file
905 * Returns TRUE if it is, FALSE if not.
908 gerber_is_rs274d_p(gerb_file_t
*fd
)
914 gboolean found_binary
= FALSE
;
915 gboolean found_ADD
= FALSE
;
916 gboolean found_D0
= FALSE
;
917 gboolean found_D2
= FALSE
;
918 gboolean found_M0
= FALSE
;
919 gboolean found_M2
= FALSE
;
920 gboolean found_star
= FALSE
;
921 gboolean found_X
= FALSE
;
922 gboolean found_Y
= FALSE
;
926 GERB_FATAL_ERROR("malloc buf failed while checking for rs274d.\n");
928 while (fgets(buf
, MAXL
, fd
->fd
) != NULL
) {
931 /* First look through the file for indications of its type */
933 /* check that file is not binary (non-printing chars */
934 for (i
= 0; i
< len
; i
++) {
935 if (!isprint( (int) buf
[i
]) && (buf
[i
] != '\r') &&
936 (buf
[i
] != '\n') && (buf
[i
] != '\t')) {
941 if (g_strstr_len(buf
, len
, "%ADD")) {
944 if (g_strstr_len(buf
, len
, "D00") || g_strstr_len(buf
, len
, "D0")) {
947 if (g_strstr_len(buf
, len
, "D02") || g_strstr_len(buf
, len
, "D2")) {
950 if (g_strstr_len(buf
, len
, "M00") || g_strstr_len(buf
, len
, "M0")) {
953 if (g_strstr_len(buf
, len
, "M02") || g_strstr_len(buf
, len
, "M2")) {
956 if (g_strstr_len(buf
, len
, "*")) {
959 /* look for X<number> or Y<number> */
960 if ((letter
= g_strstr_len(buf
, len
, "X")) != NULL
) {
961 /* grab char after X */
962 if (isdigit( (int) letter
[1])) {
966 if ((letter
= g_strstr_len(buf
, len
, "Y")) != NULL
) {
967 /* grab char after Y */
968 if (isdigit( (int) letter
[1])) {
976 /* Now form logical expression determining if the file is RS-274D */
977 if ((found_D0
|| found_D2
|| found_M0
|| found_M2
) &&
978 !found_ADD
&& found_star
&& (found_X
|| found_Y
) &&
984 } /* gerber_is_rs274d */
987 /* ------------------------------------------------------------------- */
988 /*! This function reads a G number and updates the current
989 * state. It also updates the G stats counters
992 parse_G_code(gerb_file_t
*fd
, gerb_state_t
*state
, gerbv_image_t
*image
)
995 gerbv_format_t
*format
= image
->format
;
996 gerbv_stats_t
*stats
= image
->gerbv_stats
;
1000 op_int
=gerb_fgetint(fd
, NULL
);
1004 /* Is this doing anything really? */
1007 case 1: /* Linear Interpolation (1X scale) */
1008 state
->interpolation
= GERBV_INTERPOLATION_LINEARx1
;
1011 case 2: /* Clockwise Linear Interpolation */
1012 state
->interpolation
= GERBV_INTERPOLATION_CW_CIRCULAR
;
1015 case 3: /* Counter Clockwise Linear Interpolation */
1016 state
->interpolation
= GERBV_INTERPOLATION_CCW_CIRCULAR
;
1019 case 4: /* Ignore Data Block */
1020 /* Don't do anything, just read 'til * */
1021 /* SDB asks: Should we look for other codes while reading G04 in case
1022 * user forgot to put * at end of comment block? */
1024 while ((c
!= EOF
) && (c
!= '*')) {
1029 case 10: /* Linear Interpolation (10X scale) */
1030 state
->interpolation
= GERBV_INTERPOLATION_x10
;
1033 case 11: /* Linear Interpolation (0.1X scale) */
1034 state
->interpolation
= GERBV_INTERPOLATION_LINEARx01
;
1037 case 12: /* Linear Interpolation (0.01X scale) */
1038 state
->interpolation
= GERBV_INTERPOLATION_LINEARx001
;
1041 case 36: /* Turn on Polygon Area Fill */
1042 state
->prev_interpolation
= state
->interpolation
;
1043 state
->interpolation
= GERBV_INTERPOLATION_PAREA_START
;
1047 case 37: /* Turn off Polygon Area Fill */
1048 state
->interpolation
= GERBV_INTERPOLATION_PAREA_END
;
1052 case 54: /* Tool prepare */
1053 /* XXX Maybe uneccesary??? */
1054 if (gerb_fgetc(fd
) == 'D') {
1055 int a
= gerb_fgetint(fd
, NULL
);
1056 if ((a
>= 0) && (a
<= APERTURE_MAX
)) {
1057 state
->curr_aperture
= a
;
1059 string
= g_strdup_printf("Found aperture D%d out of bounds while parsing G code in file \n%s\n",
1061 gerbv_stats_add_error(stats
->error_list
,
1064 GERBV_MESSAGE_ERROR
);
1068 string
= g_strdup_printf("Found unexpected code after G54 in file \n%s\n", fd
->filename
);
1069 gerbv_stats_add_error(stats
->error_list
,
1072 GERBV_MESSAGE_ERROR
);
1074 /* Must insert error count here */
1078 case 55: /* Prepare for flash */
1081 case 70: /* Specify inches */
1082 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1083 state
->state
->unit
= GERBV_UNIT_INCH
;
1086 case 71: /* Specify millimeters */
1087 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1088 state
->state
->unit
= GERBV_UNIT_MM
;
1091 case 74: /* Disable 360 circular interpolation */
1095 case 75: /* Enable 360 circular interpolation */
1099 case 90: /* Specify absolut format */
1100 if (format
) format
->coordinate
= GERBV_COORDINATE_ABSOLUTE
;
1103 case 91: /* Specify incremental format */
1104 if (format
) format
->coordinate
= GERBV_COORDINATE_INCREMENTAL
;
1108 string
= g_strdup_printf("Encountered unknown G code G%d in file \n%s\n", op_int
, fd
->filename
);
1109 gerbv_stats_add_error(stats
->error_list
,
1112 GERBV_MESSAGE_ERROR
);
1114 string
= g_strdup_printf("Ignorning unknown G code G%d\n", op_int
);
1115 gerbv_stats_add_error(stats
->error_list
,
1118 GERBV_MESSAGE_WARNING
);
1121 /* Enter error count here */
1126 } /* parse_G_code */
1129 /* ------------------------------------------------------------------ */
1130 /*! This function reads the numeric value of a D code and updates the
1131 * state. It also updates the D stats counters
1134 parse_D_code(gerb_file_t
*fd
, gerb_state_t
*state
, gerbv_image_t
*image
)
1137 gerbv_stats_t
*stats
= image
->gerbv_stats
;
1140 a
= gerb_fgetint(fd
, NULL
);
1141 dprintf(" In parse_D_code, found D number = %d ... \n", a
);
1143 case 0 : /* Invalid code */
1144 string
= g_strdup_printf("Found invalid D00 code in file \n%s.\n", fd
->filename
);
1145 gerbv_stats_add_error(stats
->error_list
,
1148 GERBV_MESSAGE_ERROR
);
1152 case 1 : /* Exposure on */
1153 state
->aperture_state
= GERBV_APERTURE_STATE_ON
;
1157 case 2 : /* Exposure off */
1158 state
->aperture_state
= GERBV_APERTURE_STATE_OFF
;
1162 case 3 : /* Flash aperture */
1163 state
->aperture_state
= GERBV_APERTURE_STATE_FLASH
;
1167 default: /* Aperture in use */
1168 if ((a
>= 0) && (a
<= APERTURE_MAX
)) {
1169 state
->curr_aperture
= a
;
1172 string
= g_strdup_printf("Found out of bounds aperture D%d in file \n%s\n",
1174 gerbv_stats_add_error(stats
->error_list
,
1177 GERBV_MESSAGE_ERROR
);
1186 } /* parse_D_code */
1189 /* ------------------------------------------------------------------ */
1191 parse_M_code(gerb_file_t
*fd
, gerbv_image_t
*image
)
1194 gerbv_stats_t
*stats
= image
->gerbv_stats
;
1197 op_int
=gerb_fgetint(fd
, NULL
);
1200 case 0: /* Program stop */
1203 case 1: /* Optional stop */
1206 case 2: /* End of program */
1210 string
= g_strdup_printf("Encountered unknown M code M%d in file \n%s\n",
1211 op_int
, fd
->filename
);
1212 gerbv_stats_add_error(stats
->error_list
,
1215 GERBV_MESSAGE_ERROR
);
1217 string
= g_strdup_printf("Ignorning unknown M code M%d\n", op_int
);
1218 gerbv_stats_add_error(stats
->error_list
,
1221 GERBV_MESSAGE_WARNING
);
1226 } /* parse_M_code */
1229 /* ------------------------------------------------------------------ */
1231 parse_rs274x(gint levelOfRecursion
, gerb_file_t
*fd
, gerbv_image_t
*image
,
1232 gerb_state_t
*state
, gerbv_net_t
*curr_net
, gerbv_stats_t
*stats
,
1233 gchar
*directoryPath
)
1238 gerbv_aperture_t
*a
= NULL
;
1239 gerbv_amacro_t
*tmp_amacro
;
1241 gdouble scale
= 1.0;
1244 if (state
->state
->unit
== GERBV_UNIT_MM
)
1247 op
[0] = gerb_fgetc(fd
);
1248 op
[1] = gerb_fgetc(fd
);
1250 if ((op
[0] == EOF
) || (op
[1] == EOF
)) {
1251 string
= g_strdup_printf("Unexpected EOF found in file \n%s\n", fd
->filename
);
1252 gerbv_stats_add_error(stats
->error_list
,
1255 GERBV_MESSAGE_ERROR
);
1259 switch (A2I(op
[0], op
[1])){
1262 * Directive parameters
1264 case A2I('A','S'): /* Axis Select */
1265 op
[0] = gerb_fgetc(fd
);
1266 op
[1] = gerb_fgetc(fd
);
1267 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1269 if ((op
[0] == EOF
) || (op
[1] == EOF
)) {
1270 string
= g_strdup_printf("Unexpected EOF found in file \n%s\n", fd
->filename
);
1271 gerbv_stats_add_error(stats
->error_list
,
1274 GERBV_MESSAGE_ERROR
);
1278 if (((op
[0] == 'A') && (op
[1] == 'Y')) ||
1279 ((op
[0] == 'B') && (op
[1] == 'X'))) {
1280 state
->state
->axisSelect
= GERBV_AXIS_SELECT_SWAPAB
;
1282 state
->state
->axisSelect
= GERBV_AXIS_SELECT_NOSELECT
;
1285 op
[0] = gerb_fgetc(fd
);
1286 op
[1] = gerb_fgetc(fd
);
1288 if ((op
[0] == EOF
) || (op
[1] == EOF
)) {
1289 string
= g_strdup_printf("Unexpected EOF found in file \n%s\n", fd
->filename
);
1290 gerbv_stats_add_error(stats
->error_list
,
1293 GERBV_MESSAGE_ERROR
);
1297 if (((op
[0] == 'A') && (op
[1] == 'Y')) ||
1298 ((op
[0] == 'B') && (op
[1] == 'X'))) {
1299 state
->state
->axisSelect
= GERBV_AXIS_SELECT_SWAPAB
;
1301 state
->state
->axisSelect
= GERBV_AXIS_SELECT_NOSELECT
;
1305 case A2I('F','S'): /* Format Statement */
1306 image
->format
= g_new0 (gerbv_format_t
,1);
1308 switch (gerb_fgetc(fd
)) {
1310 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_LEADING
;
1313 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_TRAILING
;
1316 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_EXPLICIT
;
1319 string
= g_strdup_printf("EagleCad bug detected: Undefined handling of zeros in format code in file \n%s\n",
1321 gerbv_stats_add_error(stats
->error_list
,
1324 GERBV_MESSAGE_ERROR
);
1326 string
= g_strdup_printf("Defaulting to omitting leading zeros.\n");
1327 gerbv_stats_add_error(stats
->error_list
,
1330 GERBV_MESSAGE_WARNING
);
1333 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_LEADING
;
1336 switch (gerb_fgetc(fd
)) {
1338 image
->format
->coordinate
= GERBV_COORDINATE_ABSOLUTE
;
1341 image
->format
->coordinate
= GERBV_COORDINATE_INCREMENTAL
;
1344 string
= g_strdup_printf("Invalid coordinate type defined in format code in file \n%s\n",
1346 gerbv_stats_add_error(stats
->error_list
,
1349 GERBV_MESSAGE_ERROR
);
1351 string
= g_strdup_printf("Defaulting to absolute coordinates.\n");
1352 gerbv_stats_add_error(stats
->error_list
,
1355 GERBV_MESSAGE_WARNING
);
1357 image
->format
->coordinate
= GERBV_COORDINATE_ABSOLUTE
;
1359 op
[0] = gerb_fgetc(fd
);
1360 while((op
[0] != '*')&&(op
[0] != EOF
)) {
1363 op
[0] = (char)gerb_fgetc(fd
);
1364 image
->format
->lim_seqno
= op
[0] - '0';
1367 op
[0] = (char)gerb_fgetc(fd
);
1368 image
->format
->lim_gf
= op
[0] - '0';
1371 op
[0] = (char)gerb_fgetc(fd
);
1372 image
->format
->lim_pf
= op
[0] - '0';
1375 op
[0] = (char)gerb_fgetc(fd
);
1376 image
->format
->lim_mf
= op
[0] - '0';
1379 op
[0] = gerb_fgetc(fd
);
1380 if ((op
[0] < '0') || (op
[0] > '6')) {
1381 string
= g_strdup_printf("Illegal format size %c in file \n%s\n",
1382 (char)op
[0], fd
->filename
);
1383 gerbv_stats_add_error(stats
->error_list
,
1386 GERBV_MESSAGE_ERROR
);
1389 image
->format
->x_int
= op
[0] - '0';
1390 op
[0] = gerb_fgetc(fd
);
1391 if ((op
[0] < '0') || (op
[0] > '6')) {
1392 string
= g_strdup_printf("Illegal format size %c in file \n%s\n",
1393 (char)op
[0], fd
->filename
);
1394 gerbv_stats_add_error(stats
->error_list
,
1397 GERBV_MESSAGE_ERROR
);
1400 image
->format
->x_dec
= op
[0] - '0';
1403 op
[0] = gerb_fgetc(fd
);
1404 if ((op
[0] < '0') || (op
[0] > '6')) {
1405 string
= g_strdup_printf("Illegal format size %c in file \n%s\n",
1406 (char)op
[0], fd
->filename
);
1407 gerbv_stats_add_error(stats
->error_list
,
1410 GERBV_MESSAGE_ERROR
);
1413 image
->format
->y_int
= op
[0] - '0';
1414 op
[0] = gerb_fgetc(fd
);
1415 if ((op
[0] < '0') || (op
[0] > '6')) {
1416 string
= g_strdup_printf("Illegal format size %c in file \n%s\n",
1417 (char)op
[0], fd
->filename
);
1418 gerbv_stats_add_error(stats
->error_list
,
1421 GERBV_MESSAGE_ERROR
);
1424 image
->format
->y_dec
= op
[0] - '0';
1427 string
= g_strdup_printf("Illegal format statement [%c] in file \n%s\n",
1428 op
[0], fd
->filename
);
1429 gerbv_stats_add_error(stats
->error_list
,
1432 GERBV_MESSAGE_ERROR
);
1434 string
= g_strdup_printf("Ignoring invalid format statement.\n");
1435 gerbv_stats_add_error(stats
->error_list
,
1438 GERBV_MESSAGE_WARNING
);
1441 op
[0] = gerb_fgetc(fd
);
1444 case A2I('M','I'): /* Mirror Image */
1445 op
[0] = gerb_fgetc(fd
);
1446 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1448 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1452 readValue
= gerb_fgetint(fd
, NULL
);
1453 if (readValue
== 1) {
1454 if (state
->state
->mirrorState
== GERBV_MIRROR_STATE_FLIPB
)
1455 state
->state
->mirrorState
=GERBV_MIRROR_STATE_FLIPAB
;
1457 state
->state
->mirrorState
=GERBV_MIRROR_STATE_FLIPA
;
1461 readValue
= gerb_fgetint(fd
, NULL
);
1462 if (readValue
== 1) {
1463 if (state
->state
->mirrorState
== GERBV_MIRROR_STATE_FLIPA
)
1464 state
->state
->mirrorState
=GERBV_MIRROR_STATE_FLIPAB
;
1466 state
->state
->mirrorState
=GERBV_MIRROR_STATE_FLIPB
;
1470 string
= g_strdup_printf("Wrong character in mirror:%c\n", op
[0]);
1471 gerbv_stats_add_error(stats
->error_list
,
1474 GERBV_MESSAGE_ERROR
);
1477 op
[0] = gerb_fgetc(fd
);
1480 case A2I('M','O'): /* Mode of Units */
1481 op
[0] = gerb_fgetc(fd
);
1482 op
[1] = gerb_fgetc(fd
);
1484 if ((op
[0] == EOF
) || (op
[1] == EOF
))
1485 gerbv_stats_add_error(stats
->error_list
,
1487 "Unexpected EOF found.\n",
1488 GERBV_MESSAGE_ERROR
);
1489 switch (A2I(op
[0],op
[1])) {
1491 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1492 state
->state
->unit
= GERBV_UNIT_INCH
;
1495 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1496 state
->state
->unit
= GERBV_UNIT_MM
;
1499 string
= g_strdup_printf("Illegal unit:%c%c\n", op
[0], op
[1]);
1500 gerbv_stats_add_error(stats
->error_list
,
1503 GERBV_MESSAGE_ERROR
);
1507 case A2I('O','F'): /* Offset */
1508 op
[0] = gerb_fgetc(fd
);
1510 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1513 state
->state
->offsetA
= gerb_fgetdouble(fd
) / scale
;
1516 state
->state
->offsetB
= gerb_fgetdouble(fd
) / scale
;
1519 string
= g_strdup_printf("Wrong character in offset:%c\n", op
[0]);
1520 gerbv_stats_add_error(stats
->error_list
,
1523 GERBV_MESSAGE_ERROR
);
1526 op
[0] = gerb_fgetc(fd
);
1529 case A2I('I','F'): /* Include file */
1531 gchar
*includeFilename
= gerb_fgetstring(fd
, '*');
1533 if (includeFilename
) {
1535 if (!g_path_is_absolute(includeFilename
)) {
1536 fullPath
= g_build_filename (directoryPath
, includeFilename
, NULL
);
1538 fullPath
= g_strdup (includeFilename
);
1540 if (levelOfRecursion
< 10) {
1541 gerb_file_t
*includefd
= NULL
;
1543 includefd
= gerb_fopen(fullPath
);
1545 gerber_parse_file_segment (levelOfRecursion
+ 1, image
, state
, curr_net
, stats
, includefd
, directoryPath
);
1546 gerb_fclose(includefd
);
1548 string
= g_strdup_printf("In file %s,\nIncluded file %s cannot be found\n",
1549 fd
->filename
, fullPath
);
1550 gerbv_stats_add_error(stats
->error_list
,
1553 GERBV_MESSAGE_ERROR
);
1558 string
= g_strdup_printf("Parser encountered more than 10 levels of include file recursion which is not allowed by the RS-274X spec\n");
1559 gerbv_stats_add_error(stats
->error_list
,
1562 GERBV_MESSAGE_ERROR
);
1569 case A2I('I','O'): /* Image offset */
1570 op
[0] = gerb_fgetc(fd
);
1572 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1575 image
->info
->offsetA
= gerb_fgetdouble(fd
) / scale
;
1578 image
->info
->offsetB
= gerb_fgetdouble(fd
) / scale
;
1581 string
= g_strdup_printf("In file %s,\nwrong character in image offset %c\n",
1582 fd
->filename
, op
[0]);
1583 gerbv_stats_add_error(stats
->error_list
,
1586 GERBV_MESSAGE_ERROR
);
1589 op
[0] = gerb_fgetc(fd
);
1592 case A2I('S','F'): /* Scale Factor */
1593 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1594 if (gerb_fgetc(fd
) == 'A')
1595 state
->state
->scaleA
= gerb_fgetdouble(fd
);
1598 if (gerb_fgetc(fd
) == 'B')
1599 state
->state
->scaleB
= gerb_fgetdouble(fd
);
1603 case A2I('I','C'): /* Input Code */
1604 /* Thanks to Stephen Adam for providing this information. As he writes:
1605 * btw, here's a logic puzzle for you. If you need to
1606 * read the gerber file to see how it's encoded, then
1607 * how can you read it?
1609 op
[0] = gerb_fgetc(fd
);
1610 op
[1] = gerb_fgetc(fd
);
1612 if ((op
[0] == EOF
) || (op
[1] == EOF
)) {
1613 string
= g_strdup_printf("Unexpected EOF found in file \n%s\n", fd
->filename
);
1614 gerbv_stats_add_error(stats
->error_list
,
1617 GERBV_MESSAGE_ERROR
);
1620 switch (A2I(op
[0],op
[1])) {
1622 image
->info
->encoding
= GERBV_ENCODING_ASCII
;
1625 image
->info
->encoding
= GERBV_ENCODING_EBCDIC
;
1628 image
->info
->encoding
= GERBV_ENCODING_BCD
;
1631 image
->info
->encoding
= GERBV_ENCODING_ISO_ASCII
;
1634 image
->info
->encoding
= GERBV_ENCODING_EIA
;
1637 string
= g_strdup_printf("In file %s, \nunknown input code (IC): %c%c\n",
1638 fd
->filename
, op
[0], op
[1]);
1639 gerbv_stats_add_error(stats
->error_list
,
1642 GERBV_MESSAGE_ERROR
);
1647 /* Image parameters */
1648 case A2I('I','J'): /* Image Justify */
1649 op
[0] = gerb_fgetc(fd
);
1650 image
->info
->imageJustifyTypeA
= GERBV_JUSTIFY_LOWERLEFT
;
1651 image
->info
->imageJustifyTypeB
= GERBV_JUSTIFY_LOWERLEFT
;
1652 image
->info
->imageJustifyOffsetA
= 0.0;
1653 image
->info
->imageJustifyOffsetB
= 0.0;
1654 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1657 op
[0] = gerb_fgetc(fd
);
1659 image
->info
->imageJustifyTypeA
= GERBV_JUSTIFY_CENTERJUSTIFY
;
1660 } else if (op
[0] == 'L') {
1661 image
->info
->imageJustifyTypeA
= GERBV_JUSTIFY_LOWERLEFT
;
1664 image
->info
->imageJustifyOffsetA
= gerb_fgetdouble(fd
) / scale
;
1668 op
[0] = gerb_fgetc(fd
);
1670 image
->info
->imageJustifyTypeB
= GERBV_JUSTIFY_CENTERJUSTIFY
;
1671 } else if (op
[0] == 'L') {
1672 image
->info
->imageJustifyTypeB
= GERBV_JUSTIFY_LOWERLEFT
;
1675 image
->info
->imageJustifyOffsetB
= gerb_fgetdouble(fd
) / scale
;
1679 string
= g_strdup_printf("In file %s,\nwrong character in image justify:%c\n",
1680 fd
->filename
, op
[0]);
1681 gerbv_stats_add_error(stats
->error_list
,
1684 GERBV_MESSAGE_ERROR
);
1687 op
[0] = gerb_fgetc(fd
);
1690 case A2I('I','N'): /* Image Name */
1691 image
->info
->name
= gerb_fgetstring(fd
, '*');
1693 case A2I('I','P'): /* Image Polarity */
1695 for (ano
= 0; ano
< 3; ano
++) {
1696 op
[0] = gerb_fgetc(fd
);
1698 string
= g_strdup_printf("In file %s,\nunexpected EOF while reading image polarity (IP)\n",
1700 gerbv_stats_add_error(stats
->error_list
,
1703 GERBV_MESSAGE_ERROR
);
1706 str
[ano
] = (char)op
[0];
1709 if (strncmp(str
, "POS", 3) == 0)
1710 image
->info
->polarity
= GERBV_POLARITY_POSITIVE
;
1711 else if (strncmp(str
, "NEG", 3) == 0)
1712 image
->info
->polarity
= GERBV_POLARITY_NEGATIVE
;
1714 string
= g_strdup_printf("Unknown polarity : %c%c%c\n", str
[0], str
[1], str
[2]);
1715 gerbv_stats_add_error(stats
->error_list
,
1718 GERBV_MESSAGE_ERROR
);
1722 case A2I('I','R'): /* Image Rotation */
1723 tmp
= gerb_fgetint(fd
, NULL
) % 360;
1725 image
->info
->imageRotation
= 0.0;
1727 image
->info
->imageRotation
= M_PI
/ 2.0;
1728 else if (tmp
== 180)
1729 image
->info
->imageRotation
= M_PI
;
1730 else if (tmp
== 270)
1731 image
->info
->imageRotation
= 3.0 * M_PI
/ 2.0;
1733 string
= g_strdup_printf("Image rotation must be 0, 90, 180 or 270 (is actually %d)\n", tmp
);
1734 gerbv_stats_add_error(stats
->error_list
,
1737 GERBV_MESSAGE_ERROR
);
1741 case A2I('P','F'): /* Plotter Film */
1742 image
->info
->plotterFilm
= gerb_fgetstring(fd
, '*');
1745 /* Aperture parameters */
1746 case A2I('A','D'): /* Aperture Description */
1747 a
= (gerbv_aperture_t
*) g_new0 (gerbv_aperture_t
,1);
1749 ano
= parse_aperture_definition(fd
, a
, image
, scale
);
1751 /* error with line parse, so just quietly ignore */
1753 else if ((ano
>= 0) && (ano
<= APERTURE_MAX
)) {
1754 a
->unit
= state
->state
->unit
;
1755 image
->aperture
[ano
] = a
;
1756 dprintf(" In parse_rs274x, adding new aperture to aperture list ...\n");
1757 gerbv_stats_add_aperture(stats
->aperture_list
,
1761 gerbv_stats_add_to_D_list(stats
->D_code_list
,
1763 if (ano
< APERTURE_MIN
) {
1764 string
= g_strdup_printf("In file %s,\naperture number out of bounds : %d\n",
1766 gerbv_stats_add_error(stats
->error_list
,-1, string
, GERBV_MESSAGE_ERROR
);
1769 string
= g_strdup_printf("In file %s,\naperture number out of bounds : %d\n",
1771 gerbv_stats_add_error(stats
->error_list
,
1774 GERBV_MESSAGE_ERROR
);
1777 /* Add aperture info to stats->aperture_list here */
1780 case A2I('A','M'): /* Aperture Macro */
1781 tmp_amacro
= image
->amacro
;
1782 image
->amacro
= parse_aperture_macro(fd
);
1783 if (image
->amacro
) {
1784 image
->amacro
->next
= tmp_amacro
;
1786 print_program(image
->amacro
);
1789 string
= g_strdup_printf("In file %s, \nfailed to parse aperture macro\n",
1791 gerbv_stats_add_error(stats
->error_list
,
1794 GERBV_MESSAGE_ERROR
);
1797 // return, since we want to skip the later back-up loop
1800 case A2I('L','N'): /* Layer Name */
1801 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1802 state
->layer
->name
= gerb_fgetstring(fd
, '*');
1804 case A2I('L','P'): /* Layer Polarity */
1805 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1806 switch (gerb_fgetc(fd
)) {
1807 case 'D': /* Dark Polarity (default) */
1808 state
->layer
->polarity
= GERBV_POLARITY_DARK
;
1810 case 'C': /* Clear Polarity */
1811 state
->layer
->polarity
= GERBV_POLARITY_CLEAR
;
1814 string
= g_strdup_printf("In file %s,\nunknown Layer Polarity: %c\n",
1815 fd
->filename
, op
[0]);
1816 gerbv_stats_add_error(stats
->error_list
,
1819 GERBV_MESSAGE_ERROR
);
1823 case A2I('K','O'): /* Knock Out */
1824 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1825 gerber_update_any_running_knockout_measurements (image
);
1826 /* reset any previous knockout measurements */
1827 knockoutMeasure
= FALSE
;
1828 op
[0] = gerb_fgetc(fd
);
1829 if (op
[0] == '*') { /* Disable previous SR parameters */
1830 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_NOKNOCKOUT
;
1832 } else if (op
[0] == 'C') {
1833 state
->layer
->knockout
.polarity
= GERBV_POLARITY_CLEAR
;
1834 } else if (op
[0] == 'D') {
1835 state
->layer
->knockout
.polarity
= GERBV_POLARITY_DARK
;
1837 string
= g_strdup_printf("In file %s,\nknockout must supply a polarity (C, D, or *)\n",
1839 gerbv_stats_add_error(stats
->error_list
,
1842 GERBV_MESSAGE_ERROR
);
1845 state
->layer
->knockout
.lowerLeftX
= 0.0;
1846 state
->layer
->knockout
.lowerLeftY
= 0.0;
1847 state
->layer
->knockout
.width
= 0.0;
1848 state
->layer
->knockout
.height
= 0.0;
1849 state
->layer
->knockout
.border
= 0.0;
1850 state
->layer
->knockout
.firstInstance
= TRUE
;
1851 op
[0] = gerb_fgetc(fd
);
1852 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1855 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_FIXEDKNOCK
;
1856 state
->layer
->knockout
.lowerLeftX
= gerb_fgetdouble(fd
) / scale
;
1859 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_FIXEDKNOCK
;
1860 state
->layer
->knockout
.lowerLeftY
= gerb_fgetdouble(fd
) / scale
;
1863 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_FIXEDKNOCK
;
1864 state
->layer
->knockout
.width
= gerb_fgetdouble(fd
) / scale
;
1867 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_FIXEDKNOCK
;
1868 state
->layer
->knockout
.height
= gerb_fgetdouble(fd
) / scale
;
1871 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_BORDER
;
1872 state
->layer
->knockout
.border
= gerb_fgetdouble(fd
) / scale
;
1873 /* this is a bordered knockout, so we need to start measuring the
1874 size of a square bordering all future components */
1875 knockoutMeasure
= TRUE
;
1876 knockoutLimitXmin
= HUGE_VAL
;
1877 knockoutLimitYmin
= HUGE_VAL
;
1878 knockoutLimitXmax
= -HUGE_VAL
;
1879 knockoutLimitYmax
= -HUGE_VAL
;
1880 knockoutLayer
= state
->layer
;
1883 string
= g_strdup_printf("In file %s, \nunknown variable in knockout",
1885 gerbv_stats_add_error(stats
->error_list
,
1888 GERBV_MESSAGE_ERROR
);
1891 op
[0] = gerb_fgetc(fd
);
1894 case A2I('S','R'): /* Step and Repeat */
1895 /* start by generating a new layer (duplicating previous layer settings */
1896 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1897 op
[0] = gerb_fgetc(fd
);
1898 if (op
[0] == '*') { /* Disable previous SR parameters */
1899 state
->layer
->stepAndRepeat
.X
= 1;
1900 state
->layer
->stepAndRepeat
.Y
= 1;
1901 state
->layer
->stepAndRepeat
.dist_X
= 0.0;
1902 state
->layer
->stepAndRepeat
.dist_Y
= 0.0;
1905 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1908 state
->layer
->stepAndRepeat
.X
= gerb_fgetint(fd
, NULL
);
1911 state
->layer
->stepAndRepeat
.Y
= gerb_fgetint(fd
, NULL
);
1914 state
->layer
->stepAndRepeat
.dist_X
= gerb_fgetdouble(fd
) / scale
;
1917 state
->layer
->stepAndRepeat
.dist_Y
= gerb_fgetdouble(fd
) / scale
;
1920 string
= g_strdup_printf("In file %s,\nstep-and-repeat parameter error\n",
1922 gerbv_stats_add_error(stats
->error_list
,
1925 GERBV_MESSAGE_ERROR
);
1930 * Repeating 0 times in any direction would disable the whole plot, and
1931 * is probably not intended. At least one other tool (viewmate) seems
1932 * to interpret 0-time repeating as repeating just once too.
1934 if(state
->layer
->stepAndRepeat
.X
== 0)
1935 state
->layer
->stepAndRepeat
.X
= 1;
1936 if(state
->layer
->stepAndRepeat
.Y
== 0)
1937 state
->layer
->stepAndRepeat
.Y
= 1;
1939 op
[0] = gerb_fgetc(fd
);
1942 /* is this an actual RS274X command?? It isn't explainined in the spec... */
1944 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1946 state
->layer
->rotation
= gerb_fgetdouble(fd
) * M_PI
/ 180;
1947 op
[0] = gerb_fgetc(fd
);
1949 string
= g_strdup_printf("In file %s,\nerror in layer rotation command\n",
1951 gerbv_stats_add_error(stats
->error_list
,
1954 GERBV_MESSAGE_ERROR
);
1959 string
= g_strdup_printf("In file %s,\nunknown RS-274X extension found %%%c%c%%\n",
1960 fd
->filename
, op
[0], op
[1]);
1961 gerbv_stats_add_error(stats
->error_list
,
1964 GERBV_MESSAGE_ERROR
);
1967 // make sure we read until the trailing * character
1968 // first, backspace once in case we already read the trailing *
1970 int c
= gerb_fgetc(fd
);
1971 while ((c
!= EOF
) && (c
!= '*'))
1974 } /* parse_rs274x */
1978 * Stack declarations and operations to be used by the simple engine that
1979 * executes the parsed aperture macros.
1987 static macro_stack_t
*
1988 new_stack(unsigned int stack_size
)
1992 s
= (macro_stack_t
*) g_new0 (macro_stack_t
,1);
1993 s
->stack
= (double *) g_new0 (double, stack_size
);
2000 free_stack(macro_stack_t
*s
)
2013 push(macro_stack_t
*s
, double val
)
2015 s
->stack
[s
->sp
++] = val
;
2021 pop(macro_stack_t
*s
, double *value
)
2023 /* Check if we try to pop an empty stack */
2028 *value
= s
->stack
[--s
->sp
];
2033 /* ------------------------------------------------------------------ */
2035 simplify_aperture_macro(gerbv_aperture_t
*aperture
, gdouble scale
)
2037 const int extra_stack_size
= 10;
2039 gerbv_instruction_t
*ip
;
2040 int handled
= 1, nuf_parameters
= 0, i
, j
, clearOperatorUsed
= FALSE
;
2041 double *lp
; /* Local copy of parameters */
2042 double tmp
[2] = {0.0, 0.0};
2043 gerbv_aperture_type_t type
= GERBV_APTYPE_NONE
;
2044 gerbv_simplified_amacro_t
*sam
;
2046 if (aperture
== NULL
)
2047 GERB_FATAL_ERROR("aperture NULL in simplify aperture macro\n");
2049 if (aperture
->amacro
== NULL
)
2050 GERB_FATAL_ERROR("aperture->amacro NULL in simplify aperture macro\n");
2052 /* Allocate stack for VM */
2053 s
= new_stack(aperture
->amacro
->nuf_push
+ extra_stack_size
);
2055 GERB_FATAL_ERROR("malloc stack failed\n");
2057 /* Make a copy of the parameter list that we can rewrite if necessary */
2058 lp
= g_new (double,APERTURE_PARAMETERS_MAX
);
2060 memcpy(lp
, aperture
->parameter
, sizeof(double) * APERTURE_PARAMETERS_MAX
);
2062 for(ip
= aperture
->amacro
->program
; ip
!= NULL
; ip
= ip
->next
) {
2063 switch(ip
->opcode
) {
2064 case GERBV_OPCODE_NOP
:
2066 case GERBV_OPCODE_PUSH
:
2067 push(s
, ip
->data
.fval
);
2069 case GERBV_OPCODE_PPUSH
:
2070 push(s
, lp
[ip
->data
.ival
- 1]);
2072 case GERBV_OPCODE_PPOP
:
2073 if (pop(s
, &tmp
[0]) < 0)
2074 GERB_FATAL_ERROR("Tried to pop an empty stack");
2075 lp
[ip
->data
.ival
- 1] = tmp
[0];
2077 case GERBV_OPCODE_ADD
:
2078 if (pop(s
, &tmp
[0]) < 0)
2079 GERB_FATAL_ERROR("Tried to pop an empty stack");
2080 if (pop(s
, &tmp
[1]) < 0)
2081 GERB_FATAL_ERROR("Tried to pop an empty stack");
2082 push(s
, tmp
[1] + tmp
[0]);
2084 case GERBV_OPCODE_SUB
:
2085 if (pop(s
, &tmp
[0]) < 0)
2086 GERB_FATAL_ERROR("Tried to pop an empty stack");
2087 if (pop(s
, &tmp
[1]) < 0)
2088 GERB_FATAL_ERROR("Tried to pop an empty stack");
2089 push(s
, tmp
[1] - tmp
[0]);
2091 case GERBV_OPCODE_MUL
:
2092 if (pop(s
, &tmp
[0]) < 0)
2093 GERB_FATAL_ERROR("Tried to pop an empty stack");
2094 if (pop(s
, &tmp
[1]) < 0)
2095 GERB_FATAL_ERROR("Tried to pop an empty stack");
2096 push(s
, tmp
[1] * tmp
[0]);
2098 case GERBV_OPCODE_DIV
:
2099 if (pop(s
, &tmp
[0]) < 0)
2100 GERB_FATAL_ERROR("Tried to pop an empty stack");
2101 if (pop(s
, &tmp
[1]) < 0)
2102 GERB_FATAL_ERROR("Tried to pop an empty stack");
2103 push(s
, tmp
[1] / tmp
[0]);
2105 case GERBV_OPCODE_PRIM
:
2107 * This handles the exposure thing in the aperture macro
2108 * The exposure is always the first element on stack independent
2109 * of aperture macro.
2111 switch(ip
->data
.ival
) {
2113 dprintf(" Aperture macro circle [1] (");
2114 type
= GERBV_APTYPE_MACRO_CIRCLE
;
2120 dprintf(" Aperture macro outline [4] (");
2121 type
= GERBV_APTYPE_MACRO_OUTLINE
;
2123 * Number of parameters are:
2124 * - number of points defined in entry 1 of the stack +
2125 * start point. Times two since it is both X and Y.
2126 * - Then three more; exposure, nuf points and rotation.
2128 nuf_parameters
= ((int)s
->stack
[1] + 1) * 2 + 3;
2131 dprintf(" Aperture macro polygon [5] (");
2132 type
= GERBV_APTYPE_MACRO_POLYGON
;
2136 dprintf(" Aperture macro moiré [6] (");
2137 type
= GERBV_APTYPE_MACRO_MOIRE
;
2141 dprintf(" Aperture macro thermal [7] (");
2142 type
= GERBV_APTYPE_MACRO_THERMAL
;
2147 dprintf(" Aperture macro line 20/2 (");
2148 type
= GERBV_APTYPE_MACRO_LINE20
;
2152 dprintf(" Aperture macro line 21 (");
2153 type
= GERBV_APTYPE_MACRO_LINE21
;
2157 dprintf(" Aperture macro line 22 (");
2158 type
= GERBV_APTYPE_MACRO_LINE22
;
2165 if (type
!= GERBV_APTYPE_NONE
) {
2166 if (nuf_parameters
> APERTURE_PARAMETERS_MAX
) {
2167 GERB_COMPILE_ERROR("Number of parameters to aperture macro are more than gerbv is able to store\n");
2171 * Create struct for simplified aperture macro and
2172 * start filling in the blanks.
2174 sam
= g_new (gerbv_simplified_amacro_t
, 1);
2177 memset(sam
->parameter
, 0,
2178 sizeof(double) * APERTURE_PARAMETERS_MAX
);
2179 memcpy(sam
->parameter
, s
->stack
,
2180 sizeof(double) * nuf_parameters
);
2182 /* convert any mm values to inches */
2184 case GERBV_APTYPE_MACRO_CIRCLE
:
2185 if (fabs(sam
->parameter
[0]) < 0.001)
2186 clearOperatorUsed
= TRUE
;
2187 sam
->parameter
[1]/=scale
;
2188 sam
->parameter
[2]/=scale
;
2189 sam
->parameter
[3]/=scale
;
2191 case GERBV_APTYPE_MACRO_OUTLINE
:
2192 if (fabs(sam
->parameter
[0]) < 0.001)
2193 clearOperatorUsed
= TRUE
;
2194 for (j
=2; j
<nuf_parameters
-1; j
++){
2195 sam
->parameter
[j
]/=scale
;
2198 case GERBV_APTYPE_MACRO_POLYGON
:
2199 if (fabs(sam
->parameter
[0]) < 0.001)
2200 clearOperatorUsed
= TRUE
;
2201 sam
->parameter
[2]/=scale
;
2202 sam
->parameter
[3]/=scale
;
2203 sam
->parameter
[4]/=scale
;
2205 case GERBV_APTYPE_MACRO_MOIRE
:
2206 sam
->parameter
[0]/=scale
;
2207 sam
->parameter
[1]/=scale
;
2208 sam
->parameter
[2]/=scale
;
2209 sam
->parameter
[3]/=scale
;
2210 sam
->parameter
[4]/=scale
;
2211 sam
->parameter
[6]/=scale
;
2212 sam
->parameter
[7]/=scale
;
2214 case GERBV_APTYPE_MACRO_THERMAL
:
2215 sam
->parameter
[0]/=scale
;
2216 sam
->parameter
[1]/=scale
;
2217 sam
->parameter
[2]/=scale
;
2218 sam
->parameter
[3]/=scale
;
2219 sam
->parameter
[4]/=scale
;
2221 case GERBV_APTYPE_MACRO_LINE20
:
2222 if (fabs(sam
->parameter
[0]) < 0.001)
2223 clearOperatorUsed
= TRUE
;
2224 sam
->parameter
[1]/=scale
;
2225 sam
->parameter
[2]/=scale
;
2226 sam
->parameter
[3]/=scale
;
2227 sam
->parameter
[4]/=scale
;
2228 sam
->parameter
[5]/=scale
;
2230 case GERBV_APTYPE_MACRO_LINE21
:
2231 case GERBV_APTYPE_MACRO_LINE22
:
2232 if (fabs(sam
->parameter
[0]) < 0.001)
2233 clearOperatorUsed
= TRUE
;
2234 sam
->parameter
[1]/=scale
;
2235 sam
->parameter
[2]/=scale
;
2236 sam
->parameter
[3]/=scale
;
2237 sam
->parameter
[4]/=scale
;
2243 * Add this simplified aperture macro to the end of the list
2244 * of simplified aperture macros. If first entry, put it
2247 if (aperture
->simplified
== NULL
) {
2248 aperture
->simplified
= sam
;
2250 gerbv_simplified_amacro_t
*tmp_sam
;
2251 tmp_sam
= aperture
->simplified
;
2252 while (tmp_sam
->next
!= NULL
) {
2253 tmp_sam
= tmp_sam
->next
;
2255 tmp_sam
->next
= sam
;
2259 for (i
= 0; i
< nuf_parameters
; i
++) {
2260 dprintf("%f, ", s
->stack
[i
]);
2267 * Here we reset the stack pointer. It's not general correct
2268 * correct to do this, but since I know how the compiler works
2269 * I can do this. The correct way to do this should be to
2270 * subtract number of used elements in each primitive operation.
2281 /* store a flag to let the renderer know if it should expect any "clear"
2283 aperture
->parameter
[0]= (gdouble
) clearOperatorUsed
;
2285 } /* simplify_aperture_macro */
2288 /* ------------------------------------------------------------------ */
2290 parse_aperture_definition(gerb_file_t
*fd
, gerbv_aperture_t
*aperture
,
2291 gerbv_image_t
*image
, gdouble scale
)
2296 gerbv_amacro_t
*curr_amacro
;
2297 gerbv_amacro_t
*amacro
= image
->amacro
;
2298 gerbv_stats_t
*stats
= image
->gerbv_stats
;
2302 if (gerb_fgetc(fd
) != 'D') {
2303 string
= g_strdup_printf("Found AD code with no following 'D' in file \n%s\n",
2305 gerbv_stats_add_error(stats
->error_list
,
2308 GERBV_MESSAGE_ERROR
);
2316 ano
= gerb_fgetint(fd
, NULL
);
2319 * Read in the whole aperture defintion and tokenize it
2321 ad
= gerb_fgetstring(fd
, '*');
2322 token
= strtok(ad
, ",");
2324 if (token
== NULL
) {
2325 string
= g_strdup_printf("Invalid aperture definition in file \n%s\n",
2327 gerbv_stats_add_error(stats
->error_list
,
2330 GERBV_MESSAGE_ERROR
);
2334 if (strlen(token
) == 1) {
2337 aperture
->type
= GERBV_APTYPE_CIRCLE
;
2340 aperture
->type
= GERBV_APTYPE_RECTANGLE
;
2343 aperture
->type
= GERBV_APTYPE_OVAL
;
2346 aperture
->type
= GERBV_APTYPE_POLYGON
;
2349 /* Here a should a T be defined, but I don't know what it represents */
2351 aperture
->type
= GERBV_APTYPE_MACRO
;
2353 * In aperture definition, point to the aperture macro
2354 * used in the defintion
2356 curr_amacro
= amacro
;
2357 while (curr_amacro
) {
2358 if ((strlen(curr_amacro
->name
) == strlen(token
)) &&
2359 (strcmp(curr_amacro
->name
, token
) == 0)) {
2360 aperture
->amacro
= curr_amacro
;
2363 curr_amacro
= curr_amacro
->next
;
2368 * Parse all parameters
2370 for (token
= strtok(NULL
, "X"), i
= 0; token
!= NULL
;
2371 token
= strtok(NULL
, "X"), i
++) {
2372 if (i
== APERTURE_PARAMETERS_MAX
) {
2373 string
= g_strdup_printf("In file %s,\nmaximum number of allowed parameters exceeded in aperture %d\n",
2375 gerbv_stats_add_error(stats
->error_list
,
2378 GERBV_MESSAGE_ERROR
);
2384 tempHolder
= strtod(token
, NULL
);
2385 /* convert any MM values to inches */
2386 /* don't scale polygon angles or side numbers, or macro parmaeters */
2387 if (!(((aperture
->type
== GERBV_APTYPE_POLYGON
) && ((i
==1) || (i
==2)))||
2388 (aperture
->type
== GERBV_APTYPE_MACRO
))) {
2389 tempHolder
/= scale
;
2392 aperture
->parameter
[i
] = tempHolder
;
2394 string
= g_strdup_printf("Failed to read all parameters exceeded in aperture %d\n", ano
);
2395 gerbv_stats_add_error(stats
->error_list
,
2398 GERBV_MESSAGE_WARNING
);
2400 aperture
->parameter
[i
] = 0.0;
2404 aperture
->nuf_parameters
= i
;
2408 if (aperture
->type
== GERBV_APTYPE_MACRO
) {
2409 dprintf("Simplifying aperture %d using aperture macro \"%s\"\n", ano
,
2410 aperture
->amacro
->name
);
2411 simplify_aperture_macro(aperture
, scale
);
2412 dprintf("Done simplifying\n");
2418 } /* parse_aperture_definition */
2421 /* ------------------------------------------------------------------ */
2423 calc_cirseg_sq(struct gerbv_net
*net
, int cw
,
2424 double delta_cp_x
, double delta_cp_y
)
2426 double d1x
, d1y
, d2x
, d2y
;
2432 * Quadrant detection (based on ccw, converted below if cw)
2438 if (net
->start_x
> net
->stop_x
)
2439 /* 1st and 2nd quadrant */
2440 if (net
->start_y
< net
->stop_y
)
2445 /* 3rd and 4th quadrant */
2446 if (net
->start_y
> net
->stop_y
)
2452 * If clockwise, rotate quadrant
2469 GERB_COMPILE_ERROR("Unknow quadrant value while converting to cw\n");
2474 * Calculate arc center point
2478 net
->cirseg
->cp_x
= net
->start_x
- delta_cp_x
;
2479 net
->cirseg
->cp_y
= net
->start_y
- delta_cp_y
;
2482 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
2483 net
->cirseg
->cp_y
= net
->start_y
- delta_cp_y
;
2486 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
2487 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
2490 net
->cirseg
->cp_x
= net
->start_x
- delta_cp_x
;
2491 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
2494 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant
);
2500 d1x
= fabs(net
->start_x
- net
->cirseg
->cp_x
);
2501 d1y
= fabs(net
->start_y
- net
->cirseg
->cp_y
);
2502 d2x
= fabs(net
->stop_x
- net
->cirseg
->cp_x
);
2503 d2y
= fabs(net
->stop_y
- net
->cirseg
->cp_y
);
2505 alfa
= atan2(d1y
, d1x
);
2506 beta
= atan2(d2y
, d2x
);
2509 * Avoid divide by zero when sin(0) = 0 and cos(90) = 0
2511 net
->cirseg
->width
= alfa
< beta
?
2512 2 * (d1x
/ cos(alfa
)) : 2 * (d2x
/ cos(beta
));
2513 net
->cirseg
->height
= alfa
> beta
?
2514 2 * (d1y
/ sin(alfa
)) : 2 * (d2y
/ sin(beta
));
2516 if (alfa
< 0.000001 && beta
< 0.000001) {
2517 net
->cirseg
->height
= 0;
2520 #define RAD2DEG(a) (a * 180 / M_PI)
2524 net
->cirseg
->angle1
= RAD2DEG(alfa
);
2525 net
->cirseg
->angle2
= RAD2DEG(beta
);
2528 net
->cirseg
->angle1
= 180.0 - RAD2DEG(alfa
);
2529 net
->cirseg
->angle2
= 180.0 - RAD2DEG(beta
);
2532 net
->cirseg
->angle1
= 180.0 + RAD2DEG(alfa
);
2533 net
->cirseg
->angle2
= 180.0 + RAD2DEG(beta
);
2536 net
->cirseg
->angle1
= 360.0 - RAD2DEG(alfa
);
2537 net
->cirseg
->angle2
= 360.0 - RAD2DEG(beta
);
2540 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant
);
2543 if (net
->cirseg
->width
< 0.0)
2544 GERB_COMPILE_WARNING("Negative width [%f] in quadrant %d [%f][%f]\n",
2545 net
->cirseg
->width
, quadrant
, alfa
, beta
);
2547 if (net
->cirseg
->height
< 0.0)
2548 GERB_COMPILE_WARNING("Negative height [%f] in quadrant %d [%f][%f]\n",
2549 net
->cirseg
->height
, quadrant
, RAD2DEG(alfa
), RAD2DEG(beta
));
2553 } /* calc_cirseg_sq */
2556 /* ------------------------------------------------------------------ */
2558 calc_cirseg_mq(struct gerbv_net
*net
, int cw
,
2559 double delta_cp_x
, double delta_cp_y
)
2561 double d1x
, d1y
, d2x
, d2y
;
2564 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
2565 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
2570 d1x
= net
->start_x
- net
->cirseg
->cp_x
;
2571 d1y
= net
->start_y
- net
->cirseg
->cp_y
;
2572 d2x
= net
->stop_x
- net
->cirseg
->cp_x
;
2573 d2y
= net
->stop_y
- net
->cirseg
->cp_y
;
2575 alfa
= atan2(d1y
, d1x
);
2576 beta
= atan2(d2y
, d2x
);
2578 net
->cirseg
->width
= sqrt(delta_cp_x
*delta_cp_x
+ delta_cp_y
*delta_cp_y
);
2579 net
->cirseg
->width
*= 2.0;
2580 net
->cirseg
->height
= net
->cirseg
->width
;
2582 net
->cirseg
->angle1
= RAD2DEG(alfa
);
2583 net
->cirseg
->angle2
= RAD2DEG(beta
);
2586 * Make sure it's always positive angles
2588 if (net
->cirseg
->angle1
< 0.0) {
2589 net
->cirseg
->angle1
+= 360.0;
2590 net
->cirseg
->angle2
+= 360.0;
2593 if (net
->cirseg
->angle2
< 0.0)
2594 net
->cirseg
->angle2
+= 360.0;
2596 if(net
->cirseg
->angle2
== 0.0)
2597 net
->cirseg
->angle2
= 360.0;
2600 * This is a sanity check for angles after the nature of atan2.
2601 * If cw we must make sure angle1-angle2 are always positive,
2602 * If ccw we must make sure angle2-angle1 are always negative.
2603 * We should really return one angle and the difference as GTK
2604 * uses them. But what the heck, it works for me.
2607 if (net
->cirseg
->angle1
<= net
->cirseg
->angle2
)
2608 net
->cirseg
->angle2
-= 360.0;
2610 if (net
->cirseg
->angle1
>= net
->cirseg
->angle2
)
2611 net
->cirseg
->angle2
+= 360.0;
2615 } /* calc_cirseg_mq */
2619 gerber_update_any_running_knockout_measurements (gerbv_image_t
*image
)
2621 if (knockoutMeasure
) {
2622 knockoutLayer
->knockout
.lowerLeftX
= knockoutLimitXmin
;
2623 knockoutLayer
->knockout
.lowerLeftY
= knockoutLimitYmin
;
2624 knockoutLayer
->knockout
.width
= knockoutLimitXmax
- knockoutLimitXmin
;
2625 knockoutLayer
->knockout
.height
= knockoutLimitYmax
- knockoutLimitYmin
;
2626 knockoutMeasure
= FALSE
;
2632 gerber_calculate_final_justify_effects(gerbv_image_t
*image
)
2634 gdouble translateA
= 0.0, translateB
= 0.0;
2636 if (image
->info
->imageJustifyTypeA
!= GERBV_JUSTIFY_NOJUSTIFY
) {
2637 if (image
->info
->imageJustifyTypeA
== GERBV_JUSTIFY_CENTERJUSTIFY
)
2638 translateA
= (image
->info
->max_x
- image
->info
->min_x
) / 2.0;
2640 translateA
= -image
->info
->min_x
;
2642 if (image
->info
->imageJustifyTypeB
!= GERBV_JUSTIFY_NOJUSTIFY
) {
2643 if (image
->info
->imageJustifyTypeB
== GERBV_JUSTIFY_CENTERJUSTIFY
)
2644 translateB
= (image
->info
->max_y
- image
->info
->min_y
) / 2.0;
2646 translateB
= -image
->info
->min_y
;
2649 /* update the min/max values so the autoscale function can correctly
2650 centered a justified image */
2651 image
->info
->min_x
+= translateA
+ image
->info
->imageJustifyOffsetA
;
2652 image
->info
->max_x
+= translateA
+ image
->info
->imageJustifyOffsetA
;
2653 image
->info
->min_y
+= translateB
+ image
->info
->imageJustifyOffsetB
;
2654 image
->info
->max_y
+= translateB
+ image
->info
->imageJustifyOffsetB
;
2656 /* store the absolute offset for the justify so we can quickly offset
2657 the rendered picture during drawing */
2658 image
->info
->imageJustifyOffsetActualA
= translateA
+
2659 image
->info
->imageJustifyOffsetA
;
2660 image
->info
->imageJustifyOffsetActualB
= translateB
+
2661 image
->info
->imageJustifyOffsetB
;
2662 } /* gerber_calculate_final_justify_effects */
2665 void gerber_update_image_min_max (gerbv_render_size_t
*boundingBox
, double repeat_off_X
,
2666 double repeat_off_Y
, gerbv_image_t
* image
) {
2667 if (boundingBox
->left
< image
->info
->min_x
)
2668 image
->info
->min_x
= boundingBox
->left
;
2669 if (boundingBox
->right
+repeat_off_X
> image
->info
->max_x
)
2670 image
->info
->max_x
= boundingBox
->right
+repeat_off_X
;
2671 if (boundingBox
->bottom
< image
->info
->min_y
)
2672 image
->info
->min_y
= boundingBox
->bottom
;
2673 if (boundingBox
->top
+repeat_off_Y
> image
->info
->max_y
)
2674 image
->info
->max_y
= boundingBox
->top
+repeat_off_Y
;
2678 gerber_update_min_and_max(gerbv_render_size_t
*boundingBox
,
2679 gdouble x
, gdouble y
, gdouble apertureSizeX1
,
2680 gdouble apertureSizeX2
,gdouble apertureSizeY1
,
2681 gdouble apertureSizeY2
)
2683 gdouble ourX1
= x
- apertureSizeX1
, ourY1
= y
- apertureSizeY1
;
2684 gdouble ourX2
= x
+ apertureSizeX2
, ourY2
= y
+ apertureSizeY2
;
2686 /* transform the point to the final rendered position, accounting
2687 for any scaling, offsets, mirroring, etc */
2688 /* NOTE: we need to already add/subtract in the aperture size since
2689 the final rendering may be scaled */
2690 cairo_matrix_transform_point (¤tMatrix
, &ourX1
, &ourY1
);
2691 cairo_matrix_transform_point (¤tMatrix
, &ourX2
, &ourY2
);
2693 /* check both points against the min/max, since depending on the rotation,
2694 mirroring, etc, either point could possibly be a min or max */
2695 if(boundingBox
->left
> ourX1
)
2696 boundingBox
->left
= ourX1
;
2697 if(boundingBox
->left
> ourX2
)
2698 boundingBox
->left
= ourX2
;
2699 if(boundingBox
->right
< ourX1
)
2700 boundingBox
->right
= ourX1
;
2701 if(boundingBox
->right
< ourX2
)
2702 boundingBox
->right
= ourX2
;
2703 if(boundingBox
->bottom
> ourY1
)
2704 boundingBox
->bottom
= ourY1
;
2705 if(boundingBox
->bottom
> ourY2
)
2706 boundingBox
->bottom
= ourY2
;
2707 if(boundingBox
->top
< ourY1
)
2708 boundingBox
->top
= ourY1
;
2709 if(boundingBox
->top
< ourY2
)
2710 boundingBox
->top
= ourY2
;
2711 } /* gerber_update_min_and_max */