2 * gEDA - GNU Electronic Design Automation
3 * This is a part of gerbv
5 * Copyright (C) 2000-2003 Stefan Petersen (spe@stacken.kth.se)
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
26 #include <math.h> /* pow() */
35 #include "gerb_error.h"
36 #include "gerb_stats.h"
38 //#define AMACRO_DEBUG
40 #ifndef RENDER_USING_GDK
44 /* include this for macro enums */
47 /* DEBUG printing. #define DEBUG 1 in config.h to use this fcn. */
48 #define dprintf if(DEBUG) printf
50 //#define AMACRO_DEBUG
52 #define A2I(a,b) (((a & 0xff) << 8) + (b & 0xff))
56 typedef struct gerb_state
{
65 enum aperture_state_t aperture_state
;
66 enum interpolation_t interpolation
;
67 enum interpolation_t prev_interpolation
;
68 gerb_net_t
*parea_start_node
;
70 gerb_netstate_t
*state
;
76 /* Local function prototypes */
77 static void parse_G_code(gerb_file_t
*fd
, gerb_state_t
*state
,
79 static void parse_D_code(gerb_file_t
*fd
, gerb_state_t
*state
,
81 static int parse_M_code(gerb_file_t
*fd
, gerb_image_t
*image
);
82 static void parse_rs274x(gint levelOfRecursion
, gerb_file_t
*fd
,
83 gerb_image_t
*image
, gerb_state_t
*state
,
84 gerb_net_t
*curr_net
, gerb_stats_t
*stats
,
85 gchar
*directoryPath
);
86 static int parse_aperture_definition(gerb_file_t
*fd
,
87 gerb_aperture_t
*aperture
,
88 gerb_image_t
*image
, gdouble scale
);
89 static void calc_cirseg_sq(struct gerb_net
*net
, int cw
,
90 double delta_cp_x
, double delta_cp_y
);
91 static void calc_cirseg_mq(struct gerb_net
*net
, int cw
,
92 double delta_cp_x
, double delta_cp_y
);
95 gerber_update_min_and_max(gerb_image_info_t
*info
, gdouble repeatX
, gdouble repeatY
,
96 gdouble x
, gdouble y
, gdouble apertureSizeX1
,
97 gdouble apertureSizeX2
,gdouble apertureSizeY1
,
98 gdouble apertureSizeY2
);
101 static void gerber_update_any_running_knockout_measurements(gerb_image_t
*image
);
103 static void gerber_calculate_final_justify_effects (gerb_image_t
*image
);
105 gboolean knockoutMeasure
= FALSE
;
106 gdouble knockoutLimitXmin
, knockoutLimitYmin
, knockoutLimitXmax
,
108 gerb_layer_t
*knockoutLayer
= NULL
;
110 #ifndef RENDER_USING_GDK
111 cairo_matrix_t currentMatrix
;
115 gerber_parse_file_segment (gint levelOfRecursion
, gerb_image_t
*image
,
116 gerb_state_t
*state
, gerb_net_t
*curr_net
,
117 gerb_stats_t
*stats
, gerb_file_t
*fd
,
118 gchar
*directoryPath
) {
119 int read
, coord
, len
;
120 double x_scale
= 0.0, y_scale
= 0.0;
121 double delta_cp_x
= 0.0, delta_cp_y
= 0.0;
122 double aperture_size
;
124 gboolean foundEOF
= FALSE
;
126 while ((read
= gerb_fgetc(fd
)) != EOF
) {
127 /* figure out the scale, since we need to normalize
128 all dimensions to inches */
129 if (state
->state
->unit
== MM
)
133 switch ((char)(read
& 0xff)) {
135 dprintf("... Found G code\n");
136 parse_G_code(fd
, state
, image
);
139 dprintf("... Found D code\n");
140 parse_D_code(fd
, state
, image
);
143 dprintf("... Found M code\n");
144 switch(parse_M_code(fd
, image
)) {
151 gerb_stats_add_error(stats
->error_list
,
153 "Unknown M code found.\n",
155 } /* switch(parse_M_code) */
158 dprintf("... Found X code\n");
160 coord
= gerb_fgetint(fd
, &len
);
161 if (image
->format
&& image
->format
->omit_zeros
== TRAILING
) {
163 switch ((image
->format
->x_int
+ image
->format
->x_dec
) - len
) {
179 if (image
->format
&& (image
->format
->coordinate
==INCREMENTAL
))
180 state
->curr_x
+= coord
;
182 state
->curr_x
= coord
;
186 dprintf("... Found Y code\n");
188 coord
= gerb_fgetint(fd
, &len
);
189 if (image
->format
&& image
->format
->omit_zeros
== TRAILING
) {
191 switch ((image
->format
->y_int
+ image
->format
->y_dec
) - len
) {
207 if (image
->format
&& (image
->format
->coordinate
==INCREMENTAL
))
208 state
->curr_y
+= coord
;
210 state
->curr_y
= coord
;
214 dprintf("... Found I code\n");
216 state
->delta_cp_x
= gerb_fgetint(fd
, NULL
);
220 dprintf("... Found J code\n");
222 state
->delta_cp_y
= gerb_fgetint(fd
, NULL
);
226 dprintf("... Found %% code\n");
227 parse_rs274x(levelOfRecursion
, fd
, image
, state
, curr_net
, stats
, directoryPath
);
229 int c
= gerb_fgetc(fd
);
230 if(c
== EOF
|| c
== '%')
235 dprintf("... Found * code\n");
237 if (state
->changed
== 0) break;
240 curr_net
->next
= (gerb_net_t
*)g_malloc(sizeof(gerb_net_t
));
241 if (curr_net
->next
== NULL
)
242 GERB_FATAL_ERROR("malloc curr_net->next failed\n");
243 curr_net
= curr_net
->next
;
244 memset((void *)curr_net
, 0, sizeof(gerb_net_t
));
245 curr_net
->layer
= state
->layer
;
246 curr_net
->state
= state
->state
;
248 * Scale to given coordinate format
249 * XXX only "omit leading zeros".
251 if (image
&& image
->format
){
252 x_scale
= pow(10.0, (double)image
->format
->x_dec
);
253 y_scale
= pow(10.0, (double)image
->format
->y_dec
);
257 curr_net
->start_x
= (double)state
->prev_x
/ x_scale
;
258 curr_net
->start_y
= (double)state
->prev_y
/ y_scale
;
259 curr_net
->stop_x
= (double)state
->curr_x
/ x_scale
;
260 curr_net
->stop_y
= (double)state
->curr_y
/ y_scale
;
261 delta_cp_x
= (double)state
->delta_cp_x
/ x_scale
;
262 delta_cp_y
= (double)state
->delta_cp_y
/ y_scale
;
265 switch (state
->interpolation
) {
267 curr_net
->cirseg
= (gerb_cirseg_t
*)g_malloc(sizeof(gerb_cirseg_t
));
268 if (curr_net
->cirseg
== NULL
)
269 GERB_FATAL_ERROR("malloc curr_net->cirseg failed\n");
270 memset((void *)curr_net
->cirseg
, 0, sizeof(gerb_cirseg_t
));
272 calc_cirseg_mq(curr_net
, 1, delta_cp_x
, delta_cp_y
);
274 calc_cirseg_sq(curr_net
, 1, delta_cp_x
, delta_cp_y
);
277 curr_net
->cirseg
= (gerb_cirseg_t
*)g_malloc(sizeof(gerb_cirseg_t
));
278 if (curr_net
->cirseg
== NULL
)
279 GERB_FATAL_ERROR("malloc curr_net->cirseg failed\n");
280 memset((void *)curr_net
->cirseg
, 0, sizeof(gerb_cirseg_t
));
282 calc_cirseg_mq(curr_net
, 0, delta_cp_x
, delta_cp_y
);
284 calc_cirseg_sq(curr_net
, 0, delta_cp_x
, delta_cp_y
);
288 * To be able to get back and fill in number of polygon corners
290 state
->parea_start_node
= curr_net
;
291 state
->in_parea_fill
= 1;
294 state
->parea_start_node
= NULL
;
295 state
->in_parea_fill
= 0;
299 } /* switch(state->interpolation) */
302 * Count number of points in Polygon Area
304 if (state
->in_parea_fill
&& state
->parea_start_node
) {
306 * "...all lines drawn with D01 are considered edges of the
307 * polygon. D02 closes and fills the polygon."
308 * p.49 rs274xrevd_e.pdf
309 * D02 -> state->aperture_state == OFF
312 /* UPDATE: temporarily disabling, since I suspect this is a typo
313 in the manual...D02 shouldn't end the polygon. This code
314 was adding many spurious polygon starts and ends to the render
315 image, making polygon element handling very tough
316 if (state->aperture_state == OFF &&
317 state->interpolation != PAREA_START) {
318 curr_net->interpolation = PAREA_END;
320 curr_net->next = (gerb_net_t *)g_malloc(sizeof(gerb_net_t));
321 if (curr_net->next == NULL)
322 GERB_FATAL_ERROR("malloc curr_net->next failed\n");
323 curr_net = curr_net->next;
324 memset((void *)curr_net, 0, sizeof(gerb_net_t));
325 curr_net->layer = state->layer;
326 curr_net->state = state->state;
328 curr_net->interpolation = PAREA_START;
329 state->parea_start_node = curr_net;
330 curr_net->next = (gerb_net_t *)g_malloc(sizeof(gerb_net_t));
331 if (curr_net->next == NULL)
332 GERB_FATAL_ERROR("malloc curr_net->next failed\n");
333 curr_net = curr_net->next;
334 memset((void *)curr_net, 0, sizeof(gerb_net_t));
335 curr_net->layer = state->layer;
336 curr_net->state = state->state;
338 curr_net->start_x = (double)state->prev_x / x_scale;
339 curr_net->start_y = (double)state->prev_y / y_scale;
340 curr_net->stop_x = (double)state->curr_x / x_scale;
341 curr_net->stop_y = (double)state->curr_y / y_scale;
344 } /* if (state->in_parea_fill && state->parea_start_node) */
346 curr_net
->interpolation
= state
->interpolation
;
349 * Override circular interpolation if no center was given.
350 * This should be a safe hack, since a good file should always
351 * include I or J. And even if the radius is zero, the endpoint
352 * should be the same as the start point, creating no line
354 if (((state
->interpolation
== CW_CIRCULAR
) ||
355 (state
->interpolation
== CCW_CIRCULAR
)) &&
356 ((state
->delta_cp_x
== 0.0) && (state
->delta_cp_y
== 0.0)))
357 curr_net
->interpolation
= LINEARx1
;
360 * If we detected the end of Polygon Area Fill we go back to
361 * the interpolation we had before that.
362 * Also if we detected any of the quadrant flags, since some
363 * gerbers don't reset the interpolation (EagleCad again).
365 if ((state
->interpolation
== PAREA_START
) ||
366 (state
->interpolation
== PAREA_END
))
367 state
->interpolation
= state
->prev_interpolation
;
370 * Save layer polarity and unit
372 curr_net
->layer
= state
->layer
;
374 state
->delta_cp_x
= 0.0;
375 state
->delta_cp_y
= 0.0;
376 curr_net
->aperture
= state
->curr_aperture
;
377 curr_net
->aperture_state
= state
->aperture_state
;
380 * For next round we save the current position as
381 * the previous position
383 state
->prev_x
= state
->curr_x
;
384 state
->prev_y
= state
->curr_y
;
387 * If we have an aperture defined at the moment we find
388 * min and max of image with compensation for mm.
390 if ((curr_net
->aperture
== 0) && !state
->in_parea_fill
)
393 /* only update the min/max values if we are drawing */
394 if ((curr_net
->aperture_state
!= OFF
)){
395 double repeat_off_X
= 0.0, repeat_off_Y
= 0.0;
398 * If step_and_repeat (%SR%) is used, check min_x,max_y etc for
399 * the ends of the step_and_repeat lattice. This goes wrong in
400 * the case of negative dist_X or dist_Y, in which case we
401 * should compare against the startpoints of the lines, not
402 * the stoppoints, but that seems an uncommon case (and the
403 * error isn't very big any way).
405 repeat_off_X
= (state
->layer
->stepAndRepeat
.X
- 1) *
406 state
->layer
->stepAndRepeat
.dist_X
;
407 repeat_off_Y
= (state
->layer
->stepAndRepeat
.Y
- 1) *
408 state
->layer
->stepAndRepeat
.dist_Y
;
411 #ifndef RENDER_USING_GDK
412 cairo_matrix_init (¤tMatrix
, 1, 0, 0, 1, 0, 0);
414 cairo_matrix_translate (¤tMatrix
, image
->info
->offsetA
,
415 image
->info
->offsetB
);
416 /* do image rotation */
417 cairo_matrix_rotate (¤tMatrix
, image
->info
->imageRotation
);
418 /* it's a new layer, so recalculate the new transformation
420 /* do any rotations */
421 cairo_matrix_rotate (¤tMatrix
, state
->layer
->rotation
);
423 /* calculate current layer and state transformation matrices */
424 /* apply scale factor */
425 cairo_matrix_scale (¤tMatrix
, state
->state
->scaleA
,
426 state
->state
->scaleB
);
428 cairo_matrix_translate (¤tMatrix
, state
->state
->offsetA
,
429 state
->state
->offsetB
);
431 switch (state
->state
->mirrorState
) {
433 cairo_matrix_scale (¤tMatrix
, -1, 1);
436 cairo_matrix_scale (¤tMatrix
, 1, -1);
439 cairo_matrix_scale (¤tMatrix
, -1, -1);
444 /* finally, apply axis select */
445 if (state
->state
->axisSelect
== SWAPAB
) {
446 /* we do this by rotating 270 (counterclockwise, then
447 * mirroring the Y axis
449 cairo_matrix_rotate (¤tMatrix
, 3 * M_PI
/ 2);
450 cairo_matrix_scale (¤tMatrix
, 1, -1);
453 /* if it's a macro, step through all the primitive components
454 and calculate the true bounding box */
455 if ((image
->aperture
[curr_net
->aperture
] != NULL
) &&
456 (image
->aperture
[curr_net
->aperture
]->type
== MACRO
)) {
457 gerb_simplified_amacro_t
*ls
= image
->aperture
[curr_net
->aperture
]->simplified
;
460 gdouble offsetx
= 0, offsety
= 0, widthx
= 0, widthy
= 0;
461 gboolean calculatedAlready
= FALSE
;
463 if (ls
->type
== MACRO_CIRCLE
) {
464 offsetx
=ls
->parameter
[CIRCLE_CENTER_X
];
465 offsety
=ls
->parameter
[CIRCLE_CENTER_Y
];
466 widthx
=widthy
=ls
->parameter
[CIRCLE_DIAMETER
];
467 } else if (ls
->type
== MACRO_OUTLINE
) {
468 int pointCounter
,numberOfPoints
;
469 numberOfPoints
= (int) ls
->parameter
[OUTLINE_NUMBER_OF_POINTS
];
471 for (pointCounter
= 0; pointCounter
< numberOfPoints
; pointCounter
++) {
472 gerber_update_min_and_max (image
->info
, repeat_off_X
, repeat_off_Y
,
473 ls
->parameter
[pointCounter
* 2 + OUTLINE_FIRST_X
],
474 ls
->parameter
[pointCounter
* 2 + OUTLINE_FIRST_Y
],
477 calculatedAlready
= TRUE
;
478 } else if (ls
->type
== MACRO_POLYGON
) {
479 offsetx
= ls
->parameter
[POLYGON_CENTER_X
];
480 offsety
= ls
->parameter
[POLYGON_CENTER_Y
];
481 widthx
= widthy
= ls
->parameter
[POLYGON_DIAMETER
];
482 } else if (ls
->type
== MACRO_MOIRE
) {
483 offsetx
= ls
->parameter
[MOIRE_CENTER_X
];
484 offsety
= ls
->parameter
[MOIRE_CENTER_Y
];
485 widthx
= widthy
= ls
->parameter
[MOIRE_OUTSIDE_DIAMETER
];
486 } else if (ls
->type
== MACRO_THERMAL
) {
487 offsetx
= ls
->parameter
[THERMAL_CENTER_X
];
488 offsety
= ls
->parameter
[THERMAL_CENTER_Y
];
489 widthx
= widthy
= ls
->parameter
[THERMAL_OUTSIDE_DIAMETER
];
490 } else if (ls
->type
== MACRO_LINE20
) {
491 widthx
= widthy
= ls
->parameter
[LINE20_LINE_WIDTH
];
492 gerber_update_min_and_max (image
->info
, repeat_off_X
, repeat_off_Y
,
493 ls
->parameter
[LINE20_START_X
] + offsetx
,
494 ls
->parameter
[LINE20_START_Y
] + offsety
,
495 widthx
/2,widthx
/2,widthy
/2,widthy
/2);
496 gerber_update_min_and_max (image
->info
, repeat_off_X
, repeat_off_Y
,
497 ls
->parameter
[LINE20_END_X
] + offsetx
,
498 ls
->parameter
[LINE20_END_Y
] + offsety
,
499 widthx
/2,widthx
/2,widthy
/2,widthy
/2);
500 calculatedAlready
= TRUE
;
501 } else if (ls
->type
== MACRO_LINE21
) {
502 gdouble largestDimension
= sqrt (ls
->parameter
[LINE21_WIDTH
]/2 *
503 ls
->parameter
[LINE21_WIDTH
]/2 + ls
->parameter
[LINE21_HEIGHT
/2] *
504 ls
->parameter
[LINE21_HEIGHT
]/2);
506 offsetx
= ls
->parameter
[LINE21_CENTER_X
];
507 offsety
= ls
->parameter
[LINE21_CENTER_Y
];
508 widthx
= widthy
=largestDimension
;
509 } else if (ls
->type
== MACRO_LINE22
) {
510 gdouble largestDimension
= sqrt (ls
->parameter
[LINE22_WIDTH
]/2 *
511 ls
->parameter
[LINE22_WIDTH
]/2 + ls
->parameter
[LINE22_HEIGHT
/2] *
512 ls
->parameter
[LINE22_HEIGHT
]/2);
514 offsetx
= ls
->parameter
[LINE22_LOWER_LEFT_X
] +
515 ls
->parameter
[LINE22_WIDTH
]/2;
516 offsety
= ls
->parameter
[LINE22_LOWER_LEFT_Y
] +
517 ls
->parameter
[LINE22_HEIGHT
]/2;
518 widthx
= widthy
=largestDimension
;
521 if (!calculatedAlready
) {
522 gerber_update_min_and_max (image
->info
, repeat_off_X
, repeat_off_Y
,
523 curr_net
->stop_x
+ offsetx
,
524 curr_net
->stop_y
+ offsety
,
525 widthx
/2,widthx
/2,widthy
/2,widthy
/2);
530 if (image
->aperture
[curr_net
->aperture
] != NULL
) {
531 aperture_size
= image
->aperture
[curr_net
->aperture
]->parameter
[0];
533 /* this is usually for polygon fills, where the aperture width
538 /* check both the start and stop of the aperture points against
539 a running min/max counter */
540 /* Note: only check start coordinate if this isn't a flash,
541 since the start point may be bogus if it is a flash */
542 if (curr_net
->aperture_state
!= FLASH
) {
543 gerber_update_min_and_max (image
->info
, repeat_off_X
, repeat_off_Y
,
544 curr_net
->start_x
, curr_net
->start_y
,
545 aperture_size
/2,aperture_size
/2,
546 aperture_size
/2,aperture_size
/2);
548 gerber_update_min_and_max (image
->info
, repeat_off_X
, repeat_off_Y
,
549 curr_net
->stop_x
, curr_net
->stop_y
,
550 aperture_size
/2,aperture_size
/2,
551 aperture_size
/2,aperture_size
/2);
555 case 10 : /* White space */
563 gerb_stats_add_error(stats
->error_list
,
565 g_strdup_printf("Found unknown character (whitespace?) [%d]%c\n",
568 } /* switch((char) (read & 0xff)) */
574 /* ------------------------------------------------------------------ */
576 parse_gerb(gerb_file_t
*fd
, gchar
*directoryPath
)
578 gerb_state_t
*state
= NULL
;
579 gerb_image_t
*image
= NULL
;
580 gerb_net_t
*curr_net
= NULL
;
582 gboolean foundEOF
= FALSE
;
584 /* added by t.motylewski@bfad.de
585 * many locales redefine "." as "," and so on,
586 * so sscanf and strtod has problems when
587 * reading files using %f format */
588 setlocale(LC_NUMERIC
, "C" );
591 * Create new state. This is used locally to keep track
592 * of the photoplotter's state as the Gerber is read in.
594 state
= (gerb_state_t
*)g_malloc(sizeof(gerb_state_t
));
596 GERB_FATAL_ERROR("malloc state failed\n");
601 memset((void *)state
, 0, sizeof(gerb_state_t
));
604 * Create new image. This will be returned.
606 image
= new_gerb_image(image
, "RS274-X (Gerber) File");
608 GERB_FATAL_ERROR("malloc image failed\n");
609 curr_net
= image
->netlist
;
610 image
->layertype
= GERBER
;
611 image
->gerb_stats
= gerb_stats_new();
612 if (image
->gerb_stats
== NULL
)
613 GERB_FATAL_ERROR("malloc gerb_stats failed\n");
614 stats
= (gerb_stats_t
*) image
->gerb_stats
;
616 /* set active layer and netstate to point to first default one created */
617 state
->layer
= image
->layers
;
618 state
->state
= image
->states
;
619 curr_net
->layer
= state
->layer
;
620 curr_net
->state
= state
->state
;
625 dprintf("In parse_gerb, starting to parse file...\n");
626 foundEOF
= gerber_parse_file_segment (1, image
, state
, curr_net
, stats
,
630 gerb_stats_add_error(stats
->error_list
,
632 "File is missing Gerber EOF code.\n",
637 dprintf(" ... done parsing Gerber file\n");
638 gerber_update_any_running_knockout_measurements (image
);
639 gerber_calculate_final_justify_effects(image
);
645 /* ------------------------------------------------------------------- */
647 * Checks for signs that this is a RS-274X file
648 * Returns TRUE if it is, FALSE if not.
651 gerber_is_rs274x_p(gerb_file_t
*fd
, gboolean
*returnFoundBinary
)
657 gboolean found_binary
= FALSE
;
658 gboolean found_ADD
= FALSE
;
659 gboolean found_D0
= FALSE
;
660 gboolean found_D2
= FALSE
;
661 gboolean found_M0
= FALSE
;
662 gboolean found_M2
= FALSE
;
663 gboolean found_star
= FALSE
;
664 gboolean found_X
= FALSE
;
665 gboolean found_Y
= FALSE
;
667 dprintf ("gerber_is_rs274x_p(%p, %p), fd->fd = %p\n", fd
, returnFoundBinary
, fd
->fd
);
668 buf
= (char *) g_malloc(MAXL
);
670 GERB_FATAL_ERROR("malloc buf failed while checking for rs274x.\n");
672 while (fgets(buf
, MAXL
, fd
->fd
) != NULL
) {
673 dprintf ("buf = \"%s\"\n", buf
);
676 /* First look through the file for indications of its type by
677 * checking that file is not binary (non-printing chars and white
680 for (i
= 0; i
< len
; i
++) {
681 if (!isprint((int) buf
[i
]) && (buf
[i
] != '\r') &&
682 (buf
[i
] != '\n') && (buf
[i
] != '\t')) {
684 dprintf ("found_binary (%d)\n", buf
[i
]);
687 if (g_strstr_len(buf
, len
, "%ADD")) {
689 dprintf ("found_ADD\n");
691 if (g_strstr_len(buf
, len
, "D00")) {
693 dprintf ("found_D0\n");
695 if (g_strstr_len(buf
, len
, "D02")) {
697 dprintf ("found_D2\n");
699 if (g_strstr_len(buf
, len
, "M0")) {
701 dprintf ("found_M0\n");
703 if (g_strstr_len(buf
, len
, "M00")) {
705 dprintf ("found_M0\n");
707 if (g_strstr_len(buf
, len
, "M2")) {
709 dprintf ("found_M2\n");
711 if (g_strstr_len(buf
, len
, "M02")) {
713 dprintf ("found_M2\n");
715 if (g_strstr_len(buf
, len
, "*")) {
717 dprintf ("found_star\n");
719 /* look for X<number> or Y<number> */
720 if ((letter
= g_strstr_len(buf
, len
, "X")) != NULL
) {
721 if (isdigit((int) letter
[1])) { /* grab char after X */
723 dprintf ("found_X\n");
726 if ((letter
= g_strstr_len(buf
, len
, "Y")) != NULL
) {
727 if (isdigit((int) letter
[1])) { /* grab char after Y */
729 dprintf ("found_Y\n");
736 *returnFoundBinary
= found_binary
;
738 /* Now form logical expression determining if the file is RS-274X */
739 if ((found_D0
|| found_D2
|| found_M0
|| found_M2
) &&
740 found_ADD
&& found_star
&& (found_X
|| found_Y
))
746 } /* gerber_is_rs274x */
749 /* ------------------------------------------------------------------- */
751 * Checks for signs that this is a RS-274D file
752 * Returns TRUE if it is, FALSE if not.
755 gerber_is_rs274d_p(gerb_file_t
*fd
)
761 gboolean found_binary
= FALSE
;
762 gboolean found_ADD
= FALSE
;
763 gboolean found_D0
= FALSE
;
764 gboolean found_D2
= FALSE
;
765 gboolean found_M0
= FALSE
;
766 gboolean found_M2
= FALSE
;
767 gboolean found_star
= FALSE
;
768 gboolean found_X
= FALSE
;
769 gboolean found_Y
= FALSE
;
773 GERB_FATAL_ERROR("malloc buf failed while checking for rs274d.\n");
775 while (fgets(buf
, MAXL
, fd
->fd
) != NULL
) {
778 /* First look through the file for indications of its type */
780 /* check that file is not binary (non-printing chars */
781 for (i
= 0; i
< len
; i
++) {
782 if (!isprint( (int) buf
[i
]) && (buf
[i
] != '\r') &&
783 (buf
[i
] != '\n') && (buf
[i
] != '\t')) {
788 if (g_strstr_len(buf
, len
, "%ADD")) {
791 if (g_strstr_len(buf
, len
, "D00")) {
794 if (g_strstr_len(buf
, len
, "D02")) {
797 if (g_strstr_len(buf
, len
, "M0")) {
800 if (g_strstr_len(buf
, len
, "M00")) {
803 if (g_strstr_len(buf
, len
, "M02")) {
806 if (g_strstr_len(buf
, len
, "*")) {
809 /* look for X<number> or Y<number> */
810 if ((letter
= g_strstr_len(buf
, len
, "X")) != NULL
) {
811 /* grab char after X */
812 if (isdigit( (int) letter
[1])) {
816 if ((letter
= g_strstr_len(buf
, len
, "Y")) != NULL
) {
817 /* grab char after Y */
818 if (isdigit( (int) letter
[1])) {
826 /* Now form logical expression determining if the file is RS-274D */
827 if ((found_D0
|| found_D2
|| found_M0
|| found_M2
) &&
828 !found_ADD
&& found_star
&& (found_X
|| found_Y
) &&
834 } /* gerber_is_rs274d */
837 /* ------------------------------------------------------------------- */
839 parse_G_code(gerb_file_t
*fd
, gerb_state_t
*state
, gerb_image_t
*image
)
842 gerb_format_t
*format
= image
->format
;
843 gerb_stats_t
*stats
= image
->gerb_stats
;
846 op_int
=gerb_fgetint(fd
, NULL
);
850 /* Is this doing anything really? */
853 case 1: /* Linear Interpolation (1X scale) */
854 state
->interpolation
= LINEARx1
;
857 case 2: /* Clockwise Linear Interpolation */
858 state
->interpolation
= CW_CIRCULAR
;
861 case 3: /* Counter Clockwise Linear Interpolation */
862 state
->interpolation
= CCW_CIRCULAR
;
865 case 4: /* Ignore Data Block */
866 /* Don't do anything, just read 'til * */
868 while ((c
!= EOF
) && (c
!= '*')) {
873 case 10: /* Linear Interpolation (10X scale) */
874 state
->interpolation
= LINEARx10
;
877 case 11: /* Linear Interpolation (0.1X scale) */
878 state
->interpolation
= LINEARx01
;
881 case 12: /* Linear Interpolation (0.01X scale) */
882 state
->interpolation
= LINEARx001
;
885 case 36: /* Turn on Polygon Area Fill */
886 state
->prev_interpolation
= state
->interpolation
;
887 state
->interpolation
= PAREA_START
;
891 case 37: /* Turn off Polygon Area Fill */
892 state
->interpolation
= PAREA_END
;
896 case 54: /* Tool prepare */
897 /* XXX Maybe uneccesary??? */
898 if (gerb_fgetc(fd
) == 'D') {
899 int a
= gerb_fgetint(fd
, NULL
);
900 if ((a
>= APERTURE_MIN
) && (a
<= APERTURE_MAX
)) {
901 state
->curr_aperture
= a
;
902 dprintf(" In parse_G_code, case 54, found D and adding 1 to no %d in D_list ...\n", a
);
903 gerb_stats_increment_D_list_count(stats
->D_code_list
,
908 gerb_stats_add_error(stats
->error_list
,
910 g_strdup_printf("Found aperture out of bounds while parsing G code: %d\n", a
),
914 gerb_stats_add_error(stats
->error_list
,
916 "Found unexpected code after G54\n",
918 /* Must insert error count here */
922 case 55: /* Prepare for flash */
925 case 70: /* Specify inches */
926 state
->state
= gerb_image_return_new_netstate (state
->state
);
927 state
->state
->unit
= INCH
;
930 case 71: /* Specify millimeters */
931 state
->state
= gerb_image_return_new_netstate (state
->state
);
932 state
->state
->unit
= MM
;
935 case 74: /* Disable 360 circular interpolation */
939 case 75: /* Enable 360 circular interpolation */
943 case 90: /* Specify absolut format */
944 if (format
) format
->coordinate
= ABSOLUTE
;
947 case 91: /* Specify incremental format */
948 if (format
) format
->coordinate
= INCREMENTAL
;
952 gerb_stats_add_error(stats
->error_list
,
954 g_strdup_printf("Encountered unknown G code : G%d\n", op_int
),
956 gerb_stats_add_error(stats
->error_list
,
958 g_strdup_printf("Ignorning unknown G code\n"),
962 /* Enter error count here */
970 /* ------------------------------------------------------------------ */
972 parse_D_code(gerb_file_t
*fd
, gerb_state_t
*state
, gerb_image_t
*image
)
975 gerb_stats_t
*stats
= image
->gerb_stats
;
977 a
= gerb_fgetint(fd
, NULL
);
978 dprintf(" In parse_D_code, found D number = %d ... \n", a
);
980 case 1 : /* Exposure on */
981 state
->aperture_state
= ON
;
985 case 2 : /* Exposure off */
986 state
->aperture_state
= OFF
;
990 case 3 : /* Flash aperture */
991 state
->aperture_state
= FLASH
;
995 default: /* Aperture in use */
996 if ((a
>= APERTURE_MIN
) && (a
<= APERTURE_MAX
)) {
997 state
->curr_aperture
= a
;
999 dprintf(" In parse_D_code, adding 1 to D_list ...\n");
1000 int retcode
= gerb_stats_increment_D_list_count(stats
->D_code_list
,
1004 if (retcode
== -1) {
1005 gerb_stats_add_error(stats
->error_list
,
1007 g_strdup_printf("Found undefined D code: D%d\n", a
),
1012 gerb_stats_add_error(stats
->error_list
,
1014 g_strdup_printf("Found aperture number out of bounds while parsing D code: %d\n", a
),
1023 } /* parse_D_code */
1026 /* ------------------------------------------------------------------ */
1028 parse_M_code(gerb_file_t
*fd
, gerb_image_t
*image
)
1031 gerb_stats_t
*stats
= image
->gerb_stats
;
1033 op_int
=gerb_fgetint(fd
, NULL
);
1036 case 0: /* Program stop */
1039 case 1: /* Optional stop */
1042 case 2: /* End of program */
1046 gerb_stats_add_error(stats
->error_list
,
1048 g_strdup_printf("Encountered unknown M code : M%d\n", op_int
),
1050 gerb_stats_add_error(stats
->error_list
,
1052 g_strdup_printf("Ignorning unknown M code\n"),
1057 } /* parse_M_code */
1060 /* ------------------------------------------------------------------ */
1062 parse_rs274x(gint levelOfRecursion
, gerb_file_t
*fd
, gerb_image_t
*image
,
1063 gerb_state_t
*state
, gerb_net_t
*curr_net
, gerb_stats_t
*stats
,
1064 gchar
*directoryPath
)
1069 gerb_aperture_t
*a
= NULL
;
1070 amacro_t
*tmp_amacro
;
1072 gdouble scale
= 1.0;
1074 if (state
->state
->unit
== MM
)
1077 op
[0] = gerb_fgetc(fd
);
1078 op
[1] = gerb_fgetc(fd
);
1080 if ((op
[0] == EOF
) || (op
[1] == EOF
))
1081 gerb_stats_add_error(stats
->error_list
,
1083 "Unexpected EOF found.\n",
1086 switch (A2I(op
[0], op
[1])){
1089 * Directive parameters
1091 case A2I('A','S'): /* Axis Select */
1092 op
[0] = gerb_fgetc(fd
);
1093 op
[1] = gerb_fgetc(fd
);
1094 state
->state
= gerb_image_return_new_netstate (state
->state
);
1096 if ((op
[0] == EOF
) || (op
[1] == EOF
))
1097 gerb_stats_add_error(stats
->error_list
,
1099 "Unexpected EOF found.\n",
1102 if (((op
[0] == 'A') && (op
[1] == 'Y')) ||
1103 ((op
[0] == 'B') && (op
[1] == 'X'))) {
1104 state
->state
->axisSelect
= SWAPAB
;
1106 state
->state
->axisSelect
= NOSELECT
;
1109 op
[0] = gerb_fgetc(fd
);
1110 op
[1] = gerb_fgetc(fd
);
1112 if ((op
[0] == EOF
) || (op
[1] == EOF
))
1113 gerb_stats_add_error(stats
->error_list
,
1115 "Unexpected EOF found.\n",
1118 if (((op
[0] == 'A') && (op
[1] == 'Y')) ||
1119 ((op
[0] == 'B') && (op
[1] == 'X'))) {
1120 state
->state
->axisSelect
= SWAPAB
;
1122 state
->state
->axisSelect
= NOSELECT
;
1126 case A2I('F','S'): /* Format Statement */
1127 image
->format
= (gerb_format_t
*)g_malloc(sizeof(gerb_format_t
));
1128 if (image
->format
== NULL
)
1129 GERB_FATAL_ERROR("Failed malloc for format\n");
1130 memset((void *)image
->format
, 0, sizeof(gerb_format_t
));
1132 switch (gerb_fgetc(fd
)) {
1134 image
->format
->omit_zeros
= LEADING
;
1137 image
->format
->omit_zeros
= TRAILING
;
1140 image
->format
->omit_zeros
= EXPLICIT
;
1143 gerb_stats_add_error(stats
->error_list
,
1145 "EagleCad bug detected: Undefined handling of zeros in format code\n",
1147 gerb_stats_add_error(stats
->error_list
,
1149 "Defaulting to omitting leading zeros.\n",
1152 image
->format
->omit_zeros
= LEADING
;
1155 switch (gerb_fgetc(fd
)) {
1157 image
->format
->coordinate
= ABSOLUTE
;
1160 image
->format
->coordinate
= INCREMENTAL
;
1163 gerb_stats_add_error(stats
->error_list
,
1165 "Invalid coordinate type defined in format code.\n",
1167 gerb_stats_add_error(stats
->error_list
,
1169 "Defaulting to absolute.\n",
1171 image
->format
->coordinate
= ABSOLUTE
;
1173 op
[0] = gerb_fgetc(fd
);
1174 while((op
[0] != '*')&&(op
[0] != EOF
)) {
1177 op
[0] = (char)gerb_fgetc(fd
);
1178 image
->format
->lim_seqno
= op
[0] - '0';
1181 op
[0] = (char)gerb_fgetc(fd
);
1182 image
->format
->lim_gf
= op
[0] - '0';
1185 op
[0] = (char)gerb_fgetc(fd
);
1186 image
->format
->lim_pf
= op
[0] - '0';
1189 op
[0] = (char)gerb_fgetc(fd
);
1190 image
->format
->lim_mf
= op
[0] - '0';
1193 op
[0] = gerb_fgetc(fd
);
1194 if ((op
[0] < '0') || (op
[0] > '6'))
1195 gerb_stats_add_error(stats
->error_list
,
1197 g_strdup_printf("Illegal format size : %c\n", (char)op
[0]),
1199 image
->format
->x_int
= op
[0] - '0';
1200 op
[0] = gerb_fgetc(fd
);
1201 if ((op
[0] < '0') || (op
[0] > '6'))
1202 gerb_stats_add_error(stats
->error_list
,
1204 g_strdup_printf("Illegal format size : %c\n", (char)op
[0]),
1206 image
->format
->x_dec
= op
[0] - '0';
1209 op
[0] = gerb_fgetc(fd
);
1210 if ((op
[0] < '0') || (op
[0] > '6'))
1211 gerb_stats_add_error(stats
->error_list
,
1213 g_strdup_printf("Illegal format size : %c\n", (char)op
[0]),
1215 image
->format
->y_int
= op
[0] - '0';
1216 op
[0] = gerb_fgetc(fd
);
1217 if ((op
[0] < '0') || (op
[0] > '6'))
1218 gerb_stats_add_error(stats
->error_list
,
1220 g_strdup_printf("Illegal format size : %c\n", (char)op
[0]),
1222 image
->format
->y_dec
= op
[0] - '0';
1225 gerb_stats_add_error(stats
->error_list
,
1227 g_strdup_printf("Invalid format statement [%c]\n", op
[0]),
1229 gerb_stats_add_error(stats
->error_list
,
1231 "Ignoring invalid format statement.\n",
1234 op
[0] = gerb_fgetc(fd
);
1237 case A2I('M','I'): /* Mirror Image */
1238 op
[0] = gerb_fgetc(fd
);
1239 state
->state
= gerb_image_return_new_netstate (state
->state
);
1241 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1245 readValue
= gerb_fgetint(fd
, NULL
);
1246 if (readValue
== 1) {
1247 if (state
->state
->mirrorState
== FLIPB
)
1248 state
->state
->mirrorState
=FLIPAB
;
1250 state
->state
->mirrorState
=FLIPA
;
1254 readValue
= gerb_fgetint(fd
, NULL
);
1255 if (readValue
== 1) {
1256 if (state
->state
->mirrorState
== FLIPA
)
1257 state
->state
->mirrorState
=FLIPAB
;
1259 state
->state
->mirrorState
=FLIPB
;
1263 gerb_stats_add_error(stats
->error_list
,
1265 g_strdup_printf("Wrong character in mirror:%c\n", op
[0]),
1268 op
[0] = gerb_fgetc(fd
);
1271 case A2I('M','O'): /* Mode of Units */
1272 op
[0] = gerb_fgetc(fd
);
1273 op
[1] = gerb_fgetc(fd
);
1275 if ((op
[0] == EOF
) || (op
[1] == EOF
))
1276 gerb_stats_add_error(stats
->error_list
,
1278 "Unexpected EOF found.\n",
1280 switch (A2I(op
[0],op
[1])) {
1282 state
->state
= gerb_image_return_new_netstate (state
->state
);
1283 state
->state
->unit
= INCH
;
1286 state
->state
= gerb_image_return_new_netstate (state
->state
);
1287 state
->state
->unit
= MM
;
1290 gerb_stats_add_error(stats
->error_list
,
1292 g_strdup_printf("Illegal unit:%c%c\n", op
[0], op
[1]),
1296 case A2I('O','F'): /* Offset */
1297 op
[0] = gerb_fgetc(fd
);
1299 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1302 state
->state
->offsetA
= gerb_fgetdouble(fd
) / scale
;
1305 state
->state
->offsetB
= gerb_fgetdouble(fd
) / scale
;
1308 gerb_stats_add_error(stats
->error_list
,
1310 g_strdup_printf("Wrong character in offset:%c\n", op
[0]),
1313 op
[0] = gerb_fgetc(fd
);
1316 case A2I('I','F'): /* Include file */
1318 gchar
*includeFilename
= gerb_fgetstring(fd
, '*');
1320 if (includeFilename
) {
1322 if (!g_path_is_absolute(includeFilename
)) {
1323 fullPath
= g_build_filename (directoryPath
, includeFilename
, NULL
);
1325 fullPath
= g_strdup (includeFilename
);
1327 if (levelOfRecursion
< 10) {
1328 gerb_file_t
*includefd
= NULL
;
1330 includefd
= gerb_fopen(fullPath
);
1332 gerber_parse_file_segment (levelOfRecursion
+ 1, image
, state
, curr_net
, stats
, includefd
, directoryPath
);
1333 gerb_fclose(includefd
);
1335 gerb_stats_add_error(stats
->error_list
, -1,
1336 g_strdup_printf("Included file cannot be found:%s\n",fullPath
), GRB_ERROR
);
1340 gerb_stats_add_error(stats
->error_list
, -1,
1341 g_strdup_printf("Parser encountered more than 10 levels of include file recursion, which is not allowed by the RS-274X spec\n"), GRB_ERROR
);
1347 case A2I('I','O'): /* Image offset */
1348 op
[0] = gerb_fgetc(fd
);
1350 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1353 image
->info
->offsetA
= gerb_fgetdouble(fd
) / scale
;
1356 image
->info
->offsetB
= gerb_fgetdouble(fd
) / scale
;
1359 gerb_stats_add_error(stats
->error_list
,
1361 g_strdup_printf("Wrong character in offset:%c\n", op
[0]),
1364 op
[0] = gerb_fgetc(fd
);
1367 case A2I('S','F'): /* Scale Factor */
1368 if (gerb_fgetc(fd
) == 'A')
1369 state
->state
->scaleA
= gerb_fgetdouble(fd
);
1372 if (gerb_fgetc(fd
) == 'B')
1373 state
->state
->scaleB
= gerb_fgetdouble(fd
);
1377 case A2I('I','C'): /* Input Code */
1378 /* Thanks to Stephen Adam for providing this information. As he writes:
1379 * btw, here's a logic puzzle for you. If you need to
1380 * read the gerber file to see how it's encoded, then
1381 * how can you read it?
1383 op
[0] = gerb_fgetc(fd
);
1384 op
[1] = gerb_fgetc(fd
);
1386 if ((op
[0] == EOF
) || (op
[1] == EOF
))
1387 gerb_stats_add_error(stats
->error_list
,
1389 "Unexpected EOF found.\n",
1391 switch (A2I(op
[0],op
[1])) {
1393 image
->info
->encoding
= ASCII
;
1396 image
->info
->encoding
= EBCDIC
;
1399 image
->info
->encoding
= BCD
;
1402 image
->info
->encoding
= ISO_ASCII
;
1405 image
->info
->encoding
= EIA
;
1408 gerb_stats_add_error(stats
->error_list
,
1410 g_strdup_printf("Unknown input code (IC): %c%c\n", op
[0], op
[1]),
1415 /* Image parameters */
1416 case A2I('I','J'): /* Image Justify */
1417 op
[0] = gerb_fgetc(fd
);
1418 image
->info
->imageJustifyTypeA
= LOWERLEFT
;
1419 image
->info
->imageJustifyTypeB
= LOWERLEFT
;
1420 image
->info
->imageJustifyOffsetA
= 0.0;
1421 image
->info
->imageJustifyOffsetB
= 0.0;
1422 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1425 op
[0] = gerb_fgetc(fd
);
1427 image
->info
->imageJustifyTypeA
= CENTERJUSTIFY
;
1428 } else if (op
[0] == 'L') {
1429 image
->info
->imageJustifyTypeA
= LOWERLEFT
;
1432 image
->info
->imageJustifyOffsetA
= gerb_fgetdouble(fd
) / scale
;
1436 op
[0] = gerb_fgetc(fd
);
1438 image
->info
->imageJustifyTypeB
= CENTERJUSTIFY
;
1439 } else if (op
[0] == 'L') {
1440 image
->info
->imageJustifyTypeB
= LOWERLEFT
;
1443 image
->info
->imageJustifyOffsetB
= gerb_fgetdouble(fd
) / scale
;
1447 gerb_stats_add_error(stats
->error_list
,
1449 g_strdup_printf("Wrong character in image justify:%c\n", op
[0]),
1452 op
[0] = gerb_fgetc(fd
);
1455 case A2I('I','N'): /* Image Name */
1456 image
->info
->name
= gerb_fgetstring(fd
, '*');
1458 case A2I('I','P'): /* Image Polarity */
1460 for (ano
= 0; ano
< 3; ano
++) {
1461 op
[0] = gerb_fgetc(fd
);
1463 gerb_stats_add_error(stats
->error_list
,
1465 "Unexpected EOF while reading image polarity (IP)\n",
1467 str
[ano
] = (char)op
[0];
1470 if (strncmp(str
, "POS", 3) == 0)
1471 image
->info
->polarity
= POSITIVE
;
1472 else if (strncmp(str
, "NEG", 3) == 0)
1473 image
->info
->polarity
= NEGATIVE
;
1475 gerb_stats_add_error(stats
->error_list
,
1477 g_strdup_printf("Unknown polarity : %c%c%c\n", str
[0], str
[1], str
[2]),
1480 case A2I('I','R'): /* Image Rotation */
1481 tmp
= gerb_fgetint(fd
, NULL
);
1483 image
->info
->imageRotation
= M_PI
/ 2.0;
1484 else if (tmp
== 180)
1485 image
->info
->imageRotation
= M_PI
;
1486 else if (tmp
== 270)
1487 image
->info
->imageRotation
= 3.0 * M_PI
/ 2.0;
1489 gerb_stats_add_error(stats
->error_list
,
1491 g_strdup_printf("Image rotation must be 0, 90, 180 or 270 (is actually %d)\n", tmp
),
1494 case A2I('P','F'): /* Plotter Film */
1495 image
->info
->plotterFilm
= gerb_fgetstring(fd
, '*');
1498 /* Aperture parameters */
1499 case A2I('A','D'): /* Aperture Description */
1500 a
= (gerb_aperture_t
*)g_malloc(sizeof(gerb_aperture_t
));
1502 GERB_FATAL_ERROR("malloc aperture failed\n");
1503 memset((void *)a
, 0, sizeof(gerb_aperture_t
));
1504 ano
= parse_aperture_definition(fd
, a
, image
, scale
);
1505 if ((ano
>= APERTURE_MIN
) && (ano
<= APERTURE_MAX
)) {
1506 a
->unit
= state
->state
->unit
;
1507 image
->aperture
[ano
] = a
;
1508 dprintf(" In parse_rs274x, adding new aperture to aperture list ...\n");
1509 gerb_stats_add_aperture(stats
->aperture_list
,
1513 gerb_stats_add_to_D_list(stats
->D_code_list
,
1516 gerb_stats_add_error(stats
->error_list
,
1518 g_strdup_printf("Aperture number out of bounds : %d\n", ano
),
1521 /* Add aperture info to stats->aperture_list here */
1524 case A2I('A','M'): /* Aperture Macro */
1525 tmp_amacro
= image
->amacro
;
1526 image
->amacro
= parse_aperture_macro(fd
);
1527 if (image
->amacro
) {
1528 image
->amacro
->next
= tmp_amacro
;
1530 print_program(image
->amacro
);
1533 gerb_stats_add_error(stats
->error_list
,
1535 "Failed to parse aperture macro\n",
1540 case A2I('L','N'): /* Layer Name */
1541 state
->layer
= gerb_image_return_new_layer (state
->layer
);
1542 state
->layer
->name
= gerb_fgetstring(fd
, '*');
1544 case A2I('L','P'): /* Layer Polarity */
1545 state
->layer
= gerb_image_return_new_layer (state
->layer
);
1546 switch (gerb_fgetc(fd
)) {
1547 case 'D': /* Dark Polarity (default) */
1548 state
->layer
->polarity
= DARK
;
1550 case 'C': /* Clear Polarity */
1551 state
->layer
->polarity
= CLEAR
;
1554 gerb_stats_add_error(stats
->error_list
,
1556 g_strdup_printf("Unknown Layer Polarity: %c\n", op
[0]),
1560 case A2I('K','O'): /* Knock Out */
1561 state
->layer
= gerb_image_return_new_layer (state
->layer
);
1562 gerber_update_any_running_knockout_measurements (image
);
1563 /* reset any previous knockout measurements */
1564 knockoutMeasure
= FALSE
;
1565 op
[0] = gerb_fgetc(fd
);
1566 if (op
[0] == '*') { /* Disable previous SR parameters */
1567 state
->layer
->knockout
.type
= NOKNOCKOUT
;
1569 } else if (op
[0] == 'C') {
1570 state
->layer
->knockout
.polarity
= CLEAR
;
1571 } else if (op
[0] == 'D') {
1572 state
->layer
->knockout
.polarity
= DARK
;
1574 gerb_stats_add_error(stats
->error_list
,
1576 "Knockout must supply a polarity (C, D, or *)\n",
1579 state
->layer
->knockout
.lowerLeftX
= 0.0;
1580 state
->layer
->knockout
.lowerLeftY
= 0.0;
1581 state
->layer
->knockout
.width
= 0.0;
1582 state
->layer
->knockout
.height
= 0.0;
1583 state
->layer
->knockout
.border
= 0.0;
1584 state
->layer
->knockout
.firstInstance
= TRUE
;
1585 op
[0] = gerb_fgetc(fd
);
1586 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1589 state
->layer
->knockout
.type
= FIXEDKNOCK
;
1590 state
->layer
->knockout
.lowerLeftX
= gerb_fgetdouble(fd
) / scale
;
1593 state
->layer
->knockout
.type
= FIXEDKNOCK
;
1594 state
->layer
->knockout
.lowerLeftY
= gerb_fgetdouble(fd
) / scale
;
1597 state
->layer
->knockout
.type
= FIXEDKNOCK
;
1598 state
->layer
->knockout
.width
= gerb_fgetdouble(fd
) / scale
;
1601 state
->layer
->knockout
.type
= FIXEDKNOCK
;
1602 state
->layer
->knockout
.height
= gerb_fgetdouble(fd
) / scale
;
1605 state
->layer
->knockout
.type
= BORDER
;
1606 state
->layer
->knockout
.border
= gerb_fgetdouble(fd
) / scale
;
1607 /* this is a bordered knockout, so we need to start measuring the
1608 size of a square bordering all future components */
1609 knockoutMeasure
= TRUE
;
1610 knockoutLimitXmin
= HUGE_VAL
;
1611 knockoutLimitYmin
= HUGE_VAL
;
1612 knockoutLimitXmax
= -HUGE_VAL
;
1613 knockoutLimitYmax
= -HUGE_VAL
;
1614 knockoutLayer
= state
->layer
;
1617 gerb_stats_add_error(stats
->error_list
,
1619 "Unknown variable in knockout",
1622 op
[0] = gerb_fgetc(fd
);
1625 case A2I('S','R'): /* Step and Repeat */
1626 /* start by generating a new layer (duplicating previous layer settings */
1627 state
->layer
= gerb_image_return_new_layer (state
->layer
);
1628 op
[0] = gerb_fgetc(fd
);
1629 if (op
[0] == '*') { /* Disable previous SR parameters */
1630 state
->layer
->stepAndRepeat
.X
= 1;
1631 state
->layer
->stepAndRepeat
.Y
= 1;
1632 state
->layer
->stepAndRepeat
.dist_X
= 0.0;
1633 state
->layer
->stepAndRepeat
.dist_Y
= 0.0;
1636 while ((op
[0] != '*')&&(op
[0] != EOF
)) {
1639 state
->layer
->stepAndRepeat
.X
= gerb_fgetint(fd
, NULL
);
1642 state
->layer
->stepAndRepeat
.Y
= gerb_fgetint(fd
, NULL
);
1645 state
->layer
->stepAndRepeat
.dist_X
= gerb_fgetdouble(fd
) / scale
;
1648 state
->layer
->stepAndRepeat
.dist_Y
= gerb_fgetdouble(fd
) / scale
;
1651 gerb_stats_add_error(stats
->error_list
,
1653 "Step-and-repeat parameter error\n",
1658 * Repeating 0 times in any direction would disable the whole plot, and
1659 * is probably not intended. At least one other tool (viewmate) seems
1660 * to interpret 0-time repeating as repeating just once too.
1662 if(state
->layer
->stepAndRepeat
.X
== 0)
1663 state
->layer
->stepAndRepeat
.X
= 1;
1664 if(state
->layer
->stepAndRepeat
.Y
== 0)
1665 state
->layer
->stepAndRepeat
.Y
= 1;
1667 op
[0] = gerb_fgetc(fd
);
1670 /* is this an actual RS274X command?? It isn't explainined in the spec... */
1672 state
->layer
= gerb_image_return_new_layer (state
->layer
);
1674 state
->layer
->rotation
= gerb_fgetdouble(fd
) * M_PI
/ 180;
1675 op
[0] = gerb_fgetc(fd
);
1677 gerb_stats_add_error(stats
->error_list
,
1679 "Error in layer rotation comman\n",
1684 gerb_stats_add_error(stats
->error_list
,
1686 g_strdup_printf("Unknown RS-274X extension found %%%c%c%%\n", op
[0], op
[1]),
1691 } /* parse_rs274x */
1695 * Stack declarations and operations to be used by the simple engine that
1696 * executes the parsed aperture macros.
1704 static macro_stack_t
*
1705 new_stack(unsigned int stack_size
)
1709 s
= (macro_stack_t
*)malloc(sizeof(macro_stack_t
));
1714 memset(s
, 0, sizeof(macro_stack_t
));
1716 s
->stack
= (double *)malloc(sizeof(double) * stack_size
);
1722 memset(s
->stack
, 0, sizeof(double) * stack_size
);
1730 free_stack(macro_stack_t
*s
)
1743 push(macro_stack_t
*s
, double val
)
1745 s
->stack
[s
->sp
++] = val
;
1751 pop(macro_stack_t
*s
, double *value
)
1753 /* Check if we try to pop an empty stack */
1758 *value
= s
->stack
[--s
->sp
];
1763 /* ------------------------------------------------------------------ */
1765 simplify_aperture_macro(gerb_aperture_t
*aperture
, gdouble scale
)
1767 const int extra_stack_size
= 10;
1770 int handled
= 1, nuf_parameters
= 0, i
, j
, clearOperatorUsed
= FALSE
;
1771 double *lp
; /* Local copy of parameters */
1772 double tmp
[2] = {0.0, 0.0};
1773 enum aperture_t type
= APERTURE_NONE
;
1774 gerb_simplified_amacro_t
*sam
;
1776 if (aperture
== NULL
)
1777 GERB_FATAL_ERROR("aperture NULL in simplify aperture macro\n");
1779 if (aperture
->amacro
== NULL
)
1780 GERB_FATAL_ERROR("aperture->amacro NULL in simplify aperture macro\n");
1782 /* Allocate stack for VM */
1783 s
= new_stack(aperture
->amacro
->nuf_push
+ extra_stack_size
);
1785 GERB_FATAL_ERROR("malloc stack failed\n");
1787 /* Make a copy of the parameter list that we can rewrite if necessary */
1788 lp
= (double *)malloc(sizeof(double) * APERTURE_PARAMETERS_MAX
);
1790 GERB_FATAL_ERROR("malloc local parameter storage failed\n");
1792 memcpy(lp
, aperture
->parameter
, sizeof(double) * APERTURE_PARAMETERS_MAX
);
1794 for(ip
= aperture
->amacro
->program
; ip
!= NULL
; ip
= ip
->next
) {
1795 switch(ip
->opcode
) {
1799 push(s
, ip
->data
.fval
);
1802 push(s
, lp
[ip
->data
.ival
- 1]);
1805 if (pop(s
, &tmp
[0]) < 0)
1806 GERB_FATAL_ERROR("Tried to pop an empty stack");
1807 lp
[ip
->data
.ival
- 1] = tmp
[0];
1810 if (pop(s
, &tmp
[0]) < 0)
1811 GERB_FATAL_ERROR("Tried to pop an empty stack");
1812 if (pop(s
, &tmp
[1]) < 0)
1813 GERB_FATAL_ERROR("Tried to pop an empty stack");
1814 push(s
, tmp
[1] + tmp
[0]);
1817 if (pop(s
, &tmp
[0]) < 0)
1818 GERB_FATAL_ERROR("Tried to pop an empty stack");
1819 if (pop(s
, &tmp
[1]) < 0)
1820 GERB_FATAL_ERROR("Tried to pop an empty stack");
1821 push(s
, tmp
[1] - tmp
[0]);
1824 if (pop(s
, &tmp
[0]) < 0)
1825 GERB_FATAL_ERROR("Tried to pop an empty stack");
1826 if (pop(s
, &tmp
[1]) < 0)
1827 GERB_FATAL_ERROR("Tried to pop an empty stack");
1828 push(s
, tmp
[1] * tmp
[0]);
1831 if (pop(s
, &tmp
[0]) < 0)
1832 GERB_FATAL_ERROR("Tried to pop an empty stack");
1833 if (pop(s
, &tmp
[1]) < 0)
1834 GERB_FATAL_ERROR("Tried to pop an empty stack");
1835 push(s
, tmp
[1] / tmp
[0]);
1839 * This handles the exposure thing in the aperture macro
1840 * The exposure is always the first element on stack independent
1841 * of aperture macro.
1843 switch(ip
->data
.ival
) {
1845 dprintf(" Aperture macro circle [1] (");
1846 type
= MACRO_CIRCLE
;
1852 dprintf(" Aperture macro outline [4] (");
1853 type
= MACRO_OUTLINE
;
1855 * Number of parameters are:
1856 * - number of points defined in entry 1 of the stack +
1857 * start point. Times two since it is both X and Y.
1858 * - Then three more; exposure, nuf points and rotation.
1860 nuf_parameters
= ((int)s
->stack
[1] + 1) * 2 + 3;
1863 dprintf(" Aperture macro polygon [5] (");
1864 type
= MACRO_POLYGON
;
1868 dprintf(" Aperture macro moiré [6] (");
1873 dprintf(" Aperture macro thermal [7] (");
1874 type
= MACRO_THERMAL
;
1879 dprintf(" Aperture macro line 20/2 (");
1880 type
= MACRO_LINE20
;
1884 dprintf(" Aperture macro line 21 (");
1885 type
= MACRO_LINE21
;
1889 dprintf(" Aperture macro line 22 (");
1890 type
= MACRO_LINE22
;
1897 if (type
!= APERTURE_NONE
) {
1898 if (nuf_parameters
> APERTURE_PARAMETERS_MAX
) {
1899 GERB_COMPILE_ERROR("Number of parameters to aperture macro are more than gerbv is able to store\n");
1903 * Create struct for simplified aperture macro and
1904 * start filling in the blanks.
1906 sam
= (gerb_simplified_amacro_t
*)malloc(sizeof(gerb_simplified_amacro_t
));
1908 GERB_FATAL_ERROR("Failed to malloc simplified aperture macro\n");
1911 memset(sam
->parameter
, 0,
1912 sizeof(double) * APERTURE_PARAMETERS_MAX
);
1913 memcpy(sam
->parameter
, s
->stack
,
1914 sizeof(double) * nuf_parameters
);
1916 /* convert any mm values to inches */
1919 if (fabs(sam
->parameter
[0]) < 0.001)
1920 clearOperatorUsed
= TRUE
;
1921 sam
->parameter
[1]/=scale
;
1922 sam
->parameter
[2]/=scale
;
1923 sam
->parameter
[3]/=scale
;
1926 if (fabs(sam
->parameter
[0]) < 0.001)
1927 clearOperatorUsed
= TRUE
;
1928 for (j
=2; j
<nuf_parameters
-1; j
++){
1929 sam
->parameter
[j
]/=scale
;
1933 if (fabs(sam
->parameter
[0]) < 0.001)
1934 clearOperatorUsed
= TRUE
;
1935 sam
->parameter
[2]/=scale
;
1936 sam
->parameter
[3]/=scale
;
1937 sam
->parameter
[4]/=scale
;
1940 sam
->parameter
[0]/=scale
;
1941 sam
->parameter
[1]/=scale
;
1942 sam
->parameter
[2]/=scale
;
1943 sam
->parameter
[3]/=scale
;
1944 sam
->parameter
[4]/=scale
;
1945 sam
->parameter
[6]/=scale
;
1946 sam
->parameter
[7]/=scale
;
1949 sam
->parameter
[0]/=scale
;
1950 sam
->parameter
[1]/=scale
;
1951 sam
->parameter
[2]/=scale
;
1952 sam
->parameter
[3]/=scale
;
1953 sam
->parameter
[4]/=scale
;
1956 if (fabs(sam
->parameter
[0]) < 0.001)
1957 clearOperatorUsed
= TRUE
;
1958 sam
->parameter
[1]/=scale
;
1959 sam
->parameter
[2]/=scale
;
1960 sam
->parameter
[3]/=scale
;
1961 sam
->parameter
[4]/=scale
;
1962 sam
->parameter
[5]/=scale
;
1966 if (fabs(sam
->parameter
[0]) < 0.001)
1967 clearOperatorUsed
= TRUE
;
1968 sam
->parameter
[1]/=scale
;
1969 sam
->parameter
[2]/=scale
;
1970 sam
->parameter
[3]/=scale
;
1971 sam
->parameter
[4]/=scale
;
1977 * Add this simplified aperture macro to the end of the list
1978 * of simplified aperture macros. If first entry, put it
1981 if (aperture
->simplified
== NULL
) {
1982 aperture
->simplified
= sam
;
1984 gerb_simplified_amacro_t
*tmp_sam
;
1985 tmp_sam
= aperture
->simplified
;
1986 while (tmp_sam
->next
!= NULL
) {
1987 tmp_sam
= tmp_sam
->next
;
1989 tmp_sam
->next
= sam
;
1993 for (i
= 0; i
< nuf_parameters
; i
++) {
1994 dprintf("%f, ", s
->stack
[i
]);
2001 * Here we reset the stack pointer. It's not general correct
2002 * correct to do this, but since I know how the compiler works
2003 * I can do this. The correct way to do this should be to
2004 * subtract number of used elements in each primitive operation.
2014 /* store a flag to let the renderer know if it should expect any "clear"
2016 aperture
->parameter
[0]= (gdouble
) clearOperatorUsed
;
2018 } /* simplify_aperture_macro */
2021 /* ------------------------------------------------------------------ */
2023 parse_aperture_definition(gerb_file_t
*fd
, gerb_aperture_t
*aperture
,
2024 gerb_image_t
*image
, gdouble scale
)
2029 amacro_t
*curr_amacro
;
2030 amacro_t
*amacro
= image
->amacro
;
2031 gerb_stats_t
*stats
= image
->gerb_stats
;
2034 if (gerb_fgetc(fd
) != 'D') {
2035 gerb_stats_add_error(stats
->error_list
,
2037 g_strdup_printf("Found AD code with no following 'D'.\n"),
2045 ano
= gerb_fgetint(fd
, NULL
);
2048 * Read in the whole aperture defintion and tokenize it
2050 ad
= gerb_fgetstring(fd
, '*');
2051 token
= strtok(ad
, ",");
2053 if (strlen(token
) == 1) {
2056 aperture
->type
= CIRCLE
;
2059 aperture
->type
= RECTANGLE
;
2062 aperture
->type
= OVAL
;
2065 aperture
->type
= POLYGON
;
2068 /* Here a should a T be defined, but I don't know what it represents */
2070 aperture
->type
= MACRO
;
2072 * In aperture definition, point to the aperture macro
2073 * used in the defintion
2075 curr_amacro
= amacro
;
2076 while (curr_amacro
) {
2077 if ((strlen(curr_amacro
->name
) == strlen(token
)) &&
2078 (strcmp(curr_amacro
->name
, token
) == 0)) {
2079 aperture
->amacro
= curr_amacro
;
2082 curr_amacro
= curr_amacro
->next
;
2087 * Parse all parameters
2089 for (token
= strtok(NULL
, "X"), i
= 0; token
!= NULL
;
2090 token
= strtok(NULL
, "X"), i
++) {
2091 if (i
== APERTURE_PARAMETERS_MAX
) {
2092 gerb_stats_add_error(stats
->error_list
,
2094 g_strdup_printf("Maximum number of allowed parameters exceeded in aperture %d\n", ano
),
2100 tempHolder
= strtod(token
, NULL
);
2101 /* convert any MM values to inches */
2102 /* don't scale polygon angles or side numbers, or macro parmaeters */
2103 if (!(((aperture
->type
== POLYGON
) && ((i
==1) || (i
==2)))||
2104 (aperture
->type
== MACRO
))) {
2105 tempHolder
/= scale
;
2108 aperture
->parameter
[i
] = tempHolder
;
2110 gerb_stats_add_error(stats
->error_list
,
2112 g_strdup_printf("Failed to read all parameters exceeded in aperture %d\n", ano
),
2114 aperture
->parameter
[i
] = 0.0;
2118 aperture
->nuf_parameters
= i
;
2122 if (aperture
->type
== MACRO
) {
2123 dprintf("Simplifying aperture %d using aperture macro \"%s\"\n", ano
,
2124 aperture
->amacro
->name
);
2125 simplify_aperture_macro(aperture
, scale
);
2126 dprintf("Done simplifying\n");
2132 } /* parse_aperture_definition */
2135 /* ------------------------------------------------------------------ */
2137 calc_cirseg_sq(struct gerb_net
*net
, int cw
,
2138 double delta_cp_x
, double delta_cp_y
)
2140 double d1x
, d1y
, d2x
, d2y
;
2146 * Quadrant detection (based on ccw, converted below if cw)
2152 if (net
->start_x
> net
->stop_x
)
2153 /* 1st and 2nd quadrant */
2154 if (net
->start_y
< net
->stop_y
)
2159 /* 3rd and 4th quadrant */
2160 if (net
->start_y
> net
->stop_y
)
2166 * If clockwise, rotate quadrant
2183 GERB_COMPILE_ERROR("Unknow quadrant value while converting to cw\n");
2188 * Calculate arc center point
2192 net
->cirseg
->cp_x
= net
->start_x
- delta_cp_x
;
2193 net
->cirseg
->cp_y
= net
->start_y
- delta_cp_y
;
2196 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
2197 net
->cirseg
->cp_y
= net
->start_y
- delta_cp_y
;
2200 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
2201 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
2204 net
->cirseg
->cp_x
= net
->start_x
- delta_cp_x
;
2205 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
2208 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant
);
2214 d1x
= fabs(net
->start_x
- net
->cirseg
->cp_x
);
2215 d1y
= fabs(net
->start_y
- net
->cirseg
->cp_y
);
2216 d2x
= fabs(net
->stop_x
- net
->cirseg
->cp_x
);
2217 d2y
= fabs(net
->stop_y
- net
->cirseg
->cp_y
);
2219 alfa
= atan2(d1y
, d1x
);
2220 beta
= atan2(d2y
, d2x
);
2223 * Avoid divide by zero when sin(0) = 0 and cos(90) = 0
2225 net
->cirseg
->width
= alfa
< beta
?
2226 2 * (d1x
/ cos(alfa
)) : 2 * (d2x
/ cos(beta
));
2227 net
->cirseg
->height
= alfa
> beta
?
2228 2 * (d1y
/ sin(alfa
)) : 2 * (d2y
/ sin(beta
));
2230 if (alfa
< 0.000001 && beta
< 0.000001) {
2231 net
->cirseg
->height
= 0;
2234 #define RAD2DEG(a) (a * 180 / M_PI)
2238 net
->cirseg
->angle1
= RAD2DEG(alfa
);
2239 net
->cirseg
->angle2
= RAD2DEG(beta
);
2242 net
->cirseg
->angle1
= 180.0 - RAD2DEG(alfa
);
2243 net
->cirseg
->angle2
= 180.0 - RAD2DEG(beta
);
2246 net
->cirseg
->angle1
= 180.0 + RAD2DEG(alfa
);
2247 net
->cirseg
->angle2
= 180.0 + RAD2DEG(beta
);
2250 net
->cirseg
->angle1
= 360.0 - RAD2DEG(alfa
);
2251 net
->cirseg
->angle2
= 360.0 - RAD2DEG(beta
);
2254 GERB_COMPILE_ERROR("Strange quadrant : %d\n", quadrant
);
2257 if (net
->cirseg
->width
< 0.0)
2258 GERB_COMPILE_WARNING("Negative width [%f] in quadrant %d [%f][%f]\n",
2259 net
->cirseg
->width
, quadrant
, alfa
, beta
);
2261 if (net
->cirseg
->height
< 0.0)
2262 GERB_COMPILE_WARNING("Negative height [%f] in quadrant %d [%f][%f]\n",
2263 net
->cirseg
->height
, quadrant
, RAD2DEG(alfa
), RAD2DEG(beta
));
2267 } /* calc_cirseg_sq */
2270 /* ------------------------------------------------------------------ */
2272 calc_cirseg_mq(struct gerb_net
*net
, int cw
,
2273 double delta_cp_x
, double delta_cp_y
)
2275 double d1x
, d1y
, d2x
, d2y
;
2278 net
->cirseg
->cp_x
= net
->start_x
+ delta_cp_x
;
2279 net
->cirseg
->cp_y
= net
->start_y
+ delta_cp_y
;
2284 d1x
= net
->start_x
- net
->cirseg
->cp_x
;
2285 d1y
= net
->start_y
- net
->cirseg
->cp_y
;
2286 d2x
= net
->stop_x
- net
->cirseg
->cp_x
;
2287 d2y
= net
->stop_y
- net
->cirseg
->cp_y
;
2289 alfa
= atan2(d1y
, d1x
);
2290 beta
= atan2(d2y
, d2x
);
2292 net
->cirseg
->width
= sqrt(delta_cp_x
*delta_cp_x
+ delta_cp_y
*delta_cp_y
);
2293 net
->cirseg
->width
*= 2.0;
2294 net
->cirseg
->height
= net
->cirseg
->width
;
2296 net
->cirseg
->angle1
= RAD2DEG(alfa
);
2297 net
->cirseg
->angle2
= RAD2DEG(beta
);
2300 * Make sure it's always positive angles
2302 if (net
->cirseg
->angle1
< 0.0) {
2303 net
->cirseg
->angle1
+= 360.0;
2304 net
->cirseg
->angle2
+= 360.0;
2307 if (net
->cirseg
->angle2
< 0.0)
2308 net
->cirseg
->angle2
+= 360.0;
2310 if(net
->cirseg
->angle2
== 0.0)
2311 net
->cirseg
->angle2
= 360.0;
2314 * This is a sanity check for angles after the nature of atan2.
2315 * If cw we must make sure angle1-angle2 are always positive,
2316 * If ccw we must make sure angle2-angle1 are always negative.
2317 * We should really return one angle and the difference as GTK
2318 * uses them. But what the heck, it works for me.
2321 if (net
->cirseg
->angle1
<= net
->cirseg
->angle2
)
2322 net
->cirseg
->angle2
-= 360.0;
2324 if (net
->cirseg
->angle1
>= net
->cirseg
->angle2
)
2325 net
->cirseg
->angle2
+= 360.0;
2329 } /* calc_cirseg_mq */
2333 gerber_update_any_running_knockout_measurements (gerb_image_t
*image
)
2335 if (knockoutMeasure
) {
2336 knockoutLayer
->knockout
.lowerLeftX
= knockoutLimitXmin
;
2337 knockoutLayer
->knockout
.lowerLeftY
= knockoutLimitYmin
;
2338 knockoutLayer
->knockout
.width
= knockoutLimitXmax
- knockoutLimitXmin
;
2339 knockoutLayer
->knockout
.height
= knockoutLimitYmax
- knockoutLimitYmin
;
2340 knockoutMeasure
= FALSE
;
2346 gerber_calculate_final_justify_effects(gerb_image_t
*image
)
2348 gdouble translateA
= 0.0, translateB
= 0.0;
2350 if (image
->info
->imageJustifyTypeA
!= NOJUSTIFY
) {
2351 if (image
->info
->imageJustifyTypeA
== CENTERJUSTIFY
)
2352 translateA
= (image
->info
->max_x
- image
->info
->min_x
) / 2.0;
2354 translateA
= -image
->info
->min_x
;
2356 if (image
->info
->imageJustifyTypeB
!= NOJUSTIFY
) {
2357 if (image
->info
->imageJustifyTypeB
== CENTERJUSTIFY
)
2358 translateB
= (image
->info
->max_y
- image
->info
->min_y
) / 2.0;
2360 translateB
= -image
->info
->min_y
;
2363 /* update the min/max values so the autoscale function can correctly
2364 centered a justified image */
2365 image
->info
->min_x
+= translateA
+ image
->info
->imageJustifyOffsetA
;
2366 image
->info
->max_x
+= translateA
+ image
->info
->imageJustifyOffsetA
;
2367 image
->info
->min_y
+= translateB
+ image
->info
->imageJustifyOffsetB
;
2368 image
->info
->max_y
+= translateB
+ image
->info
->imageJustifyOffsetB
;
2370 /* store the absolute offset for the justify so we can quickly offset
2371 the rendered picture during drawing */
2372 image
->info
->imageJustifyOffsetActualA
= translateA
+
2373 image
->info
->imageJustifyOffsetA
;
2374 image
->info
->imageJustifyOffsetActualB
= translateB
+
2375 image
->info
->imageJustifyOffsetB
;
2376 } /* gerber_calculate_final_justify_effects */
2380 gerber_update_min_and_max(gerb_image_info_t
*info
, gdouble repeatX
, gdouble repeatY
,
2381 gdouble x
, gdouble y
, gdouble apertureSizeX1
,
2382 gdouble apertureSizeX2
,gdouble apertureSizeY1
,
2383 gdouble apertureSizeY2
)
2385 gdouble ourX1
= x
- apertureSizeX1
, ourY1
= y
- apertureSizeY1
;
2386 gdouble ourX2
= x
+ apertureSizeX2
, ourY2
= y
+ apertureSizeY2
;
2393 #ifndef RENDER_USING_GDK
2394 /* transform the point to the final rendered position, accounting
2395 for any scaling, offsets, mirroring, etc */
2396 /* NOTE: we need to already add/subtract in the aperture size since
2397 the final rendering may be scaled */
2398 cairo_matrix_transform_point (¤tMatrix
, &ourX1
, &ourY1
);
2399 cairo_matrix_transform_point (¤tMatrix
, &ourX2
, &ourY2
);
2402 /* check both points against the min/max, since depending on the rotation,
2403 mirroring, etc, either point could possibly be a min or max */
2404 if(info
->min_x
> ourX1
)
2405 info
->min_x
= ourX1
;
2406 if(info
->min_x
> ourX2
)
2407 info
->min_x
= ourX2
;
2408 if(info
->max_x
< ourX1
)
2409 info
->max_x
= ourX1
;
2410 if(info
->max_x
< ourX2
)
2411 info
->max_x
= ourX2
;
2412 if(info
->min_y
> ourY1
)
2413 info
->min_y
= ourY1
;
2414 if(info
->min_y
> ourY2
)
2415 info
->min_y
= ourY2
;
2416 if(info
->max_y
< ourY1
)
2417 info
->max_y
= ourY1
;
2418 if(info
->max_y
< ourY2
)
2419 info
->max_y
= ourY2
;
2421 if (knockoutMeasure
) {
2422 if(knockoutLimitXmin
> ourX1
)
2423 knockoutLimitXmin
= ourX1
;
2424 if(knockoutLimitXmin
> ourX2
)
2425 knockoutLimitXmin
= ourX2
;
2426 if(knockoutLimitXmax
< ourX1
)
2427 knockoutLimitXmax
= ourX1
;
2428 if(knockoutLimitXmax
< ourX2
)
2429 knockoutLimitXmax
= ourX2
;
2430 if(knockoutLimitYmin
> ourY1
)
2431 knockoutLimitYmin
= ourY1
;
2432 if(knockoutLimitYmin
> ourY2
)
2433 knockoutLimitYmin
= ourY2
;
2434 if(knockoutLimitYmax
< ourY1
)
2435 knockoutLimitYmax
= ourY1
;
2436 if(knockoutLimitYmax
< ourY2
)
2437 knockoutLimitYmax
= ourY2
;
2439 } /* gerber_update_min_and_max */