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 gerber_update_min_and_max(gerbv_render_size_t
*boundingBox
,
80 gdouble x
, gdouble y
, gdouble apertureSizeX1
,
81 gdouble apertureSizeX2
,gdouble apertureSizeY1
,
82 gdouble apertureSizeY2
);
85 static void gerber_update_any_running_knockout_measurements(gerbv_image_t
*image
);
87 static void gerber_calculate_final_justify_effects (gerbv_image_t
*image
);
89 gboolean knockoutMeasure
= FALSE
;
90 gdouble knockoutLimitXmin
, knockoutLimitYmin
, knockoutLimitXmax
,
92 gerbv_layer_t
*knockoutLayer
= NULL
;
93 cairo_matrix_t currentMatrix
;
96 /* --------------------------------------------------------- */
98 gerber_create_new_net (gerbv_net_t
*currentNet
, gerbv_layer_t
*layer
, gerbv_netstate_t
*state
){
99 gerbv_net_t
*newNet
= g_new0 (gerbv_net_t
, 1);
101 currentNet
->next
= newNet
;
103 newNet
->layer
= layer
;
105 newNet
->layer
= currentNet
->layer
;
107 newNet
->state
= state
;
109 newNet
->state
= currentNet
->state
;
113 /* --------------------------------------------------------- */
115 gerber_create_new_aperture (gerbv_image_t
*image
, int *indexNumber
,
116 gerbv_aperture_type_t apertureType
, gdouble parameter1
, gdouble parameter2
){
119 /* search for an available aperture spot */
120 for (i
= 0; i
<= APERTURE_MAX
; i
++) {
121 if (image
->aperture
[i
] == NULL
) {
122 image
->aperture
[i
] = g_new0 (gerbv_aperture_t
, 1);
123 image
->aperture
[i
]->type
= apertureType
;
124 image
->aperture
[i
]->parameter
[0] = parameter1
;
125 image
->aperture
[i
]->parameter
[1] = parameter2
;
133 /* --------------------------------------------------------- */
134 /*! This function reads the Gerber file char by char, looking
135 * for various Gerber codes (e.g. G, D, etc). Once it reads
136 * a code, it then dispatches control to one or another
137 * bits of code which parse the individual code.
138 * It also updates the state struct, which holds info about
139 * the current state of the hypothetical photoplotter
140 * (i.e. updates whether the aperture is on or off, updates
141 * any other parameters, like units, offsets, apertures, etc.)
144 gerber_parse_file_segment (gint levelOfRecursion
, gerbv_image_t
*image
,
145 gerb_state_t
*state
, gerbv_net_t
*curr_net
,
146 gerbv_stats_t
*stats
, gerb_file_t
*fd
,
147 gchar
*directoryPath
) {
148 int read
, coord
, len
, polygonPoints
=0;
149 double x_scale
= 0.0, y_scale
= 0.0;
150 double delta_cp_x
= 0.0, delta_cp_y
= 0.0;
151 double aperture_sizeX
, aperture_sizeY
;
153 gboolean foundEOF
= FALSE
;
155 gerbv_render_size_t boundingBox
={HUGE_VAL
,-HUGE_VAL
,HUGE_VAL
,-HUGE_VAL
};
157 while ((read
= gerb_fgetc(fd
)) != EOF
) {
158 /* figure out the scale, since we need to normalize
159 all dimensions to inches */
160 if (state
->state
->unit
== GERBV_UNIT_MM
)
164 switch ((char)(read
& 0xff)) {
166 dprintf("... Found G code\n");
167 parse_G_code(fd
, state
, image
);
170 dprintf("... Found D code\n");
171 parse_D_code(fd
, state
, image
);
174 dprintf("... Found M code\n");
175 switch(parse_M_code(fd
, image
)) {
182 gerbv_stats_add_error(stats
->error_list
,
184 "Unknown M code found.\n",
185 GERBV_MESSAGE_ERROR
);
186 } /* switch(parse_M_code) */
189 dprintf("... Found X code\n");
191 coord
= gerb_fgetint(fd
, &len
);
192 if (image
->format
&& image
->format
->omit_zeros
== GERBV_OMIT_ZEROS_TRAILING
) {
194 switch ((image
->format
->x_int
+ image
->format
->x_dec
) - len
) {
210 if (image
->format
&& (image
->format
->coordinate
==GERBV_COORDINATE_INCREMENTAL
))
211 state
->curr_x
+= coord
;
213 state
->curr_x
= coord
;
217 dprintf("... Found Y code\n");
219 coord
= gerb_fgetint(fd
, &len
);
220 if (image
->format
&& image
->format
->omit_zeros
== GERBV_OMIT_ZEROS_TRAILING
) {
222 switch ((image
->format
->y_int
+ image
->format
->y_dec
) - len
) {
238 if (image
->format
&& (image
->format
->coordinate
==GERBV_COORDINATE_INCREMENTAL
))
239 state
->curr_y
+= coord
;
241 state
->curr_y
= coord
;
245 dprintf("... Found I code\n");
247 state
->delta_cp_x
= gerb_fgetint(fd
, NULL
);
251 dprintf("... Found J code\n");
253 state
->delta_cp_y
= gerb_fgetint(fd
, NULL
);
257 dprintf("... Found %% code\n");
258 parse_rs274x(levelOfRecursion
, fd
, image
, state
, curr_net
, stats
, directoryPath
);
260 int c
= gerb_fgetc(fd
);
261 if(c
== EOF
|| c
== '%')
266 dprintf("... Found * code\n");
268 if (state
->changed
== 0) break;
271 /* don't even bother saving the net if the aperture state is GERBV_APERTURE_STATE_OFF and we
272 aren't starting a polygon fill (where we need it to get to the start point) */
273 if ((state
->aperture_state
== GERBV_APERTURE_STATE_OFF
)&&(!state
->in_parea_fill
)&&
274 (state
->interpolation
!= GERBV_INTERPOLATION_PAREA_START
)) {
275 /* save the coordinate so the next net can use it for a start point */
276 state
->prev_x
= state
->curr_x
;
277 state
->prev_y
= state
->curr_y
;
280 curr_net
= gerber_create_new_net (curr_net
, state
->layer
, state
->state
);
282 * Scale to given coordinate format
283 * XXX only "omit leading zeros".
285 if (image
&& image
->format
){
286 x_scale
= pow(10.0, (double)image
->format
->x_dec
);
287 y_scale
= pow(10.0, (double)image
->format
->y_dec
);
291 curr_net
->start_x
= (double)state
->prev_x
/ x_scale
;
292 curr_net
->start_y
= (double)state
->prev_y
/ y_scale
;
293 curr_net
->stop_x
= (double)state
->curr_x
/ x_scale
;
294 curr_net
->stop_y
= (double)state
->curr_y
/ y_scale
;
295 delta_cp_x
= (double)state
->delta_cp_x
/ x_scale
;
296 delta_cp_y
= (double)state
->delta_cp_y
/ y_scale
;
299 switch (state
->interpolation
) {
300 case GERBV_INTERPOLATION_CW_CIRCULAR
:
301 curr_net
->cirseg
= g_new0 (gerbv_cirseg_t
,1);
303 calc_cirseg_mq(curr_net
, 1, delta_cp_x
, delta_cp_y
);
305 calc_cirseg_sq(curr_net
, 1, delta_cp_x
, delta_cp_y
);
307 case GERBV_INTERPOLATION_CCW_CIRCULAR
:
308 curr_net
->cirseg
= g_new0 (gerbv_cirseg_t
,1);
310 calc_cirseg_mq(curr_net
, 0, delta_cp_x
, delta_cp_y
);
312 calc_cirseg_sq(curr_net
, 0, delta_cp_x
, delta_cp_y
);
314 case GERBV_INTERPOLATION_PAREA_START
:
316 * To be able to get back and fill in number of polygon corners
318 state
->parea_start_node
= curr_net
;
319 state
->in_parea_fill
= 1;
321 /* reset the bounding box */
322 boundingBox
.left
= HUGE_VAL
;
323 boundingBox
.right
= -HUGE_VAL
;
324 boundingBox
.top
= -HUGE_VAL
;
325 boundingBox
.bottom
= HUGE_VAL
;
327 case GERBV_INTERPOLATION_PAREA_END
:
328 /* save the calculated bounding box to the master node */
329 state
->parea_start_node
->boundingBox
= boundingBox
;
330 /* close out the polygon */
331 state
->parea_start_node
= NULL
;
332 state
->in_parea_fill
= 0;
337 } /* switch(state->interpolation) */
340 * Count number of points in Polygon Area
342 if (state
->in_parea_fill
&& state
->parea_start_node
) {
344 * "...all lines drawn with D01 are considered edges of the
345 * polygon. D02 closes and fills the polygon."
346 * p.49 rs274xrevd_e.pdf
347 * D02 -> state->aperture_state == GERBV_APERTURE_STATE_OFF
350 /* UPDATE: only end the polygon during a D02 call if we've already
351 drawn a polygon edge (with D01) */
353 if ((state
->aperture_state
== GERBV_APERTURE_STATE_OFF
&&
354 state
->interpolation
!= GERBV_INTERPOLATION_PAREA_START
) && (polygonPoints
> 0)) {
355 curr_net
->interpolation
= GERBV_INTERPOLATION_PAREA_END
;
356 curr_net
= gerber_create_new_net (curr_net
, state
->layer
, state
->state
);
357 curr_net
->interpolation
= GERBV_INTERPOLATION_PAREA_START
;
358 state
->parea_start_node
->boundingBox
= boundingBox
;
359 state
->parea_start_node
= curr_net
;
361 curr_net
= gerber_create_new_net (curr_net
, state
->layer
, state
->state
);
362 curr_net
->start_x
= (double)state
->prev_x
/ x_scale
;
363 curr_net
->start_y
= (double)state
->prev_y
/ y_scale
;
364 curr_net
->stop_x
= (double)state
->curr_x
/ x_scale
;
365 curr_net
->stop_y
= (double)state
->curr_y
/ y_scale
;
366 /* reset the bounding box */
367 boundingBox
.left
= HUGE_VAL
;
368 boundingBox
.right
= -HUGE_VAL
;
369 boundingBox
.top
= -HUGE_VAL
;
370 boundingBox
.bottom
= HUGE_VAL
;
372 else if (state
->interpolation
!= GERBV_INTERPOLATION_PAREA_START
)
375 } /* if (state->in_parea_fill && state->parea_start_node) */
377 curr_net
->interpolation
= state
->interpolation
;
380 * Override circular interpolation if no center was given.
381 * This should be a safe hack, since a good file should always
382 * include I or J. And even if the radius is zero, the endpoint
383 * should be the same as the start point, creating no line
385 if (((state
->interpolation
== GERBV_INTERPOLATION_CW_CIRCULAR
) ||
386 (state
->interpolation
== GERBV_INTERPOLATION_CCW_CIRCULAR
)) &&
387 ((state
->delta_cp_x
== 0.0) && (state
->delta_cp_y
== 0.0)))
388 curr_net
->interpolation
= GERBV_INTERPOLATION_LINEARx1
;
391 * If we detected the end of Polygon Area Fill we go back to
392 * the interpolation we had before that.
393 * Also if we detected any of the quadrant flags, since some
394 * gerbers don't reset the interpolation (EagleCad again).
396 if ((state
->interpolation
== GERBV_INTERPOLATION_PAREA_START
) ||
397 (state
->interpolation
== GERBV_INTERPOLATION_PAREA_END
))
398 state
->interpolation
= state
->prev_interpolation
;
401 * Save layer polarity and unit
403 curr_net
->layer
= state
->layer
;
405 state
->delta_cp_x
= 0.0;
406 state
->delta_cp_y
= 0.0;
407 curr_net
->aperture
= state
->curr_aperture
;
408 curr_net
->aperture_state
= state
->aperture_state
;
411 * For next round we save the current position as
412 * the previous position
414 state
->prev_x
= state
->curr_x
;
415 state
->prev_y
= state
->curr_y
;
418 * If we have an aperture defined at the moment we find
419 * min and max of image with compensation for mm.
421 if ((curr_net
->aperture
== 0) && !state
->in_parea_fill
)
424 /* only update the min/max values and aperture stats if we are drawing */
425 if ((curr_net
->aperture_state
!= GERBV_APERTURE_STATE_OFF
)&&
426 (curr_net
->interpolation
!= GERBV_INTERPOLATION_PAREA_START
)){
427 double repeat_off_X
= 0.0, repeat_off_Y
= 0.0;
429 /* Update stats with current aperture number if not in polygon */
430 if (!state
->in_parea_fill
) {
431 dprintf(" In parse_D_code, adding 1 to D_list ...\n");
432 int retcode
= gerbv_stats_increment_D_list_count(stats
->D_code_list
,
437 string
= g_strdup_printf("Found undefined D code D%d in file \n%s\n",
440 gerbv_stats_add_error(stats
->error_list
,
443 GERBV_MESSAGE_ERROR
);
450 * If step_and_repeat (%SR%) is used, check min_x,max_y etc for
451 * the ends of the step_and_repeat lattice. This goes wrong in
452 * the case of negative dist_X or dist_Y, in which case we
453 * should compare against the startpoints of the lines, not
454 * the stoppoints, but that seems an uncommon case (and the
455 * error isn't very big any way).
457 repeat_off_X
= (state
->layer
->stepAndRepeat
.X
- 1) *
458 state
->layer
->stepAndRepeat
.dist_X
;
459 repeat_off_Y
= (state
->layer
->stepAndRepeat
.Y
- 1) *
460 state
->layer
->stepAndRepeat
.dist_Y
;
462 cairo_matrix_init (¤tMatrix
, 1, 0, 0, 1, 0, 0);
464 cairo_matrix_translate (¤tMatrix
, image
->info
->offsetA
,
465 image
->info
->offsetB
);
466 /* do image rotation */
467 cairo_matrix_rotate (¤tMatrix
, image
->info
->imageRotation
);
468 /* it's a new layer, so recalculate the new transformation
470 /* do any rotations */
471 cairo_matrix_rotate (¤tMatrix
, state
->layer
->rotation
);
473 /* calculate current layer and state transformation matrices */
474 /* apply scale factor */
475 cairo_matrix_scale (¤tMatrix
, state
->state
->scaleA
,
476 state
->state
->scaleB
);
478 cairo_matrix_translate (¤tMatrix
, state
->state
->offsetA
,
479 state
->state
->offsetB
);
481 switch (state
->state
->mirrorState
) {
482 case GERBV_MIRROR_STATE_FLIPA
:
483 cairo_matrix_scale (¤tMatrix
, -1, 1);
485 case GERBV_MIRROR_STATE_FLIPB
:
486 cairo_matrix_scale (¤tMatrix
, 1, -1);
488 case GERBV_MIRROR_STATE_FLIPAB
:
489 cairo_matrix_scale (¤tMatrix
, -1, -1);
494 /* finally, apply axis select */
495 if (state
->state
->axisSelect
== GERBV_AXIS_SELECT_SWAPAB
) {
496 /* we do this by rotating 270 (counterclockwise, then
497 * mirroring the Y axis
499 cairo_matrix_rotate (¤tMatrix
, 3 * M_PI
/ 2);
500 cairo_matrix_scale (¤tMatrix
, 1, -1);
502 /* if it's a macro, step through all the primitive components
503 and calculate the true bounding box */
504 if ((image
->aperture
[curr_net
->aperture
] != NULL
) &&
505 (image
->aperture
[curr_net
->aperture
]->type
== GERBV_APTYPE_MACRO
)) {
506 gerbv_simplified_amacro_t
*ls
= image
->aperture
[curr_net
->aperture
]->simplified
;
509 gdouble offsetx
= 0, offsety
= 0, widthx
= 0, widthy
= 0;
510 gboolean calculatedAlready
= FALSE
;
512 if (ls
->type
== GERBV_APTYPE_MACRO_CIRCLE
) {
513 offsetx
=ls
->parameter
[CIRCLE_CENTER_X
];
514 offsety
=ls
->parameter
[CIRCLE_CENTER_Y
];
515 widthx
=widthy
=ls
->parameter
[CIRCLE_DIAMETER
];
516 } else if (ls
->type
== GERBV_APTYPE_MACRO_OUTLINE
) {
517 int pointCounter
,numberOfPoints
;
518 numberOfPoints
= (int) ls
->parameter
[OUTLINE_NUMBER_OF_POINTS
];
520 for (pointCounter
= 0; pointCounter
<= numberOfPoints
; pointCounter
++) {
521 gerber_update_min_and_max (&boundingBox
,
523 ls
->parameter
[pointCounter
* 2 + OUTLINE_FIRST_X
],
525 ls
->parameter
[pointCounter
* 2 + OUTLINE_FIRST_Y
],
528 calculatedAlready
= TRUE
;
529 } else if (ls
->type
== GERBV_APTYPE_MACRO_POLYGON
) {
530 offsetx
= ls
->parameter
[POLYGON_CENTER_X
];
531 offsety
= ls
->parameter
[POLYGON_CENTER_Y
];
532 widthx
= widthy
= ls
->parameter
[POLYGON_DIAMETER
];
533 } else if (ls
->type
== GERBV_APTYPE_MACRO_MOIRE
) {
534 offsetx
= ls
->parameter
[MOIRE_CENTER_X
];
535 offsety
= ls
->parameter
[MOIRE_CENTER_Y
];
536 widthx
= widthy
= ls
->parameter
[MOIRE_OUTSIDE_DIAMETER
];
537 } else if (ls
->type
== GERBV_APTYPE_MACRO_THERMAL
) {
538 offsetx
= ls
->parameter
[THERMAL_CENTER_X
];
539 offsety
= ls
->parameter
[THERMAL_CENTER_Y
];
540 widthx
= widthy
= ls
->parameter
[THERMAL_OUTSIDE_DIAMETER
];
541 } else if (ls
->type
== GERBV_APTYPE_MACRO_LINE20
) {
542 widthx
= widthy
= ls
->parameter
[LINE20_LINE_WIDTH
];
543 gerber_update_min_and_max (&boundingBox
,
545 ls
->parameter
[LINE20_START_X
],
547 ls
->parameter
[LINE20_START_Y
],
548 widthx
/2,widthx
/2,widthy
/2,widthy
/2);
549 gerber_update_min_and_max (&boundingBox
,
551 ls
->parameter
[LINE20_END_X
],
553 ls
->parameter
[LINE20_END_Y
],
554 widthx
/2,widthx
/2,widthy
/2,widthy
/2);
555 calculatedAlready
= TRUE
;
556 } else if (ls
->type
== GERBV_APTYPE_MACRO_LINE21
) {
557 gdouble largestDimension
= sqrt (ls
->parameter
[LINE21_WIDTH
]/2 *
558 ls
->parameter
[LINE21_WIDTH
]/2 + ls
->parameter
[LINE21_HEIGHT
/2] *
559 ls
->parameter
[LINE21_HEIGHT
]/2);
561 offsetx
= ls
->parameter
[LINE21_CENTER_X
];
562 offsety
= ls
->parameter
[LINE21_CENTER_Y
];
563 widthx
= widthy
=largestDimension
;
564 } else if (ls
->type
== GERBV_APTYPE_MACRO_LINE22
) {
565 gdouble largestDimension
= sqrt (ls
->parameter
[LINE22_WIDTH
]/2 *
566 ls
->parameter
[LINE22_WIDTH
]/2 + ls
->parameter
[LINE22_HEIGHT
/2] *
567 ls
->parameter
[LINE22_HEIGHT
]/2);
569 offsetx
= ls
->parameter
[LINE22_LOWER_LEFT_X
] +
570 ls
->parameter
[LINE22_WIDTH
]/2;
571 offsety
= ls
->parameter
[LINE22_LOWER_LEFT_Y
] +
572 ls
->parameter
[LINE22_HEIGHT
]/2;
573 widthx
= widthy
=largestDimension
;
576 if (!calculatedAlready
) {
577 gerber_update_min_and_max (&boundingBox
,
578 curr_net
->stop_x
+ offsetx
,
579 curr_net
->stop_y
+ offsety
,
580 widthx
/2,widthx
/2,widthy
/2,widthy
/2);
585 if (image
->aperture
[curr_net
->aperture
] != NULL
) {
586 aperture_sizeX
= image
->aperture
[curr_net
->aperture
]->parameter
[0];
587 if ((image
->aperture
[curr_net
->aperture
]->type
== GERBV_APTYPE_RECTANGLE
) || (image
->aperture
[curr_net
->aperture
]->type
== GERBV_APTYPE_OVAL
)) {
588 aperture_sizeY
= image
->aperture
[curr_net
->aperture
]->parameter
[1];
591 aperture_sizeY
= aperture_sizeX
;
593 /* this is usually for polygon fills, where the aperture width
595 aperture_sizeX
= aperture_sizeY
= 0;
597 /* if it's an arc path, use a special calc */
598 if ((curr_net
->interpolation
== GERBV_INTERPOLATION_CW_CIRCULAR
) ||
599 (curr_net
->interpolation
== GERBV_INTERPOLATION_CCW_CIRCULAR
)) {
600 /* to calculate the arc bounding box, we chop it into 1 degree steps, calculate
601 the point at each step, and use it to figure out the bounding box */
602 gdouble angleDiff
= curr_net
->cirseg
->angle2
- curr_net
->cirseg
->angle1
;
603 gint i
, steps
= abs(angleDiff
);
604 for (i
=0; i
<=steps
; i
++){
605 gdouble tempX
= curr_net
->cirseg
->cp_x
+ curr_net
->cirseg
->width
/ 2.0 *
606 cos ((curr_net
->cirseg
->angle1
+
607 (angleDiff
* i
) / steps
)*M_PI
/180);
608 gdouble tempY
= curr_net
->cirseg
->cp_y
+ curr_net
->cirseg
->width
/ 2.0 *
609 sin ((curr_net
->cirseg
->angle1
+
610 (angleDiff
* i
) / steps
)*M_PI
/180);
611 gerber_update_min_and_max (&boundingBox
,
613 aperture_sizeX
/2,aperture_sizeX
/2,
614 aperture_sizeY
/2,aperture_sizeY
/2);
619 /* check both the start and stop of the aperture points against
620 a running min/max counter */
621 /* Note: only check start coordinate if this isn't a flash,
622 since the start point may be bogus if it is a flash */
623 if (curr_net
->aperture_state
!= GERBV_APERTURE_STATE_FLASH
) {
624 gerber_update_min_and_max (&boundingBox
,
625 curr_net
->start_x
, curr_net
->start_y
,
626 aperture_sizeX
/2,aperture_sizeX
/2,
627 aperture_sizeY
/2,aperture_sizeY
/2);
629 gerber_update_min_and_max (&boundingBox
,
630 curr_net
->stop_x
, curr_net
->stop_y
,
631 aperture_sizeX
/2,aperture_sizeX
/2,
632 aperture_sizeY
/2,aperture_sizeY
/2);
636 /* update the info bounding box with this latest bounding box */
637 if (boundingBox
.left
< image
->info
->min_x
)
638 image
->info
->min_x
= boundingBox
.left
;
639 if (boundingBox
.right
+repeat_off_X
> image
->info
->max_x
)
640 image
->info
->max_x
= boundingBox
.right
+repeat_off_X
;
641 if (boundingBox
.bottom
< image
->info
->min_y
)
642 image
->info
->min_y
= boundingBox
.bottom
;
643 if (boundingBox
.top
+repeat_off_Y
> image
->info
->max_y
)
644 image
->info
->max_y
= boundingBox
.top
+repeat_off_Y
;
645 /* optionally update the knockout measurement box */
646 if (knockoutMeasure
) {
647 if (boundingBox
.left
< knockoutLimitXmin
)
648 knockoutLimitXmin
= boundingBox
.left
;
649 if (boundingBox
.right
+repeat_off_X
> knockoutLimitXmax
)
650 knockoutLimitXmax
= boundingBox
.right
+repeat_off_X
;
651 if (boundingBox
.bottom
< knockoutLimitYmin
)
652 knockoutLimitYmin
= boundingBox
.bottom
;
653 if (boundingBox
.top
+repeat_off_Y
> knockoutLimitYmax
)
654 knockoutLimitYmax
= boundingBox
.top
+repeat_off_Y
;
656 /* if we're not in a polygon fill, then update the object bounding box */
657 if (!state
->in_parea_fill
) {
658 curr_net
->boundingBox
= boundingBox
;
659 /* and reset the bounding box */
660 boundingBox
.left
= HUGE_VAL
;
661 boundingBox
.right
= -HUGE_VAL
;
662 boundingBox
.bottom
= HUGE_VAL
;
663 boundingBox
.top
= -HUGE_VAL
;
667 case 10 : /* White space */
675 string
= g_strdup_printf("Found unknown character (whitespace?) [%d]%c\n",
677 gerbv_stats_add_error(stats
->error_list
,
680 GERBV_MESSAGE_ERROR
);
682 } /* switch((char) (read & 0xff)) */
688 /* ------------------------------------------------------------------ */
689 /*! This is a wrapper which gets called from top level. It
690 * does some initialization and pre-processing, and
691 * then calls gerber_parse_file_segment
692 * which processes the actual file. Then it does final
693 * modifications to the image created.
696 parse_gerb(gerb_file_t
*fd
, gchar
*directoryPath
)
698 gerb_state_t
*state
= NULL
;
699 gerbv_image_t
*image
= NULL
;
700 gerbv_net_t
*curr_net
= NULL
;
701 gerbv_stats_t
*stats
;
702 gboolean foundEOF
= FALSE
;
705 /* added by t.motylewski@bfad.de
706 * many locales redefine "." as "," and so on,
707 * so sscanf and strtod has problems when
708 * reading files using %f format */
709 setlocale(LC_NUMERIC
, "C" );
712 * Create new state. This is used locally to keep track
713 * of the photoplotter's state as the Gerber is read in.
715 state
= g_new0 (gerb_state_t
, 1);
718 * Create new image. This will be returned.
720 image
= gerbv_create_image(image
, "RS274-X (Gerber) File");
722 GERB_FATAL_ERROR("malloc image failed\n");
723 curr_net
= image
->netlist
;
724 image
->layertype
= GERBV_LAYERTYPE_RS274X
;
725 image
->gerbv_stats
= gerbv_stats_new();
726 if (image
->gerbv_stats
== NULL
)
727 GERB_FATAL_ERROR("malloc gerbv_stats failed\n");
728 stats
= (gerbv_stats_t
*) image
->gerbv_stats
;
730 /* set active layer and netstate to point to first default one created */
731 state
->layer
= image
->layers
;
732 state
->state
= image
->states
;
733 curr_net
->layer
= state
->layer
;
734 curr_net
->state
= state
->state
;
739 dprintf("In parse_gerb, starting to parse file...\n");
740 foundEOF
= gerber_parse_file_segment (1, image
, state
, curr_net
, stats
,
744 string
= g_strdup_printf("File %s is missing Gerber EOF code.\n", fd
->filename
);
745 gerbv_stats_add_error(stats
->error_list
,
748 GERBV_MESSAGE_ERROR
);
753 dprintf(" ... done parsing Gerber file\n");
754 gerber_update_any_running_knockout_measurements (image
);
755 gerber_calculate_final_justify_effects(image
);
761 /* ------------------------------------------------------------------- */
762 /*! Checks for signs that this is a RS-274X file
763 * Returns TRUE if it is, FALSE if not.
766 gerber_is_rs274x_p(gerb_file_t
*fd
, gboolean
*returnFoundBinary
)
773 gboolean found_binary
= FALSE
;
774 gboolean found_ADD
= FALSE
;
775 gboolean found_D0
= FALSE
;
776 gboolean found_D2
= FALSE
;
777 gboolean found_M0
= FALSE
;
778 gboolean found_M2
= FALSE
;
779 gboolean found_star
= FALSE
;
780 gboolean found_X
= FALSE
;
781 gboolean found_Y
= FALSE
;
783 dprintf ("gerber_is_rs274x_p(%p, %p), fd->fd = %p, fd->zfd = %p %s\n",
784 fd
, returnFoundBinary
, fd
->fd
, fd
->zfd
, fd
->filename
);
786 buf
= (char *) g_malloc(MAXL
);
788 GERB_FATAL_ERROR("malloc buf failed while checking for rs274x.\n");
792 if (fd
->datalen
== idx
) {
796 len
= ((fd
->datalen
- idx
) < MAXL
)? (fd
->datalen
- idx
) : MAXL
;
797 memset(buf
, 0, MAXL
);
798 memcpy(buf
, &fd
->data
[idx
], len
);
800 dprintf ("buf = \"%s\"\n", buf
);
802 /* First look through the file for indications of its type by
803 * checking that file is not binary (non-printing chars and white
806 for (i
= 0; i
< len
; i
++) {
807 if (!isprint((int) buf
[i
]) && (buf
[i
] != '\r') &&
808 (buf
[i
] != '\n') && (buf
[i
] != '\t')) {
810 dprintf ("found_binary (%d)\n", buf
[i
]);
813 if (g_strstr_len(buf
, len
, "%ADD")) {
815 dprintf ("found_ADD\n");
817 if (g_strstr_len(buf
, len
, "D00")) {
819 dprintf ("found_D0\n");
821 if (g_strstr_len(buf
, len
, "D02")) {
823 dprintf ("found_D2\n");
825 if (g_strstr_len(buf
, len
, "M0")) {
827 dprintf ("found_M0\n");
829 if (g_strstr_len(buf
, len
, "M00")) {
831 dprintf ("found_M0\n");
833 if (g_strstr_len(buf
, len
, "M2")) {
835 dprintf ("found_M2\n");
837 if (g_strstr_len(buf
, len
, "M02")) {
839 dprintf ("found_M2\n");
841 if (g_strstr_len(buf
, len
, "*")) {
843 dprintf ("found_star\n");
845 /* look for X<number> or Y<number> */
846 if ((letter
= g_strstr_len(buf
, len
, "X")) != NULL
) {
847 if (isdigit((int) letter
[1])) { /* grab char after X */
849 dprintf ("found_X\n");
852 if ((letter
= g_strstr_len(buf
, len
, "Y")) != NULL
) {
853 if (isdigit((int) letter
[1])) { /* grab char after Y */
855 dprintf ("found_Y\n");
861 *returnFoundBinary
= found_binary
;
863 dprintf("Done checking RS274X\n");
865 /* Now form logical expression determining if the file is RS-274X */
866 if ((found_D0
|| found_D2
|| found_M0
|| found_M2
) &&
867 found_ADD
&& found_star
&& (found_X
|| found_Y
))
873 } /* gerber_is_rs274x */
876 /* ------------------------------------------------------------------- */
877 /*! Checks for signs that this is a RS-274D file
878 * Returns TRUE if it is, FALSE if not.
881 gerber_is_rs274d_p(gerb_file_t
*fd
)
888 gboolean found_binary
= FALSE
;
889 gboolean found_ADD
= FALSE
;
890 gboolean found_D0
= FALSE
;
891 gboolean found_D2
= FALSE
;
892 gboolean found_M0
= FALSE
;
893 gboolean found_M2
= FALSE
;
894 gboolean found_star
= FALSE
;
895 gboolean found_X
= FALSE
;
896 gboolean found_Y
= FALSE
;
898 dprintf ("gerber_is_rs274d_p(%p), fd->fd = %p, fd->zfd = %p %s\n",
899 fd
, fd
->fd
, fd
->zfd
, fd
->filename
);
903 GERB_FATAL_ERROR("malloc buf failed while checking for rs274d.\n");
907 if (fd
->datalen
== idx
) {
911 len
= ((fd
->datalen
- idx
) < MAXL
)? (fd
->datalen
- idx
) : MAXL
;
912 memset(buf
, 0, MAXL
);
913 memcpy(buf
, &fd
->data
[idx
], len
);
915 dprintf ("buf = \"%s\"\n", buf
);
917 /* First look through the file for indications of its type */
919 /* check that file is not binary (non-printing chars */
920 for (i
= 0; i
< len
; i
++) {
921 if (!isprint( (int) buf
[i
]) && (buf
[i
] != '\r') &&
922 (buf
[i
] != '\n') && (buf
[i
] != '\t')) {
927 if (g_strstr_len(buf
, len
, "%ADD")) {
930 if (g_strstr_len(buf
, len
, "D00")) {
933 if (g_strstr_len(buf
, len
, "D02")) {
936 if (g_strstr_len(buf
, len
, "M0")) {
939 if (g_strstr_len(buf
, len
, "M00")) {
942 if (g_strstr_len(buf
, len
, "M02")) {
945 if (g_strstr_len(buf
, len
, "*")) {
948 /* look for X<number> or Y<number> */
949 if ((letter
= g_strstr_len(buf
, len
, "X")) != NULL
) {
950 /* grab char after X */
951 if (isdigit( (int) letter
[1])) {
955 if ((letter
= g_strstr_len(buf
, len
, "Y")) != NULL
) {
956 /* grab char after Y */
957 if (isdigit( (int) letter
[1])) {
964 /* Now form logical expression determining if the file is RS-274D */
965 if ((found_D0
|| found_D2
|| found_M0
|| found_M2
) &&
966 !found_ADD
&& found_star
&& (found_X
|| found_Y
) &&
972 } /* gerber_is_rs274d */
975 /* ------------------------------------------------------------------- */
976 /*! This function reads a G number and updates the current
977 * state. It also updates the G stats counters
980 parse_G_code(gerb_file_t
*fd
, gerb_state_t
*state
, gerbv_image_t
*image
)
983 gerbv_format_t
*format
= image
->format
;
984 gerbv_stats_t
*stats
= image
->gerbv_stats
;
988 op_int
=gerb_fgetint(fd
, NULL
);
992 /* Is this doing anything really? */
995 case 1: /* Linear Interpolation (1X scale) */
996 state
->interpolation
= GERBV_INTERPOLATION_LINEARx1
;
999 case 2: /* Clockwise Linear Interpolation */
1000 state
->interpolation
= GERBV_INTERPOLATION_CW_CIRCULAR
;
1003 case 3: /* Counter Clockwise Linear Interpolation */
1004 state
->interpolation
= GERBV_INTERPOLATION_CCW_CIRCULAR
;
1007 case 4: /* Ignore Data Block */
1008 /* Don't do anything, just read 'til * */
1009 /* SDB asks: Should we look for other codes while reading G04 in case
1010 * user forgot to put * at end of comment block? */
1012 while ((c
!= EOF
) && (c
!= '*')) {
1017 case 10: /* Linear Interpolation (10X scale) */
1018 state
->interpolation
= GERBV_INTERPOLATION_x10
;
1021 case 11: /* Linear Interpolation (0.1X scale) */
1022 state
->interpolation
= GERBV_INTERPOLATION_LINEARx01
;
1025 case 12: /* Linear Interpolation (0.01X scale) */
1026 state
->interpolation
= GERBV_INTERPOLATION_LINEARx001
;
1029 case 36: /* Turn on Polygon Area Fill */
1030 state
->prev_interpolation
= state
->interpolation
;
1031 state
->interpolation
= GERBV_INTERPOLATION_PAREA_START
;
1035 case 37: /* Turn off Polygon Area Fill */
1036 state
->interpolation
= GERBV_INTERPOLATION_PAREA_END
;
1040 case 54: /* Tool prepare */
1041 /* XXX Maybe uneccesary??? */
1042 if (gerb_fgetc(fd
) == 'D') {
1043 int a
= gerb_fgetint(fd
, NULL
);
1044 if ((a
>= 0) && (a
<= APERTURE_MAX
)) {
1045 state
->curr_aperture
= a
;
1047 string
= g_strdup_printf("Found aperture D%d out of bounds while parsing G code in file \n%s\n",
1049 gerbv_stats_add_error(stats
->error_list
,
1052 GERBV_MESSAGE_ERROR
);
1056 string
= g_strdup_printf("Found unexpected code after G54 in file \n%s\n", fd
->filename
);
1057 gerbv_stats_add_error(stats
->error_list
,
1060 GERBV_MESSAGE_ERROR
);
1062 /* Must insert error count here */
1066 case 55: /* Prepare for flash */
1069 case 70: /* Specify inches */
1070 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1071 state
->state
->unit
= GERBV_UNIT_INCH
;
1074 case 71: /* Specify millimeters */
1075 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1076 state
->state
->unit
= GERBV_UNIT_MM
;
1079 case 74: /* Disable 360 circular interpolation */
1083 case 75: /* Enable 360 circular interpolation */
1087 case 90: /* Specify absolut format */
1088 if (format
) format
->coordinate
= GERBV_COORDINATE_ABSOLUTE
;
1091 case 91: /* Specify incremental format */
1092 if (format
) format
->coordinate
= GERBV_COORDINATE_INCREMENTAL
;
1096 string
= g_strdup_printf("Encountered unknown G code G%d in file \n%s\n", op_int
, fd
->filename
);
1097 gerbv_stats_add_error(stats
->error_list
,
1100 GERBV_MESSAGE_ERROR
);
1102 string
= g_strdup_printf("Ignorning unknown G code G%d\n", op_int
);
1103 gerbv_stats_add_error(stats
->error_list
,
1106 GERBV_MESSAGE_WARNING
);
1109 /* Enter error count here */
1114 } /* parse_G_code */
1117 /* ------------------------------------------------------------------ */
1118 /*! This function reads the numeric value of a D code and updates the
1119 * state. It also updates the D stats counters
1122 parse_D_code(gerb_file_t
*fd
, gerb_state_t
*state
, gerbv_image_t
*image
)
1125 gerbv_stats_t
*stats
= image
->gerbv_stats
;
1128 a
= gerb_fgetint(fd
, NULL
);
1129 dprintf(" In parse_D_code, found D number = %d ... \n", a
);
1131 case 0 : /* Invalid code */
1132 string
= g_strdup_printf("Found invalid D00 code in file \n%s.\n", fd
->filename
);
1133 gerbv_stats_add_error(stats
->error_list
,
1136 GERBV_MESSAGE_ERROR
);
1140 case 1 : /* Exposure on */
1141 state
->aperture_state
= GERBV_APERTURE_STATE_ON
;
1145 case 2 : /* Exposure off */
1146 state
->aperture_state
= GERBV_APERTURE_STATE_OFF
;
1150 case 3 : /* Flash aperture */
1151 state
->aperture_state
= GERBV_APERTURE_STATE_FLASH
;
1155 default: /* Aperture in use */
1156 if ((a
>= 0) && (a
<= APERTURE_MAX
)) {
1157 state
->curr_aperture
= a
;
1160 string
= g_strdup_printf("Found out of bounds aperture D%d in file \n%s\n",
1162 gerbv_stats_add_error(stats
->error_list
,
1165 GERBV_MESSAGE_ERROR
);
1174 } /* parse_D_code */
1177 /* ------------------------------------------------------------------ */
1179 parse_M_code(gerb_file_t
*fd
, gerbv_image_t
*image
)
1182 gerbv_stats_t
*stats
= image
->gerbv_stats
;
1185 op_int
=gerb_fgetint(fd
, NULL
);
1188 case 0: /* Program stop */
1191 case 1: /* Optional stop */
1194 case 2: /* End of program */
1198 string
= g_strdup_printf("Encountered unknown M code M%d in file \n%s\n",
1199 op_int
, fd
->filename
);
1200 gerbv_stats_add_error(stats
->error_list
,
1203 GERBV_MESSAGE_ERROR
);
1205 string
= g_strdup_printf("Ignorning unknown M code M%d\n", op_int
);
1206 gerbv_stats_add_error(stats
->error_list
,
1209 GERBV_MESSAGE_WARNING
);
1214 } /* parse_M_code */
1217 /* ------------------------------------------------------------------ */
1219 parse_rs274x(gint levelOfRecursion
, gerb_file_t
*fd
, gerbv_image_t
*image
,
1220 gerb_state_t
*state
, gerbv_net_t
*curr_net
, gerbv_stats_t
*stats
,
1221 gchar
*directoryPath
)
1226 gerbv_aperture_t
*a
= NULL
;
1227 gerbv_amacro_t
*tmp_amacro
;
1229 gdouble scale
= 1.0;
1232 if (state
->state
->unit
== GERBV_UNIT_MM
)
1235 op
[0] = gerb_fgetc(fd
);
1236 op
[1] = gerb_fgetc(fd
);
1238 if ((op
[0] == EOF
) || (op
[1] == EOF
)) {
1239 string
= g_strdup_printf("Unexpected EOF found in file \n%s\n", fd
->filename
);
1240 gerbv_stats_add_error(stats
->error_list
,
1243 GERBV_MESSAGE_ERROR
);
1247 switch (A2I(op
[0], op
[1])){
1250 * Directive parameters
1252 case A2I('A','S'): /* Axis Select */
1253 op
[0] = gerb_fgetc(fd
);
1254 op
[1] = gerb_fgetc(fd
);
1255 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1257 if ((op
[0] == EOF
) || (op
[1] == EOF
)) {
1258 string
= g_strdup_printf("Unexpected EOF found in file \n%s\n", fd
->filename
);
1259 gerbv_stats_add_error(stats
->error_list
,
1262 GERBV_MESSAGE_ERROR
);
1266 if (((op
[0] == 'A') && (op
[1] == 'Y')) ||
1267 ((op
[0] == 'B') && (op
[1] == 'X'))) {
1268 state
->state
->axisSelect
= GERBV_AXIS_SELECT_SWAPAB
;
1270 state
->state
->axisSelect
= GERBV_AXIS_SELECT_NOSELECT
;
1273 op
[0] = gerb_fgetc(fd
);
1274 op
[1] = gerb_fgetc(fd
);
1276 if ((op
[0] == EOF
) || (op
[1] == EOF
)) {
1277 string
= g_strdup_printf("Unexpected EOF found in file \n%s\n", fd
->filename
);
1278 gerbv_stats_add_error(stats
->error_list
,
1281 GERBV_MESSAGE_ERROR
);
1285 if (((op
[0] == 'A') && (op
[1] == 'Y')) ||
1286 ((op
[0] == 'B') && (op
[1] == 'X'))) {
1287 state
->state
->axisSelect
= GERBV_AXIS_SELECT_SWAPAB
;
1289 state
->state
->axisSelect
= GERBV_AXIS_SELECT_NOSELECT
;
1293 case A2I('F','S'): /* Format Statement */
1294 image
->format
= g_new0 (gerbv_format_t
,1);
1296 switch (gerb_fgetc(fd
)) {
1298 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_LEADING
;
1301 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_TRAILING
;
1304 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_EXPLICIT
;
1307 string
= g_strdup_printf("EagleCad bug detected: Undefined handling of zeros in format code in file \n%s\n",
1309 gerbv_stats_add_error(stats
->error_list
,
1312 GERBV_MESSAGE_ERROR
);
1314 string
= g_strdup_printf("Defaulting to omitting leading zeros.\n");
1315 gerbv_stats_add_error(stats
->error_list
,
1318 GERBV_MESSAGE_WARNING
);
1321 image
->format
->omit_zeros
= GERBV_OMIT_ZEROS_LEADING
;
1324 switch (gerb_fgetc(fd
)) {
1326 image
->format
->coordinate
= GERBV_COORDINATE_ABSOLUTE
;
1329 image
->format
->coordinate
= GERBV_COORDINATE_INCREMENTAL
;
1332 string
= g_strdup_printf("Invalid coordinate type defined in format code in file \n%s\n",
1334 gerbv_stats_add_error(stats
->error_list
,
1337 GERBV_MESSAGE_ERROR
);
1339 string
= g_strdup_printf("Defaulting to absolute coordinates.\n");
1340 gerbv_stats_add_error(stats
->error_list
,
1343 GERBV_MESSAGE_WARNING
);
1345 image
->format
->coordinate
= GERBV_COORDINATE_ABSOLUTE
;
1347 op
[0] = gerb_fgetc(fd
);
1348 while((op
[0] != '*')&&(op
[0] != EOF
)) {
1351 op
[0] = (char)gerb_fgetc(fd
);
1352 image
->format
->lim_seqno
= op
[0] - '0';
1355 op
[0] = (char)gerb_fgetc(fd
);
1356 image
->format
->lim_gf
= op
[0] - '0';
1359 op
[0] = (char)gerb_fgetc(fd
);
1360 image
->format
->lim_pf
= op
[0] - '0';
1363 op
[0] = (char)gerb_fgetc(fd
);
1364 image
->format
->lim_mf
= op
[0] - '0';
1367 op
[0] = gerb_fgetc(fd
);
1368 if ((op
[0] < '0') || (op
[0] > '6')) {
1369 string
= g_strdup_printf("Illegal format size %c in file \n%s\n",
1370 (char)op
[0], fd
->filename
);
1371 gerbv_stats_add_error(stats
->error_list
,
1374 GERBV_MESSAGE_ERROR
);
1377 image
->format
->x_int
= op
[0] - '0';
1378 op
[0] = gerb_fgetc(fd
);
1379 if ((op
[0] < '0') || (op
[0] > '6')) {
1380 string
= g_strdup_printf("Illegal format size %c in file \n%s\n",
1381 (char)op
[0], fd
->filename
);
1382 gerbv_stats_add_error(stats
->error_list
,
1385 GERBV_MESSAGE_ERROR
);
1388 image
->format
->x_dec
= op
[0] - '0';
1391 op
[0] = gerb_fgetc(fd
);
1392 if ((op
[0] < '0') || (op
[0] > '6')) {
1393 string
= g_strdup_printf("Illegal format size %c in file \n%s\n",
1394 (char)op
[0], fd
->filename
);
1395 gerbv_stats_add_error(stats
->error_list
,
1398 GERBV_MESSAGE_ERROR
);
1401 image
->format
->y_int
= op
[0] - '0';
1402 op
[0] = gerb_fgetc(fd
);
1403 if ((op
[0] < '0') || (op
[0] > '6')) {
1404 string
= g_strdup_printf("Illegal format size %c in file \n%s\n",
1405 (char)op
[0], fd
->filename
);
1406 gerbv_stats_add_error(stats
->error_list
,
1409 GERBV_MESSAGE_ERROR
);
1412 image
->format
->y_dec
= op
[0] - '0';
1415 string
= g_strdup_printf("Illegal format statement [%c] in file \n%s\n",
1416 op
[0], fd
->filename
);
1417 gerbv_stats_add_error(stats
->error_list
,
1420 GERBV_MESSAGE_ERROR
);
1422 string
= g_strdup_printf("Ignoring invalid format statement.\n");
1423 gerbv_stats_add_error(stats
->error_list
,
1426 GERBV_MESSAGE_WARNING
);
1429 op
[0] = gerb_fgetc(fd
);
1432 case A2I('M','I'): /* Mirror Image */
1433 op
[0] = gerb_fgetc(fd
);
1434 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1436 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1440 readValue
= gerb_fgetint(fd
, NULL
);
1441 if (readValue
== 1) {
1442 if (state
->state
->mirrorState
== GERBV_MIRROR_STATE_FLIPB
)
1443 state
->state
->mirrorState
=GERBV_MIRROR_STATE_FLIPAB
;
1445 state
->state
->mirrorState
=GERBV_MIRROR_STATE_FLIPA
;
1449 readValue
= gerb_fgetint(fd
, NULL
);
1450 if (readValue
== 1) {
1451 if (state
->state
->mirrorState
== GERBV_MIRROR_STATE_FLIPA
)
1452 state
->state
->mirrorState
=GERBV_MIRROR_STATE_FLIPAB
;
1454 state
->state
->mirrorState
=GERBV_MIRROR_STATE_FLIPB
;
1458 string
= g_strdup_printf("Wrong character in mirror:%c\n", op
[0]);
1459 gerbv_stats_add_error(stats
->error_list
,
1462 GERBV_MESSAGE_ERROR
);
1465 op
[0] = gerb_fgetc(fd
);
1468 case A2I('M','O'): /* Mode of Units */
1469 op
[0] = gerb_fgetc(fd
);
1470 op
[1] = gerb_fgetc(fd
);
1472 if ((op
[0] == EOF
) || (op
[1] == EOF
))
1473 gerbv_stats_add_error(stats
->error_list
,
1475 "Unexpected EOF found.\n",
1476 GERBV_MESSAGE_ERROR
);
1477 switch (A2I(op
[0],op
[1])) {
1479 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1480 state
->state
->unit
= GERBV_UNIT_INCH
;
1483 state
->state
= gerbv_image_return_new_netstate (state
->state
);
1484 state
->state
->unit
= GERBV_UNIT_MM
;
1487 string
= g_strdup_printf("Illegal unit:%c%c\n", op
[0], op
[1]);
1488 gerbv_stats_add_error(stats
->error_list
,
1491 GERBV_MESSAGE_ERROR
);
1495 case A2I('O','F'): /* Offset */
1496 op
[0] = gerb_fgetc(fd
);
1498 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1501 state
->state
->offsetA
= gerb_fgetdouble(fd
) / scale
;
1504 state
->state
->offsetB
= gerb_fgetdouble(fd
) / scale
;
1507 string
= g_strdup_printf("Wrong character in offset:%c\n", op
[0]);
1508 gerbv_stats_add_error(stats
->error_list
,
1511 GERBV_MESSAGE_ERROR
);
1514 op
[0] = gerb_fgetc(fd
);
1517 case A2I('I','F'): /* Include file */
1519 gchar
*includeFilename
= gerb_fgetstring(fd
, '*');
1521 if (includeFilename
) {
1523 if (!g_path_is_absolute(includeFilename
)) {
1524 fullPath
= g_build_filename (directoryPath
, includeFilename
, NULL
);
1526 fullPath
= g_strdup (includeFilename
);
1528 if (levelOfRecursion
< 10) {
1529 gerb_file_t
*includefd
= NULL
;
1531 includefd
= gerb_fopen(fullPath
, NULL
);
1533 gerber_parse_file_segment (levelOfRecursion
+ 1, image
, state
, curr_net
, stats
, includefd
, directoryPath
);
1534 gerb_fclose(includefd
);
1536 string
= g_strdup_printf("In file %s,\nIncluded file %s cannot be found\n",
1537 fd
->filename
, fullPath
);
1538 gerbv_stats_add_error(stats
->error_list
,
1541 GERBV_MESSAGE_ERROR
);
1546 string
= g_strdup_printf("Parser encountered more than 10 levels of include file recursion which is not allowed by the RS-274X spec\n");
1547 gerbv_stats_add_error(stats
->error_list
,
1550 GERBV_MESSAGE_ERROR
);
1557 case A2I('I','O'): /* Image offset */
1558 op
[0] = gerb_fgetc(fd
);
1560 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1563 image
->info
->offsetA
= gerb_fgetdouble(fd
) / scale
;
1566 image
->info
->offsetB
= gerb_fgetdouble(fd
) / scale
;
1569 string
= g_strdup_printf("In file %s,\nwrong character in image offset %c\n",
1570 fd
->filename
, op
[0]);
1571 gerbv_stats_add_error(stats
->error_list
,
1574 GERBV_MESSAGE_ERROR
);
1577 op
[0] = gerb_fgetc(fd
);
1580 case A2I('S','F'): /* Scale Factor */
1581 if (gerb_fgetc(fd
) == 'A')
1582 state
->state
->scaleA
= gerb_fgetdouble(fd
);
1585 if (gerb_fgetc(fd
) == 'B')
1586 state
->state
->scaleB
= gerb_fgetdouble(fd
);
1590 case A2I('I','C'): /* Input Code */
1591 /* Thanks to Stephen Adam for providing this information. As he writes:
1592 * btw, here's a logic puzzle for you. If you need to
1593 * read the gerber file to see how it's encoded, then
1594 * how can you read it?
1596 op
[0] = gerb_fgetc(fd
);
1597 op
[1] = gerb_fgetc(fd
);
1599 if ((op
[0] == EOF
) || (op
[1] == EOF
)) {
1600 string
= g_strdup_printf("Unexpected EOF found in file \n%s\n", fd
->filename
);
1601 gerbv_stats_add_error(stats
->error_list
,
1604 GERBV_MESSAGE_ERROR
);
1607 switch (A2I(op
[0],op
[1])) {
1609 image
->info
->encoding
= GERBV_ENCODING_ASCII
;
1612 image
->info
->encoding
= GERBV_ENCODING_EBCDIC
;
1615 image
->info
->encoding
= GERBV_ENCODING_BCD
;
1618 image
->info
->encoding
= GERBV_ENCODING_ISO_ASCII
;
1621 image
->info
->encoding
= GERBV_ENCODING_EIA
;
1624 string
= g_strdup_printf("In file %s, \nunknown input code (IC): %c%c\n",
1625 fd
->filename
, op
[0], op
[1]);
1626 gerbv_stats_add_error(stats
->error_list
,
1629 GERBV_MESSAGE_ERROR
);
1634 /* Image parameters */
1635 case A2I('I','J'): /* Image Justify */
1636 op
[0] = gerb_fgetc(fd
);
1637 image
->info
->imageJustifyTypeA
= GERBV_JUSTIFY_LOWERLEFT
;
1638 image
->info
->imageJustifyTypeB
= GERBV_JUSTIFY_LOWERLEFT
;
1639 image
->info
->imageJustifyOffsetA
= 0.0;
1640 image
->info
->imageJustifyOffsetB
= 0.0;
1641 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1644 op
[0] = gerb_fgetc(fd
);
1646 image
->info
->imageJustifyTypeA
= GERBV_JUSTIFY_CENTERJUSTIFY
;
1647 } else if (op
[0] == 'L') {
1648 image
->info
->imageJustifyTypeA
= GERBV_JUSTIFY_LOWERLEFT
;
1651 image
->info
->imageJustifyOffsetA
= gerb_fgetdouble(fd
) / scale
;
1655 op
[0] = gerb_fgetc(fd
);
1657 image
->info
->imageJustifyTypeB
= GERBV_JUSTIFY_CENTERJUSTIFY
;
1658 } else if (op
[0] == 'L') {
1659 image
->info
->imageJustifyTypeB
= GERBV_JUSTIFY_LOWERLEFT
;
1662 image
->info
->imageJustifyOffsetB
= gerb_fgetdouble(fd
) / scale
;
1666 string
= g_strdup_printf("In file %s,\nwrong character in image justify:%c\n",
1667 fd
->filename
, op
[0]);
1668 gerbv_stats_add_error(stats
->error_list
,
1671 GERBV_MESSAGE_ERROR
);
1674 op
[0] = gerb_fgetc(fd
);
1677 case A2I('I','N'): /* Image Name */
1678 image
->info
->name
= gerb_fgetstring(fd
, '*');
1680 case A2I('I','P'): /* Image Polarity */
1682 for (ano
= 0; ano
< 3; ano
++) {
1683 op
[0] = gerb_fgetc(fd
);
1685 string
= g_strdup_printf("In file %s,\nunexpected EOF while reading image polarity (IP)\n",
1687 gerbv_stats_add_error(stats
->error_list
,
1690 GERBV_MESSAGE_ERROR
);
1693 str
[ano
] = (char)op
[0];
1696 if (strncmp(str
, "POS", 3) == 0)
1697 image
->info
->polarity
= GERBV_POLARITY_POSITIVE
;
1698 else if (strncmp(str
, "NEG", 3) == 0)
1699 image
->info
->polarity
= GERBV_POLARITY_NEGATIVE
;
1701 string
= g_strdup_printf("Unknown polarity : %c%c%c\n", str
[0], str
[1], str
[2]);
1702 gerbv_stats_add_error(stats
->error_list
,
1705 GERBV_MESSAGE_ERROR
);
1709 case A2I('I','R'): /* Image Rotation */
1710 tmp
= gerb_fgetint(fd
, NULL
) % 360;
1712 image
->info
->imageRotation
= 0.0;
1714 image
->info
->imageRotation
= M_PI
/ 2.0;
1715 else if (tmp
== 180)
1716 image
->info
->imageRotation
= M_PI
;
1717 else if (tmp
== 270)
1718 image
->info
->imageRotation
= 3.0 * M_PI
/ 2.0;
1720 string
= g_strdup_printf("Image rotation must be 0, 90, 180 or 270 (is actually %d)\n", tmp
);
1721 gerbv_stats_add_error(stats
->error_list
,
1724 GERBV_MESSAGE_ERROR
);
1728 case A2I('P','F'): /* Plotter Film */
1729 image
->info
->plotterFilm
= gerb_fgetstring(fd
, '*');
1732 /* Aperture parameters */
1733 case A2I('A','D'): /* Aperture Description */
1734 a
= (gerbv_aperture_t
*) g_new0 (gerbv_aperture_t
,1);
1736 ano
= parse_aperture_definition(fd
, a
, image
, scale
);
1737 if ((ano
>= 0) && (ano
<= APERTURE_MAX
)) {
1738 a
->unit
= state
->state
->unit
;
1739 image
->aperture
[ano
] = a
;
1740 dprintf(" In parse_rs274x, adding new aperture to aperture list ...\n");
1741 gerbv_stats_add_aperture(stats
->aperture_list
,
1745 gerbv_stats_add_to_D_list(stats
->D_code_list
,
1747 if (ano
< APERTURE_MIN
) {
1748 string
= g_strdup_printf("In file %s,\naperture number out of bounds : %d\n",
1750 gerbv_stats_add_error(stats
->error_list
,-1, string
, GERBV_MESSAGE_ERROR
);
1753 string
= g_strdup_printf("In file %s,\naperture number out of bounds : %d\n",
1755 gerbv_stats_add_error(stats
->error_list
,
1758 GERBV_MESSAGE_ERROR
);
1761 /* Add aperture info to stats->aperture_list here */
1764 case A2I('A','M'): /* Aperture Macro */
1765 tmp_amacro
= image
->amacro
;
1766 image
->amacro
= parse_aperture_macro(fd
);
1767 if (image
->amacro
) {
1768 image
->amacro
->next
= tmp_amacro
;
1770 print_program(image
->amacro
);
1773 string
= g_strdup_printf("In file %s, \nfailed to parse aperture macro\n",
1775 gerbv_stats_add_error(stats
->error_list
,
1778 GERBV_MESSAGE_ERROR
);
1783 case A2I('L','N'): /* Layer Name */
1784 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1785 state
->layer
->name
= gerb_fgetstring(fd
, '*');
1787 case A2I('L','P'): /* Layer Polarity */
1788 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1789 switch (gerb_fgetc(fd
)) {
1790 case 'D': /* Dark Polarity (default) */
1791 state
->layer
->polarity
= GERBV_POLARITY_DARK
;
1793 case 'C': /* Clear Polarity */
1794 state
->layer
->polarity
= GERBV_POLARITY_CLEAR
;
1797 string
= g_strdup_printf("In file %s,\nunknown Layer Polarity: %c\n",
1798 fd
->filename
, op
[0]);
1799 gerbv_stats_add_error(stats
->error_list
,
1802 GERBV_MESSAGE_ERROR
);
1806 case A2I('K','O'): /* Knock Out */
1807 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1808 gerber_update_any_running_knockout_measurements (image
);
1809 /* reset any previous knockout measurements */
1810 knockoutMeasure
= FALSE
;
1811 op
[0] = gerb_fgetc(fd
);
1812 if (op
[0] == '*') { /* Disable previous SR parameters */
1813 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_NOKNOCKOUT
;
1815 } else if (op
[0] == 'C') {
1816 state
->layer
->knockout
.polarity
= GERBV_POLARITY_CLEAR
;
1817 } else if (op
[0] == 'D') {
1818 state
->layer
->knockout
.polarity
= GERBV_POLARITY_DARK
;
1820 string
= g_strdup_printf("In file %s,\nknockout must supply a polarity (C, D, or *)\n",
1822 gerbv_stats_add_error(stats
->error_list
,
1825 GERBV_MESSAGE_ERROR
);
1828 state
->layer
->knockout
.lowerLeftX
= 0.0;
1829 state
->layer
->knockout
.lowerLeftY
= 0.0;
1830 state
->layer
->knockout
.width
= 0.0;
1831 state
->layer
->knockout
.height
= 0.0;
1832 state
->layer
->knockout
.border
= 0.0;
1833 state
->layer
->knockout
.firstInstance
= TRUE
;
1834 op
[0] = gerb_fgetc(fd
);
1835 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1838 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_FIXEDKNOCK
;
1839 state
->layer
->knockout
.lowerLeftX
= gerb_fgetdouble(fd
) / scale
;
1842 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_FIXEDKNOCK
;
1843 state
->layer
->knockout
.lowerLeftY
= gerb_fgetdouble(fd
) / scale
;
1846 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_FIXEDKNOCK
;
1847 state
->layer
->knockout
.width
= gerb_fgetdouble(fd
) / scale
;
1850 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_FIXEDKNOCK
;
1851 state
->layer
->knockout
.height
= gerb_fgetdouble(fd
) / scale
;
1854 state
->layer
->knockout
.type
= GERBV_KNOCKOUT_TYPE_BORDER
;
1855 state
->layer
->knockout
.border
= gerb_fgetdouble(fd
) / scale
;
1856 /* this is a bordered knockout, so we need to start measuring the
1857 size of a square bordering all future components */
1858 knockoutMeasure
= TRUE
;
1859 knockoutLimitXmin
= HUGE_VAL
;
1860 knockoutLimitYmin
= HUGE_VAL
;
1861 knockoutLimitXmax
= -HUGE_VAL
;
1862 knockoutLimitYmax
= -HUGE_VAL
;
1863 knockoutLayer
= state
->layer
;
1866 string
= g_strdup_printf("In file %s, \nunknown variable in knockout",
1868 gerbv_stats_add_error(stats
->error_list
,
1871 GERBV_MESSAGE_ERROR
);
1874 op
[0] = gerb_fgetc(fd
);
1877 case A2I('S','R'): /* Step and Repeat */
1878 /* start by generating a new layer (duplicating previous layer settings */
1879 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1880 op
[0] = gerb_fgetc(fd
);
1881 if (op
[0] == '*') { /* Disable previous SR parameters */
1882 state
->layer
->stepAndRepeat
.X
= 1;
1883 state
->layer
->stepAndRepeat
.Y
= 1;
1884 state
->layer
->stepAndRepeat
.dist_X
= 0.0;
1885 state
->layer
->stepAndRepeat
.dist_Y
= 0.0;
1888 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1891 state
->layer
->stepAndRepeat
.X
= gerb_fgetint(fd
, NULL
);
1894 state
->layer
->stepAndRepeat
.Y
= gerb_fgetint(fd
, NULL
);
1897 state
->layer
->stepAndRepeat
.dist_X
= gerb_fgetdouble(fd
) / scale
;
1900 state
->layer
->stepAndRepeat
.dist_Y
= gerb_fgetdouble(fd
) / scale
;
1903 string
= g_strdup_printf("In file %s,\nstep-and-repeat parameter error\n",
1905 gerbv_stats_add_error(stats
->error_list
,
1908 GERBV_MESSAGE_ERROR
);
1913 * Repeating 0 times in any direction would disable the whole plot, and
1914 * is probably not intended. At least one other tool (viewmate) seems
1915 * to interpret 0-time repeating as repeating just once too.
1917 if(state
->layer
->stepAndRepeat
.X
== 0)
1918 state
->layer
->stepAndRepeat
.X
= 1;
1919 if(state
->layer
->stepAndRepeat
.Y
== 0)
1920 state
->layer
->stepAndRepeat
.Y
= 1;
1922 op
[0] = gerb_fgetc(fd
);
1925 /* is this an actual RS274X command?? It isn't explainined in the spec... */
1927 state
->layer
= gerbv_image_return_new_layer (state
->layer
);
1929 state
->layer
->rotation
= gerb_fgetdouble(fd
) * M_PI
/ 180;
1930 op
[0] = gerb_fgetc(fd
);
1932 string
= g_strdup_printf("In file %s,\nerror in layer rotation command\n",
1934 gerbv_stats_add_error(stats
->error_list
,
1937 GERBV_MESSAGE_ERROR
);
1942 string
= g_strdup_printf("In file %s,\nunknown RS-274X extension found %%%c%c%%\n",
1943 fd
->filename
, op
[0], op
[1]);
1944 gerbv_stats_add_error(stats
->error_list
,
1947 GERBV_MESSAGE_ERROR
);
1952 } /* parse_rs274x */
1956 * Stack declarations and operations to be used by the simple engine that
1957 * executes the parsed aperture macros.
1965 static macro_stack_t
*
1966 new_stack(unsigned int stack_size
)
1970 s
= (macro_stack_t
*) g_new0 (macro_stack_t
,1);
1971 s
->stack
= (double *) g_new0 (double, stack_size
);
1978 free_stack(macro_stack_t
*s
)
1991 push(macro_stack_t
*s
, double val
)
1993 s
->stack
[s
->sp
++] = val
;
1999 pop(macro_stack_t
*s
, double *value
)
2001 /* Check if we try to pop an empty stack */
2006 *value
= s
->stack
[--s
->sp
];
2011 /* ------------------------------------------------------------------ */
2013 simplify_aperture_macro(gerbv_aperture_t
*aperture
, gdouble scale
)
2015 const int extra_stack_size
= 10;
2017 gerbv_instruction_t
*ip
;
2018 int handled
= 1, nuf_parameters
= 0, i
, j
, clearOperatorUsed
= FALSE
;
2019 double *lp
; /* Local copy of parameters */
2020 double tmp
[2] = {0.0, 0.0};
2021 gerbv_aperture_type_t type
= GERBV_APTYPE_NONE
;
2022 gerbv_simplified_amacro_t
*sam
;
2024 if (aperture
== NULL
)
2025 GERB_FATAL_ERROR("aperture NULL in simplify aperture macro\n");
2027 if (aperture
->amacro
== NULL
)
2028 GERB_FATAL_ERROR("aperture->amacro NULL in simplify aperture macro\n");
2030 /* Allocate stack for VM */
2031 s
= new_stack(aperture
->amacro
->nuf_push
+ extra_stack_size
);
2033 GERB_FATAL_ERROR("malloc stack failed\n");
2035 /* Make a copy of the parameter list that we can rewrite if necessary */
2036 lp
= g_new (double,APERTURE_PARAMETERS_MAX
);
2038 memcpy(lp
, aperture
->parameter
, sizeof(double) * APERTURE_PARAMETERS_MAX
);
2040 for(ip
= aperture
->amacro
->program
; ip
!= NULL
; ip
= ip
->next
) {
2041 switch(ip
->opcode
) {
2042 case GERBV_OPCODE_NOP
:
2044 case GERBV_OPCODE_PUSH
:
2045 push(s
, ip
->data
.fval
);
2047 case GERBV_OPCODE_PPUSH
:
2048 push(s
, lp
[ip
->data
.ival
- 1]);
2050 case GERBV_OPCODE_PPOP
:
2051 if (pop(s
, &tmp
[0]) < 0)
2052 GERB_FATAL_ERROR("Tried to pop an empty stack");
2053 lp
[ip
->data
.ival
- 1] = tmp
[0];
2055 case GERBV_OPCODE_ADD
:
2056 if (pop(s
, &tmp
[0]) < 0)
2057 GERB_FATAL_ERROR("Tried to pop an empty stack");
2058 if (pop(s
, &tmp
[1]) < 0)
2059 GERB_FATAL_ERROR("Tried to pop an empty stack");
2060 push(s
, tmp
[1] + tmp
[0]);
2062 case GERBV_OPCODE_SUB
:
2063 if (pop(s
, &tmp
[0]) < 0)
2064 GERB_FATAL_ERROR("Tried to pop an empty stack");
2065 if (pop(s
, &tmp
[1]) < 0)
2066 GERB_FATAL_ERROR("Tried to pop an empty stack");
2067 push(s
, tmp
[1] - tmp
[0]);
2069 case GERBV_OPCODE_MUL
:
2070 if (pop(s
, &tmp
[0]) < 0)
2071 GERB_FATAL_ERROR("Tried to pop an empty stack");
2072 if (pop(s
, &tmp
[1]) < 0)
2073 GERB_FATAL_ERROR("Tried to pop an empty stack");
2074 push(s
, tmp
[1] * tmp
[0]);
2076 case GERBV_OPCODE_DIV
:
2077 if (pop(s
, &tmp
[0]) < 0)
2078 GERB_FATAL_ERROR("Tried to pop an empty stack");
2079 if (pop(s
, &tmp
[1]) < 0)
2080 GERB_FATAL_ERROR("Tried to pop an empty stack");
2081 push(s
, tmp
[1] / tmp
[0]);
2083 case GERBV_OPCODE_PRIM
:
2085 * This handles the exposure thing in the aperture macro
2086 * The exposure is always the first element on stack independent
2087 * of aperture macro.
2089 switch(ip
->data
.ival
) {
2091 dprintf(" Aperture macro circle [1] (");
2092 type
= GERBV_APTYPE_MACRO_CIRCLE
;
2098 dprintf(" Aperture macro outline [4] (");
2099 type
= GERBV_APTYPE_MACRO_OUTLINE
;
2101 * Number of parameters are:
2102 * - number of points defined in entry 1 of the stack +
2103 * start point. Times two since it is both X and Y.
2104 * - Then three more; exposure, nuf points and rotation.
2106 nuf_parameters
= ((int)s
->stack
[1] + 1) * 2 + 3;
2109 dprintf(" Aperture macro polygon [5] (");
2110 type
= GERBV_APTYPE_MACRO_POLYGON
;
2114 dprintf(" Aperture macro moiré [6] (");
2115 type
= GERBV_APTYPE_MACRO_MOIRE
;
2119 dprintf(" Aperture macro thermal [7] (");
2120 type
= GERBV_APTYPE_MACRO_THERMAL
;
2125 dprintf(" Aperture macro line 20/2 (");
2126 type
= GERBV_APTYPE_MACRO_LINE20
;
2130 dprintf(" Aperture macro line 21 (");
2131 type
= GERBV_APTYPE_MACRO_LINE21
;
2135 dprintf(" Aperture macro line 22 (");
2136 type
= GERBV_APTYPE_MACRO_LINE22
;
2143 if (type
!= GERBV_APTYPE_NONE
) {
2144 if (nuf_parameters
> APERTURE_PARAMETERS_MAX
) {
2145 GERB_COMPILE_ERROR("Number of parameters to aperture macro are more than gerbv is able to store\n");
2149 * Create struct for simplified aperture macro and
2150 * start filling in the blanks.
2152 sam
= g_new (gerbv_simplified_amacro_t
, 1);
2155 memset(sam
->parameter
, 0,
2156 sizeof(double) * APERTURE_PARAMETERS_MAX
);
2157 memcpy(sam
->parameter
, s
->stack
,
2158 sizeof(double) * nuf_parameters
);
2160 /* convert any mm values to inches */
2162 case GERBV_APTYPE_MACRO_CIRCLE
:
2163 if (fabs(sam
->parameter
[0]) < 0.001)
2164 clearOperatorUsed
= TRUE
;
2165 sam
->parameter
[1]/=scale
;
2166 sam
->parameter
[2]/=scale
;
2167 sam
->parameter
[3]/=scale
;
2169 case GERBV_APTYPE_MACRO_OUTLINE
:
2170 if (fabs(sam
->parameter
[0]) < 0.001)
2171 clearOperatorUsed
= TRUE
;
2172 for (j
=2; j
<nuf_parameters
-1; j
++){
2173 sam
->parameter
[j
]/=scale
;
2176 case GERBV_APTYPE_MACRO_POLYGON
:
2177 if (fabs(sam
->parameter
[0]) < 0.001)
2178 clearOperatorUsed
= TRUE
;
2179 sam
->parameter
[2]/=scale
;
2180 sam
->parameter
[3]/=scale
;
2181 sam
->parameter
[4]/=scale
;
2183 case GERBV_APTYPE_MACRO_MOIRE
:
2184 sam
->parameter
[0]/=scale
;
2185 sam
->parameter
[1]/=scale
;
2186 sam
->parameter
[2]/=scale
;
2187 sam
->parameter
[3]/=scale
;
2188 sam
->parameter
[4]/=scale
;
2189 sam
->parameter
[6]/=scale
;
2190 sam
->parameter
[7]/=scale
;
2192 case GERBV_APTYPE_MACRO_THERMAL
:
2193 sam
->parameter
[0]/=scale
;
2194 sam
->parameter
[1]/=scale
;
2195 sam
->parameter
[2]/=scale
;
2196 sam
->parameter
[3]/=scale
;
2197 sam
->parameter
[4]/=scale
;
2199 case GERBV_APTYPE_MACRO_LINE20
:
2200 if (fabs(sam
->parameter
[0]) < 0.001)
2201 clearOperatorUsed
= TRUE
;
2202 sam
->parameter
[1]/=scale
;
2203 sam
->parameter
[2]/=scale
;
2204 sam
->parameter
[3]/=scale
;
2205 sam
->parameter
[4]/=scale
;
2206 sam
->parameter
[5]/=scale
;
2208 case GERBV_APTYPE_MACRO_LINE21
:
2209 case GERBV_APTYPE_MACRO_LINE22
:
2210 if (fabs(sam
->parameter
[0]) < 0.001)
2211 clearOperatorUsed
= TRUE
;
2212 sam
->parameter
[1]/=scale
;
2213 sam
->parameter
[2]/=scale
;
2214 sam
->parameter
[3]/=scale
;
2215 sam
->parameter
[4]/=scale
;
2221 * Add this simplified aperture macro to the end of the list
2222 * of simplified aperture macros. If first entry, put it
2225 if (aperture
->simplified
== NULL
) {
2226 aperture
->simplified
= sam
;
2228 gerbv_simplified_amacro_t
*tmp_sam
;
2229 tmp_sam
= aperture
->simplified
;
2230 while (tmp_sam
->next
!= NULL
) {
2231 tmp_sam
= tmp_sam
->next
;
2233 tmp_sam
->next
= sam
;
2237 for (i
= 0; i
< nuf_parameters
; i
++) {
2238 dprintf("%f, ", s
->stack
[i
]);
2245 * Here we reset the stack pointer. It's not general correct
2246 * correct to do this, but since I know how the compiler works
2247 * I can do this. The correct way to do this should be to
2248 * subtract number of used elements in each primitive operation.
2259 /* store a flag to let the renderer know if it should expect any "clear"
2261 aperture
->parameter
[0]= (gdouble
) clearOperatorUsed
;
2263 } /* simplify_aperture_macro */
2266 /* ------------------------------------------------------------------ */
2268 parse_aperture_definition(gerb_file_t
*fd
, gerbv_aperture_t
*aperture
,
2269 gerbv_image_t
*image
, gdouble scale
)
2274 gerbv_amacro_t
*curr_amacro
;
2275 gerbv_amacro_t
*amacro
= image
->amacro
;
2276 gerbv_stats_t
*stats
= image
->gerbv_stats
;
2280 if (gerb_fgetc(fd
) != 'D') {
2281 string
= g_strdup_printf("Found AD code with no following 'D' in file \n%s\n",
2283 gerbv_stats_add_error(stats
->error_list
,
2286 GERBV_MESSAGE_ERROR
);
2294 ano
= gerb_fgetint(fd
, NULL
);
2297 * Read in the whole aperture defintion and tokenize it
2299 ad
= gerb_fgetstring(fd
, '*');
2300 token
= strtok(ad
, ",");
2302 if (strlen(token
) == 1) {
2305 aperture
->type
= GERBV_APTYPE_CIRCLE
;
2308 aperture
->type
= GERBV_APTYPE_RECTANGLE
;
2311 aperture
->type
= GERBV_APTYPE_OVAL
;
2314 aperture
->type
= GERBV_APTYPE_POLYGON
;
2317 /* Here a should a T be defined, but I don't know what it represents */
2319 aperture
->type
= GERBV_APTYPE_MACRO
;
2321 * In aperture definition, point to the aperture macro
2322 * used in the defintion
2324 curr_amacro
= amacro
;
2325 while (curr_amacro
) {
2326 if ((strlen(curr_amacro
->name
) == strlen(token
)) &&
2327 (strcmp(curr_amacro
->name
, token
) == 0)) {
2328 aperture
->amacro
= curr_amacro
;
2331 curr_amacro
= curr_amacro
->next
;
2336 * Parse all parameters
2338 for (token
= strtok(NULL
, "X"), i
= 0; token
!= NULL
;
2339 token
= strtok(NULL
, "X"), i
++) {
2340 if (i
== APERTURE_PARAMETERS_MAX
) {
2341 string
= g_strdup_printf("In file %s,\nmaximum number of allowed parameters exceeded in aperture %d\n",
2343 gerbv_stats_add_error(stats
->error_list
,
2346 GERBV_MESSAGE_ERROR
);
2352 tempHolder
= strtod(token
, NULL
);
2353 /* convert any MM values to inches */
2354 /* don't scale polygon angles or side numbers, or macro parmaeters */
2355 if (!(((aperture
->type
== GERBV_APTYPE_POLYGON
) && ((i
==1) || (i
==2)))||
2356 (aperture
->type
== GERBV_APTYPE_MACRO
))) {
2357 tempHolder
/= scale
;
2360 aperture
->parameter
[i
] = tempHolder
;
2362 string
= g_strdup_printf("Failed to read all parameters exceeded in aperture %d\n", ano
);
2363 gerbv_stats_add_error(stats
->error_list
,
2366 GERBV_MESSAGE_WARNING
);
2368 aperture
->parameter
[i
] = 0.0;
2372 aperture
->nuf_parameters
= i
;
2376 if (aperture
->type
== GERBV_APTYPE_MACRO
) {
2377 dprintf("Simplifying aperture %d using aperture macro \"%s\"\n", ano
,
2378 aperture
->amacro
->name
);
2379 simplify_aperture_macro(aperture
, scale
);
2380 dprintf("Done simplifying\n");
2386 } /* parse_aperture_definition */
2389 /* ------------------------------------------------------------------ */
2391 calc_cirseg_sq(struct gerbv_net
*net
, int cw
,
2392 double delta_cp_x
, double delta_cp_y
)
2394 double d1x
, d1y
, d2x
, d2y
;
2400 * Quadrant detection (based on ccw, converted below if cw)
2406 if (net
->start_x
> net
->stop_x
)
2407 /* 1st and 2nd quadrant */
2408 if (net
->start_y
< net
->stop_y
)
2413 /* 3rd and 4th quadrant */
2414 if (net
->start_y
> net
->stop_y
)
2420 * If clockwise, rotate quadrant
2437 GERB_COMPILE_ERROR("Unknow quadrant value while converting to cw\n");
2442 * Calculate arc center point
2446 net
->cirseg
->cp_x
= net
->start_x
- delta_cp_x
;
2447 net
->cirseg
->cp_y
= net
->start_y
- delta_cp_y
;
2450 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
2451 net
->cirseg
->cp_y
= net
->start_y
- delta_cp_y
;
2454 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
2455 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
2458 net
->cirseg
->cp_x
= net
->start_x
- delta_cp_x
;
2459 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
2462 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant
);
2468 d1x
= fabs(net
->start_x
- net
->cirseg
->cp_x
);
2469 d1y
= fabs(net
->start_y
- net
->cirseg
->cp_y
);
2470 d2x
= fabs(net
->stop_x
- net
->cirseg
->cp_x
);
2471 d2y
= fabs(net
->stop_y
- net
->cirseg
->cp_y
);
2473 alfa
= atan2(d1y
, d1x
);
2474 beta
= atan2(d2y
, d2x
);
2477 * Avoid divide by zero when sin(0) = 0 and cos(90) = 0
2479 net
->cirseg
->width
= alfa
< beta
?
2480 2 * (d1x
/ cos(alfa
)) : 2 * (d2x
/ cos(beta
));
2481 net
->cirseg
->height
= alfa
> beta
?
2482 2 * (d1y
/ sin(alfa
)) : 2 * (d2y
/ sin(beta
));
2484 if (alfa
< 0.000001 && beta
< 0.000001) {
2485 net
->cirseg
->height
= 0;
2488 #define RAD2DEG(a) (a * 180 / M_PI)
2492 net
->cirseg
->angle1
= RAD2DEG(alfa
);
2493 net
->cirseg
->angle2
= RAD2DEG(beta
);
2496 net
->cirseg
->angle1
= 180.0 - RAD2DEG(alfa
);
2497 net
->cirseg
->angle2
= 180.0 - RAD2DEG(beta
);
2500 net
->cirseg
->angle1
= 180.0 + RAD2DEG(alfa
);
2501 net
->cirseg
->angle2
= 180.0 + RAD2DEG(beta
);
2504 net
->cirseg
->angle1
= 360.0 - RAD2DEG(alfa
);
2505 net
->cirseg
->angle2
= 360.0 - RAD2DEG(beta
);
2508 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant
);
2511 if (net
->cirseg
->width
< 0.0)
2512 GERB_COMPILE_WARNING("Negative width [%f] in quadrant %d [%f][%f]\n",
2513 net
->cirseg
->width
, quadrant
, alfa
, beta
);
2515 if (net
->cirseg
->height
< 0.0)
2516 GERB_COMPILE_WARNING("Negative height [%f] in quadrant %d [%f][%f]\n",
2517 net
->cirseg
->height
, quadrant
, RAD2DEG(alfa
), RAD2DEG(beta
));
2521 } /* calc_cirseg_sq */
2524 /* ------------------------------------------------------------------ */
2526 calc_cirseg_mq(struct gerbv_net
*net
, int cw
,
2527 double delta_cp_x
, double delta_cp_y
)
2529 double d1x
, d1y
, d2x
, d2y
;
2532 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
2533 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
2538 d1x
= net
->start_x
- net
->cirseg
->cp_x
;
2539 d1y
= net
->start_y
- net
->cirseg
->cp_y
;
2540 d2x
= net
->stop_x
- net
->cirseg
->cp_x
;
2541 d2y
= net
->stop_y
- net
->cirseg
->cp_y
;
2543 alfa
= atan2(d1y
, d1x
);
2544 beta
= atan2(d2y
, d2x
);
2546 net
->cirseg
->width
= sqrt(delta_cp_x
*delta_cp_x
+ delta_cp_y
*delta_cp_y
);
2547 net
->cirseg
->width
*= 2.0;
2548 net
->cirseg
->height
= net
->cirseg
->width
;
2550 net
->cirseg
->angle1
= RAD2DEG(alfa
);
2551 net
->cirseg
->angle2
= RAD2DEG(beta
);
2554 * Make sure it's always positive angles
2556 if (net
->cirseg
->angle1
< 0.0) {
2557 net
->cirseg
->angle1
+= 360.0;
2558 net
->cirseg
->angle2
+= 360.0;
2561 if (net
->cirseg
->angle2
< 0.0)
2562 net
->cirseg
->angle2
+= 360.0;
2564 if(net
->cirseg
->angle2
== 0.0)
2565 net
->cirseg
->angle2
= 360.0;
2568 * This is a sanity check for angles after the nature of atan2.
2569 * If cw we must make sure angle1-angle2 are always positive,
2570 * If ccw we must make sure angle2-angle1 are always negative.
2571 * We should really return one angle and the difference as GTK
2572 * uses them. But what the heck, it works for me.
2575 if (net
->cirseg
->angle1
<= net
->cirseg
->angle2
)
2576 net
->cirseg
->angle2
-= 360.0;
2578 if (net
->cirseg
->angle1
>= net
->cirseg
->angle2
)
2579 net
->cirseg
->angle2
+= 360.0;
2583 } /* calc_cirseg_mq */
2587 gerber_update_any_running_knockout_measurements (gerbv_image_t
*image
)
2589 if (knockoutMeasure
) {
2590 knockoutLayer
->knockout
.lowerLeftX
= knockoutLimitXmin
;
2591 knockoutLayer
->knockout
.lowerLeftY
= knockoutLimitYmin
;
2592 knockoutLayer
->knockout
.width
= knockoutLimitXmax
- knockoutLimitXmin
;
2593 knockoutLayer
->knockout
.height
= knockoutLimitYmax
- knockoutLimitYmin
;
2594 knockoutMeasure
= FALSE
;
2600 gerber_calculate_final_justify_effects(gerbv_image_t
*image
)
2602 gdouble translateA
= 0.0, translateB
= 0.0;
2604 if (image
->info
->imageJustifyTypeA
!= GERBV_JUSTIFY_NOJUSTIFY
) {
2605 if (image
->info
->imageJustifyTypeA
== GERBV_JUSTIFY_CENTERJUSTIFY
)
2606 translateA
= (image
->info
->max_x
- image
->info
->min_x
) / 2.0;
2608 translateA
= -image
->info
->min_x
;
2610 if (image
->info
->imageJustifyTypeB
!= GERBV_JUSTIFY_NOJUSTIFY
) {
2611 if (image
->info
->imageJustifyTypeB
== GERBV_JUSTIFY_CENTERJUSTIFY
)
2612 translateB
= (image
->info
->max_y
- image
->info
->min_y
) / 2.0;
2614 translateB
= -image
->info
->min_y
;
2617 /* update the min/max values so the autoscale function can correctly
2618 centered a justified image */
2619 image
->info
->min_x
+= translateA
+ image
->info
->imageJustifyOffsetA
;
2620 image
->info
->max_x
+= translateA
+ image
->info
->imageJustifyOffsetA
;
2621 image
->info
->min_y
+= translateB
+ image
->info
->imageJustifyOffsetB
;
2622 image
->info
->max_y
+= translateB
+ image
->info
->imageJustifyOffsetB
;
2624 /* store the absolute offset for the justify so we can quickly offset
2625 the rendered picture during drawing */
2626 image
->info
->imageJustifyOffsetActualA
= translateA
+
2627 image
->info
->imageJustifyOffsetA
;
2628 image
->info
->imageJustifyOffsetActualB
= translateB
+
2629 image
->info
->imageJustifyOffsetB
;
2630 } /* gerber_calculate_final_justify_effects */
2634 gerber_update_min_and_max(gerbv_render_size_t
*boundingBox
,
2635 gdouble x
, gdouble y
, gdouble apertureSizeX1
,
2636 gdouble apertureSizeX2
,gdouble apertureSizeY1
,
2637 gdouble apertureSizeY2
)
2639 gdouble ourX1
= x
- apertureSizeX1
, ourY1
= y
- apertureSizeY1
;
2640 gdouble ourX2
= x
+ apertureSizeX2
, ourY2
= y
+ apertureSizeY2
;
2642 /* transform the point to the final rendered position, accounting
2643 for any scaling, offsets, mirroring, etc */
2644 /* NOTE: we need to already add/subtract in the aperture size since
2645 the final rendering may be scaled */
2646 cairo_matrix_transform_point (¤tMatrix
, &ourX1
, &ourY1
);
2647 cairo_matrix_transform_point (¤tMatrix
, &ourX2
, &ourY2
);
2649 /* check both points against the min/max, since depending on the rotation,
2650 mirroring, etc, either point could possibly be a min or max */
2651 if(boundingBox
->left
> ourX1
)
2652 boundingBox
->left
= ourX1
;
2653 if(boundingBox
->left
> ourX2
)
2654 boundingBox
->left
= ourX2
;
2655 if(boundingBox
->right
< ourX1
)
2656 boundingBox
->right
= ourX1
;
2657 if(boundingBox
->right
< ourX2
)
2658 boundingBox
->right
= ourX2
;
2659 if(boundingBox
->bottom
> ourY1
)
2660 boundingBox
->bottom
= ourY1
;
2661 if(boundingBox
->bottom
> ourY2
)
2662 boundingBox
->bottom
= ourY2
;
2663 if(boundingBox
->top
< ourY1
)
2664 boundingBox
->top
= ourY1
;
2665 if(boundingBox
->top
< ourY2
)
2666 boundingBox
->top
= ourY2
;
2667 } /* gerber_update_min_and_max */