27 #include "pcb-printf.h"
30 #include "../hidint.h"
31 #include "hid/common/hidnogui.h"
32 #include "hid/common/draw_helpers.h"
33 #include "hid/common/hidinit.h"
35 #ifdef HAVE_LIBDMALLOC
39 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented Gerber function %s.\n", __FUNCTION__); abort()
41 /*----------------------------------------------------------------------------*/
42 /* Function prototypes */
43 /*----------------------------------------------------------------------------*/
45 static HID_Attribute
* gerber_get_export_options (int *n
);
46 static void gerber_do_export (HID_Attr_Val
* options
);
47 static void gerber_parse_arguments (int *argc
, char ***argv
);
48 static int gerber_set_layer (const char *name
, int group
, int empty
);
49 static hidGC
gerber_make_gc (void);
50 static void gerber_destroy_gc (hidGC gc
);
51 static void gerber_use_mask (enum mask_mode mode
);
52 static void gerber_set_color (hidGC gc
, const char *name
);
53 static void gerber_set_line_cap (hidGC gc
, EndCapStyle style
);
54 static void gerber_set_line_width (hidGC gc
, Coord width
);
55 static void gerber_set_draw_xor (hidGC gc
, int _xor
);
56 static void gerber_draw_line (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
);
57 static void gerber_draw_arc (hidGC gc
, Coord cx
, Coord cy
, Coord width
, Coord height
, Angle start_angle
, Angle delta_angle
);
58 static void gerber_draw_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
);
59 static void gerber_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
);
60 static void gerber_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
);
61 static void gerber_calibrate (double xval
, double yval
);
62 static void gerber_set_crosshair (int x
, int y
, int action
);
63 static void gerber_fill_polygon (hidGC gc
, int n_coords
, Coord
*x
, Coord
*y
);
65 /*----------------------------------------------------------------------------*/
66 /* Utility routines */
67 /*----------------------------------------------------------------------------*/
69 /* These are for films */
70 #define gerberX(pcb, x) ((Coord) (x))
71 #define gerberY(pcb, y) ((Coord) ((pcb)->MaxHeight - (y)))
72 #define gerberXOffset(pcb, x) ((Coord) (x))
73 #define gerberYOffset(pcb, y) ((Coord) (-(y)))
75 /* These are for drills (printed as mils but are really 1/10th mil) */
76 #define gerberDrX(pcb, x) ((Coord) (x))
77 #define gerberDrY(pcb, y) ((Coord) ((pcb)->MaxHeight - (y)))
79 /*----------------------------------------------------------------------------*/
80 /* Private data structures */
81 /*----------------------------------------------------------------------------*/
84 static int all_layers
;
86 static char *x_convspec
, *y_convspec
;
87 static int is_mask
, was_drill
;
89 static enum mask_mode current_mask
;
90 static int flash_drills
;
91 static int copy_outline_mode
;
92 static int name_style
;
93 static LayerType
*outline_layer
;
95 #define print_xcoord(file, pcb, val)\
96 pcb_fprintf(file, x_convspec, gerberX(pcb, val))
98 #define print_ycoord(file, pcb, val)\
99 pcb_fprintf(file, y_convspec, gerberY(pcb, val))
103 ROUND
, /* Shaped like a circle */
104 OCTAGON
, /* octagonal shape */
105 SQUARE
, /* Shaped like a square */
106 ROUNDCLEAR
, /* clearance in negatives */
108 THERMAL
/* negative thermal relief */
110 typedef enum ApertureShape ApertureShape
;
112 /* This is added to the global aperture array indexes to get gerber
113 dcode and macro numbers. */
114 #define DCODE_BASE 11
116 typedef struct aperture
118 int dCode
; /* The RS-274X D code */
119 Coord width
; /* Size in pcb units */
120 ApertureShape shape
; /* ROUND/SQUARE etc */
121 struct aperture
*next
;
131 static ApertureList
*layer_aptr_list
;
132 static ApertureList
*curr_aptr_list
;
133 static int layer_list_max
;
134 static int layer_list_idx
;
142 PendingDrills
*pending_drills
= NULL
;
143 int n_pending_drills
= 0, max_pending_drills
= 0;
145 /*----------------------------------------------------------------------------*/
146 /* Defined Constants */
147 /*----------------------------------------------------------------------------*/
148 #define AUTO_OUTLINE_WIDTH MIL_TO_COORD(8) /* Auto-geneated outline width of 8 mils */
150 /*----------------------------------------------------------------------------*/
151 /* Aperture Routines */
152 /*----------------------------------------------------------------------------*/
154 /* Initialize aperture list */
156 initApertureList (ApertureList
*list
)
163 deinitApertureList (ApertureList
*list
)
165 Aperture
*search
= list
->data
;
173 initApertureList (list
);
176 static void resetApertures()
179 for (i
= 0; i
< layer_list_max
; ++i
)
180 deinitApertureList (&layer_aptr_list
[i
]);
181 free (layer_aptr_list
);
182 layer_aptr_list
= NULL
;
183 curr_aptr_list
= NULL
;
188 /* Create and add a new aperture to the list */
190 addAperture (ApertureList
*list
, Coord width
, ApertureShape shape
)
192 static int aperture_count
;
194 Aperture
*app
= (Aperture
*) malloc (sizeof *app
);
200 app
->dCode
= DCODE_BASE
+ aperture_count
++;
201 app
->next
= list
->data
;
209 /* Fetch an aperture from the list with the specified
210 * width/shape, creating a new one if none exists */
212 findAperture (ApertureList
*list
, Coord width
, ApertureShape shape
)
216 /* we never draw zero-width lines */
220 /* Search for an appropriate aperture. */
221 for (search
= list
->data
; search
; search
= search
->next
)
222 if (search
->width
== width
&& search
->shape
== shape
)
225 /* Failing that, create a new one */
226 return addAperture (list
, width
, shape
);
229 /* Output aperture data to the file */
231 fprintAperture (FILE *f
, Aperture
*aptr
)
236 pcb_fprintf (f
, metric
? "%%ADD%dC,%.3`mm*%%\r\n" : "%%ADD%dC,%.4`mi*%%\r\n", aptr
->dCode
, aptr
->width
);
239 pcb_fprintf (f
, metric
? "%%ADD%dR,%.3`mmX%.3`mm*%%\r\n" : "%%ADD%dR,%.4`miX%.4`mi*%%\r\n", aptr
->dCode
, aptr
->width
, aptr
->width
);
242 pcb_fprintf (f
, metric
? "%%AMOCT%d*5,0,8,0,0,%.3`mm,22.5*%%\r\n"
243 "%%ADD%dOCT%d*%%\r\n" : "%%AMOCT%d*5,0,8,0,0,%.3`mm,22.5*%%\r\n"
244 "%%ADD%dOCT%d*%%\r\n", aptr
->dCode
,
245 (Coord
) ((double) aptr
->width
/ COS_22_5_DEGREE
), aptr
->dCode
,
250 fprintf (f
, "%%AMTHERM%d*7,0,0,%.4f,%.4f,%.4f,45*%%\r\n"
251 "%%ADD%dTHERM%d*%%\r\n", dCode
, gap
/ 100000.0,
252 width
/ 100000.0, finger
/ 100000.0, dCode
, dCode
);
255 fprintf (f
, "%%ADD%dC,%.4fX%.4f*%%\r\n",
256 dCode
, gap
/ 100000.0, width
/ 100000.0);
259 fprintf (f
, "%%ADD%dR,%.4fX%.4fX%.4fX%.4f*%%\r\n",
260 dCode
, gap
/ 100000.0, gap
/ 100000.0,
261 width
/ 100000.0, width
/ 100000.0);
270 /* Set the aperture list for the current layer,
271 * expanding the list buffer if needed */
272 static ApertureList
*
273 setLayerApertureList (int layer_idx
)
275 if (layer_idx
>= layer_list_max
)
277 int i
= layer_list_max
;
278 layer_list_max
= 2 * (layer_idx
+ 1);
279 layer_aptr_list
= (ApertureList
*)
280 realloc (layer_aptr_list
, layer_list_max
* sizeof (*layer_aptr_list
));
281 for (; i
< layer_list_max
; ++i
)
282 initApertureList (&layer_aptr_list
[i
]);
284 curr_aptr_list
= &layer_aptr_list
[layer_idx
];
285 return curr_aptr_list
;
288 /* --------------------------------------------------------------------------- */
290 static HID gerber_hid
;
291 static HID_DRAW_API gerber_graphics
;
293 typedef struct hid_gc_struct
302 static FILE *f
= NULL
;
303 static char *filename
= NULL
;
304 static char *filesuff
= NULL
;
305 static char *layername
= NULL
;
306 static int lncount
= 0;
308 static int finding_apertures
= 0;
309 static int pagecount
= 0;
310 static int linewidth
= -1;
311 static int lastgroup
= -1;
312 static int lastcap
= -1;
313 static int print_group
[MAX_LAYER
];
314 static int print_layer
[MAX_LAYER
];
315 static int lastX
, lastY
; /* the last X and Y coordinate */
317 static const char *copy_outline_names
[] = {
318 #define COPY_OUTLINE_NONE 0
320 #define COPY_OUTLINE_MASK 1
322 #define COPY_OUTLINE_SILK 2
324 #define COPY_OUTLINE_ALL 3
329 static const char *name_style_names
[] = {
330 #define NAME_STYLE_FIXED 0
332 #define NAME_STYLE_SINGLE 1
334 #define NAME_STYLE_FIRST 2
336 #define NAME_STYLE_EAGLE 3
341 static HID_Attribute gerber_options
[] = {
343 /* %start-doc options "90 Gerber Export"
345 @item --gerberfile <string>
346 Gerber output file prefix. Can include a path.
350 {"gerberfile", "Gerber output file base",
351 HID_String
, 0, 0, {0, 0, 0}, 0, 0},
352 #define HA_gerberfile 0
354 /* %start-doc options "90 Gerber Export"
357 Output contains all layers, even empty ones.
361 {"all-layers", "Output all layers, even empty ones",
362 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
363 #define HA_all_layers 1
365 /* %start-doc options "90 Gerber Export"
368 Print file names and aperture counts on stdout.
372 {"verbose", "Print file names and aperture counts on stdout",
373 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
375 /* %start-doc options "90 Gerber Export"
378 generate metric Gerber and drill files
382 {"metric", "Generate metric Gerber and drill files",
383 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
385 {"copy-outline", "Copy outline onto other layers",
386 HID_Enum
, 0, 0, {0, 0, 0}, copy_outline_names
, 0},
387 #define HA_copy_outline 4
388 {"name-style", "Naming style for individual gerber files",
389 HID_Enum
, 0, 0, {0, 0, 0}, name_style_names
, 0},
390 #define HA_name_style 5
393 #define NUM_OPTIONS (sizeof(gerber_options)/sizeof(gerber_options[0]))
395 static HID_Attr_Val gerber_values
[NUM_OPTIONS
];
397 static HID_Attribute
*
398 gerber_get_export_options (int *n
)
400 static char *last_made_filename
= NULL
;
401 if (PCB
) derive_default_filename(PCB
->Filename
, &gerber_options
[HA_gerberfile
], "", &last_made_filename
);
405 return gerber_options
;
409 group_for_layer (int l
)
411 if (l
< max_copper_layer
+ 2 && l
>= 0)
412 return GetLayerGroupNumberByNumber (l
);
413 /* else something unique */
414 return max_group
+ 3 + l
;
418 layer_sort (const void *va
, const void *vb
)
422 int d
= group_for_layer (b
) - group_for_layer (a
);
429 maybe_close_f (FILE *f
)
434 fprintf (f
, "M30\r\n");
436 fprintf (f
, "M02*\r\n");
441 static BoxType region
;
443 /* Very similar to layer_type_to_file_name() but appends only a
444 three-character suffix compatible with Eagle's defaults. */
446 assign_eagle_file_suffix (char *dest
, int idx
)
454 case SL (SILK
, TOP
): suff
= "plc"; break;
455 case SL (SILK
, BOTTOM
): suff
= "pls"; break;
456 case SL (MASK
, TOP
): suff
= "stc"; break;
457 case SL (MASK
, BOTTOM
): suff
= "sts"; break;
458 case SL (PDRILL
, 0): suff
= "drd"; break;
459 case SL (UDRILL
, 0): suff
= "dru"; break;
460 case SL (PASTE
, TOP
): suff
= "crc"; break;
461 case SL (PASTE
, BOTTOM
): suff
= "crs"; break;
462 case SL (INVISIBLE
, 0): suff
= "inv"; break;
463 case SL (FAB
, 0): suff
= "fab"; break;
464 case SL (ASSY
, TOP
): suff
= "ast"; break;
465 case SL (ASSY
, BOTTOM
): suff
= "asb"; break;
468 group
= GetLayerGroupNumberByNumber(idx
);
469 nlayers
= PCB
->LayerGroups
.Number
[group
];
470 if (group
== GetLayerGroupNumberByNumber(component_silk_layer
))
474 else if (group
== GetLayerGroupNumberByNumber(solder_silk_layer
))
478 else if (nlayers
== 1
479 && (strcmp (PCB
->Data
->Layer
[idx
].Name
, "route") == 0 ||
480 strcmp (PCB
->Data
->Layer
[idx
].Name
, "outline") == 0))
487 sprintf (buf
, "ly%d", group
);
497 assign_file_suffix (char *dest
, int idx
)
500 const char *sext
= ".gbr";
505 case NAME_STYLE_FIXED
: fns_style
= FNS_fixed
; break;
506 case NAME_STYLE_SINGLE
: fns_style
= FNS_single
; break;
507 case NAME_STYLE_FIRST
: fns_style
= FNS_first
; break;
508 case NAME_STYLE_EAGLE
:
509 assign_eagle_file_suffix (dest
, idx
);
523 strcpy (dest
, layer_type_to_file_name (idx
, fns_style
));
528 gerber_do_export (HID_Attr_Val
* options
)
532 static int saved_layer_stack
[MAX_LAYER
];
533 int save_ons
[MAX_LAYER
+ 2];
534 FlagType save_thindraw
;
536 save_thindraw
= PCB
->Flags
;
537 CLEAR_FLAG(THINDRAWFLAG
, PCB
);
538 CLEAR_FLAG(THINDRAWPOLYFLAG
, PCB
);
539 CLEAR_FLAG(CHECKPLANESFLAG
, PCB
);
543 gerber_get_export_options (NULL
);
544 for (i
= 0; i
< NUM_OPTIONS
; i
++)
545 gerber_values
[i
] = gerber_options
[i
].default_val
;
546 options
= gerber_values
;
549 fnbase
= options
[HA_gerberfile
].str_value
;
553 verbose
= options
[HA_verbose
].int_value
;
554 metric
= options
[HA_metric
].int_value
;
556 x_convspec
= "X%.0mu";
557 y_convspec
= "Y%.0mu";
559 x_convspec
= "X%.0mc";
560 y_convspec
= "Y%.0mc";
562 all_layers
= options
[HA_all_layers
].int_value
;
564 copy_outline_mode
= options
[HA_copy_outline
].int_value
;
565 name_style
= options
[HA_name_style
].int_value
;
567 outline_layer
= NULL
;
569 for (i
= 0; i
< max_copper_layer
; i
++)
571 LayerType
*layer
= PCB
->Data
->Layer
+ i
;
572 if (strcmp (layer
->Name
, "outline") == 0 ||
573 strcmp (layer
->Name
, "route") == 0)
575 outline_layer
= layer
;
580 filename
= (char *)realloc (filename
, i
+ 40);
581 strcpy (filename
, fnbase
);
582 strcat (filename
, ".");
583 filesuff
= filename
+ strlen (filename
);
587 memset (print_group
, 1, sizeof (print_group
));
588 memset (print_layer
, 1, sizeof (print_layer
));
592 memset (print_group
, 0, sizeof (print_group
));
593 memset (print_layer
, 0, sizeof (print_layer
));
596 hid_save_and_show_layer_ons (save_ons
);
597 for (i
= 0; i
< max_copper_layer
; i
++)
599 LayerType
*layer
= PCB
->Data
->Layer
+ i
;
600 if (layer
->LineN
|| layer
->TextN
|| layer
->ArcN
|| layer
->PolygonN
)
601 print_group
[GetLayerGroupNumberByNumber (i
)] = 1;
603 print_group
[GetLayerGroupNumberByNumber (solder_silk_layer
)] = 1;
604 print_group
[GetLayerGroupNumberByNumber (component_silk_layer
)] = 1;
605 for (i
= 0; i
< max_copper_layer
; i
++)
606 if (print_group
[GetLayerGroupNumberByNumber (i
)])
609 memcpy (saved_layer_stack
, LayerStack
, sizeof (LayerStack
));
610 qsort (LayerStack
, max_copper_layer
, sizeof (LayerStack
[0]), layer_sort
);
617 region
.X2
= PCB
->MaxWidth
;
618 region
.Y2
= PCB
->MaxHeight
;
625 finding_apertures
= 1;
626 hid_expose_callback (&gerber_hid
, ®ion
, 0);
629 finding_apertures
= 0;
630 hid_expose_callback (&gerber_hid
, ®ion
, 0);
632 memcpy (LayerStack
, saved_layer_stack
, sizeof (LayerStack
));
636 hid_restore_layer_ons (save_ons
);
637 PCB
->Flags
= save_thindraw
;
641 gerber_parse_arguments (int *argc
, char ***argv
)
643 hid_register_attributes (gerber_options
, NUM_OPTIONS
);
644 hid_parse_command_line (argc
, argv
);
648 drill_sort (const void *va
, const void *vb
)
650 PendingDrills
*a
= (PendingDrills
*) va
;
651 PendingDrills
*b
= (PendingDrills
*) vb
;
652 if (a
->diam
!= b
->diam
)
653 return a
->diam
- b
->diam
;
660 gerber_set_layer (const char *name
, int group
, int empty
)
664 int idx
= (group
>= 0
666 max_group
) ? PCB
->LayerGroups
.Entries
[group
][0] : group
;
669 name
= PCB
->Data
->Layer
[idx
].Name
;
671 if (idx
>= 0 && idx
< max_copper_layer
&& !print_layer
[idx
])
674 if (strcmp (name
, "invisible") == 0)
676 if (SL_TYPE (idx
) == SL_ASSY
)
680 if (strcmp (name
, "outline") == 0 ||
681 strcmp (name
, "route") == 0)
684 if (is_drill
&& n_pending_drills
)
687 /* dump pending drills in sequence */
688 qsort (pending_drills
, n_pending_drills
, sizeof (pending_drills
[0]),
690 for (i
= 0; i
< n_pending_drills
; i
++)
692 if (i
== 0 || pending_drills
[i
].diam
!= pending_drills
[i
- 1].diam
)
694 Aperture
*ap
= findAperture (curr_aptr_list
, pending_drills
[i
].diam
, ROUND
);
695 fprintf (f
, "T%02d\r\n", ap
->dCode
);
697 /* Notice the last zeroes are literal zeroes here, a x10 scale factor. *
699 pcb_fprintf (f
, metric
? "X%06.0muY%06.0mu\r\n" : "X%06.0ml0Y%06.0ml0\r\n",
700 gerberDrX (PCB
, pending_drills
[i
].x
),
701 gerberDrY (PCB
, pending_drills
[i
].y
));
703 free (pending_drills
);
704 n_pending_drills
= max_pending_drills
= 0;
705 pending_drills
= NULL
;
708 is_drill
= (SL_TYPE (idx
) == SL_PDRILL
|| SL_TYPE (idx
) == SL_UDRILL
);
709 is_mask
= (SL_TYPE (idx
) == SL_MASK
);
710 current_mask
= HID_MASK_OFF
;
712 printf ("Layer %s group %d drill %d mask %d\n", name
, group
, is_drill
,
716 if (group
< 0 || group
!= lastgroup
)
721 struct passwd
*pwentry
;
723 ApertureList
*aptr_list
;
732 aptr_list
= setLayerApertureList (layer_list_idx
++);
734 if (finding_apertures
)
737 if (aptr_list
->count
== 0 && !all_layers
)
744 assign_file_suffix (filesuff
, idx
);
745 f
= fopen (filename
, "wb"); /* Binary needed to force CR-LF */
748 Message ( "Error: Could not open %s for writing.\n", filename
);
752 was_drill
= is_drill
;
756 int c
= aptr_list
->count
;
757 printf ("Gerber: %d aperture%s in %s\n", c
,
758 c
== 1 ? "" : "s", filename
);
763 /* We omit the ,TZ here because we are not omitting trailing zeros. Our format is
764 always six-digit 0.1 mil or µm resolution (i.e. 001100 = 0.11" or 1.1mm)*/
765 fprintf (f
, "M48\r\n");
766 fprintf (f
, metric
? "METRIC,000.000\r\n" : "INCH\r\n");
767 for (search
= aptr_list
->data
; search
; search
= search
->next
)
768 pcb_fprintf (f
, metric
? "T%02dC%.3`mm\r\n" : "T%02dC%.3`mi\r\n", search
->dCode
, search
->width
);
769 fprintf (f
, "%%\r\n");
774 fprintf (f
, "G04 start of page %d for group %d idx %d *\r\n",
775 pagecount
, group
, idx
);
777 /* Create a portable timestamp. */
778 currenttime
= time (NULL
);
780 /* avoid gcc complaints */
781 const char *fmt
= "%c UTC";
782 strftime (utcTime
, sizeof utcTime
, fmt
, gmtime (¤ttime
));
784 /* Print a cute file header at the beginning of each file. */
785 fprintf (f
, "G04 Title: %s, %s *\r\n", UNKNOWN (PCB
->Name
),
787 fprintf (f
, "G04 Creator: %s " VERSION
" *\r\n", Progname
);
788 fprintf (f
, "G04 CreationDate: %s *\r\n", utcTime
);
792 pwentry
= getpwuid (getuid ());
793 fprintf (f
, "G04 For: %s *\r\n", pwentry
->pw_name
);
796 fprintf (f
, "G04 Format: Gerber/RS-274X *\r\n");
797 pcb_fprintf (f
, metric
? "G04 PCB-Dimensions (mm): %.2mm %.2mm *\r\n" :
798 "G04 PCB-Dimensions (mil): %.2ml %.2ml *\r\n",
799 PCB
->MaxWidth
, PCB
->MaxHeight
);
800 fprintf (f
, "G04 PCB-Coordinate-Origin: lower left *\r\n");
802 /* Signal data in inches. */
803 fprintf (f
, metric
? "%%MOMM*%%\r\n" : "%%MOIN*%%\r\n");
805 /* Signal Leading zero suppression, Absolute Data, 2.5 format in inch, 4.3 in mm */
806 fprintf (f
, metric
? "%%FSLAX43Y43*%%\r\n" : "%%FSLAX25Y25*%%\r\n");
808 /* build a legal identifier. */
811 layername
= strdup (filesuff
);
812 if (strrchr (layername
, '.'))
813 * strrchr (layername
, '.') = 0;
815 for (cp
=layername
; *cp
; cp
++)
817 if (isalnum((int) *cp
))
818 *cp
= toupper((int) *cp
);
822 fprintf (f
, "%%LN%s*%%\r\n", layername
);
825 for (search
= aptr_list
->data
; search
; search
= search
->next
)
826 fprintAperture(f
, search
);
827 if (aptr_list
->count
== 0)
828 /* We need to put *something* in the file to make it be parsed
829 as RS-274X instead of RS-274D. */
830 fprintf (f
, "%%ADD11C,0.0100*%%\r\n");
834 /* If we're printing a copper layer other than the outline layer,
835 and we want to "print outlines", and we have an outline layer,
836 print the outline layer on this layer also. */
838 if (copy_outline_mode
== COPY_OUTLINE_MASK
839 && SL_TYPE (idx
) == SL_MASK
)
841 if (copy_outline_mode
== COPY_OUTLINE_SILK
842 && SL_TYPE (idx
) == SL_SILK
)
844 if (copy_outline_mode
== COPY_OUTLINE_ALL
845 && (SL_TYPE (idx
) == SL_SILK
846 || SL_TYPE (idx
) == SL_MASK
847 || SL_TYPE (idx
) == SL_FAB
848 || SL_TYPE (idx
) == SL_ASSY
849 || SL_TYPE (idx
) == 0))
853 && strcmp (name
, "outline")
854 && strcmp (name
, "route"))
857 && outline_layer
!= PCB
->Data
->Layer
+idx
)
858 DrawLayer (outline_layer
, ®ion
);
859 else if (!outline_layer
)
861 hidGC gc
= gui
->graphics
->make_gc ();
862 printf("name %s idx %d\n", name
, idx
);
863 if (SL_TYPE (idx
) == SL_SILK
)
864 gui
->graphics
->set_line_width (gc
, PCB
->minSlk
);
866 gui
->graphics
->set_line_width (gc
, PCB
->minWid
);
868 gui
->graphics
->set_line_width (gc
, AUTO_OUTLINE_WIDTH
);
869 gui
->graphics
->draw_line (gc
, 0, 0, PCB
->MaxWidth
, 0);
870 gui
->graphics
->draw_line (gc
, 0, 0, 0, PCB
->MaxHeight
);
871 gui
->graphics
->draw_line (gc
, PCB
->MaxWidth
, 0, PCB
->MaxWidth
, PCB
->MaxHeight
);
872 gui
->graphics
->draw_line (gc
, 0, PCB
->MaxHeight
, PCB
->MaxWidth
, PCB
->MaxHeight
);
873 gui
->graphics
->destroy_gc (gc
);
881 gerber_make_gc (void)
883 hidGC rv
= (hidGC
) calloc (1, sizeof (*rv
));
889 gerber_destroy_gc (hidGC gc
)
895 gerber_use_mask (enum mask_mode mode
)
901 gerber_set_color (hidGC gc
, const char *name
)
903 if (strcmp (name
, "erase") == 0)
909 else if (strcmp (name
, "drill") == 0)
924 gerber_set_line_cap (hidGC gc
, EndCapStyle style
)
930 gerber_set_line_width (hidGC gc
, Coord width
)
936 gerber_set_draw_xor (hidGC gc
, int xor_
)
942 use_gc (hidGC gc
, int radius
)
947 if (radius
!= linewidth
|| lastcap
!= Round_Cap
)
949 Aperture
*aptr
= findAperture (curr_aptr_list
, radius
, ROUND
);
951 pcb_fprintf (stderr
, "error: aperture for radius %$mS type ROUND is null\n", radius
);
952 else if (f
&& !is_drill
)
953 fprintf (f
, "G54D%d*", aptr
->dCode
);
958 else if (linewidth
!= gc
->width
|| lastcap
!= gc
->cap
)
963 linewidth
= gc
->width
;
976 aptr
= findAperture (curr_aptr_list
, linewidth
, shape
);
978 pcb_fprintf (stderr
, "error: aperture for width %$mS type %s is null\n",
979 linewidth
, shape
== ROUND
? "ROUND" : "SQUARE");
981 fprintf (f
, "G54D%d*", aptr
->dCode
);
986 gerber_draw_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
988 gerber_draw_line (gc
, x1
, y1
, x1
, y2
);
989 gerber_draw_line (gc
, x1
, y1
, x2
, y1
);
990 gerber_draw_line (gc
, x1
, y2
, x2
, y2
);
991 gerber_draw_line (gc
, x2
, y1
, x2
, y2
);
995 gerber_draw_line (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
999 if (x1
!= x2
&& y1
!= y2
&& gc
->cap
== Square_Cap
)
1002 double tx
, ty
, theta
;
1004 theta
= atan2 (y2
-y1
, x2
-x1
);
1006 /* T is a vector half a thickness long, in the direction of
1007 one of the corners. */
1008 tx
= gc
->width
/ 2.0 * cos (theta
+ M_PI
/4) * sqrt(2.0);
1009 ty
= gc
->width
/ 2.0 * sin (theta
+ M_PI
/4) * sqrt(2.0);
1011 x
[0] = x1
- tx
; y
[0] = y1
- ty
;
1012 x
[1] = x2
+ ty
; y
[1] = y2
- tx
;
1013 x
[2] = x2
+ tx
; y
[2] = y2
+ ty
;
1014 x
[3] = x1
- ty
; y
[3] = y1
+ tx
;
1016 x
[4] = x
[0]; y
[4] = y
[0];
1017 gerber_fill_polygon (gc
, 5, x
, y
);
1029 print_xcoord (f
, PCB
, lastX
);
1035 print_ycoord (f
, PCB
, lastY
);
1037 if ((x1
== x2
) && (y1
== y2
))
1038 fprintf (f
, "D03*\r\n");
1042 fprintf (f
, "D02*");
1046 print_xcoord (f
, PCB
, lastX
);
1051 print_ycoord (f
, PCB
, lastY
);
1053 fprintf (f
, "D01*\r\n");
1059 gerber_draw_arc (hidGC gc
, Coord cx
, Coord cy
, Coord width
, Coord height
,
1060 Angle start_angle
, Angle delta_angle
)
1063 double arcStartX
, arcStopX
, arcStartY
, arcStopY
;
1065 /* we never draw zero-width lines */
1073 arcStartX
= cx
- width
* cos (TO_RADIANS (start_angle
));
1074 arcStartY
= cy
+ height
* sin (TO_RADIANS (start_angle
));
1076 /* I checked three different gerber viewers, and they all disagreed
1077 on how ellipses should be drawn. The spec just calls G74/G75
1078 "circular interpolation" so there's a chance it just doesn't
1079 support ellipses at all. Thus, we draw them out with line
1080 segments. Note that most arcs in pcb are circles anyway. */
1081 if (width
!= height
)
1084 Coord max
= width
> height
? width
: height
;
1085 Coord minr
= max
- gc
->width
/ 10;
1087 Coord x0
, y0
, x1
, y1
;
1091 step
= acos((double)minr
/(double)max
) * 180.0/M_PI
;
1094 nsteps
= abs(delta_angle
) / step
+ 1;
1095 step
= (double)delta_angle
/ nsteps
;
1099 angle
= start_angle
;
1103 x1
= cx
- width
* cos (TO_RADIANS (angle
+step
));
1104 y1
= cy
+ height
* sin (TO_RADIANS (angle
+step
));
1105 gerber_draw_line (gc
, x0
, y0
, x1
, y1
);
1113 arcStopX
= cx
- width
* cos (TO_RADIANS (start_angle
+ delta_angle
));
1114 arcStopY
= cy
+ height
* sin (TO_RADIANS (start_angle
+ delta_angle
));
1115 if (arcStartX
!= lastX
)
1119 print_xcoord (f
, PCB
, lastX
);
1121 if (arcStartY
!= lastY
)
1125 print_ycoord (f
, PCB
, lastY
);
1128 fprintf (f
, "D02*");
1130 metric
? "G75*G0%1dX%.0muY%.0muI%.0muJ%.0muD01*G01*\r\n" :
1131 "G75*G0%1dX%.0mcY%.0mcI%.0mcJ%.0mcD01*G01*\r\n",
1132 (delta_angle
< 0) ? 2 : 3,
1133 gerberX (PCB
, arcStopX
), gerberY (PCB
, arcStopY
),
1134 gerberXOffset (PCB
, cx
- arcStartX
),
1135 gerberYOffset (PCB
, cy
- arcStartY
));
1141 gerber_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
)
1146 radius
= 50 * round (radius
/ 50.0);
1147 use_gc (gc
, radius
);
1152 if (n_pending_drills
>= max_pending_drills
)
1154 max_pending_drills
+= 100;
1155 pending_drills
= (PendingDrills
*) realloc(pending_drills
,
1156 max_pending_drills
*
1157 sizeof (pending_drills
[0]));
1159 pending_drills
[n_pending_drills
].x
= cx
;
1160 pending_drills
[n_pending_drills
].y
= cy
;
1161 pending_drills
[n_pending_drills
].diam
= radius
* 2;
1165 else if (gc
->drill
&& !flash_drills
)
1170 print_xcoord (f
, PCB
, lastX
);
1175 print_ycoord (f
, PCB
, lastY
);
1177 fprintf (f
, "D03*\r\n");
1181 gerber_fill_polygon (hidGC gc
, int n_coords
, Coord
*x
, Coord
*y
)
1186 Coord startX
= 0, startY
= 0;
1188 if (is_mask
&& current_mask
== HID_MASK_BEFORE
)
1191 use_gc (gc
, 10 * 100);
1194 fprintf (f
, "G36*\r\n");
1195 for (i
= 0; i
< n_coords
; i
++)
1201 print_xcoord (f
, PCB
, lastX
);
1207 print_ycoord (f
, PCB
, lastY
);
1215 fprintf (f
, "D02*");
1218 fprintf (f
, "D01*\r\n");
1221 if (startX
!= lastX
)
1225 print_xcoord (f
, PCB
, startX
);
1227 if (startY
!= lastY
)
1231 print_ycoord (f
, PCB
, lastY
);
1234 fprintf (f
, "D01*\r\n");
1235 fprintf (f
, "G37*\r\n");
1239 gerber_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
1251 gerber_fill_polygon (gc
, 5, x
, y
);
1255 gerber_calibrate (double xval
, double yval
)
1261 gerber_set_crosshair (int x
, int y
, int action
)
1268 memset (&gerber_hid
, 0, sizeof (gerber_hid
));
1269 memset (&gerber_graphics
, 0, sizeof (gerber_graphics
));
1271 common_nogui_init (&gerber_hid
);
1272 common_draw_helpers_init (&gerber_hid
);
1274 gerber_hid
.struct_size
= sizeof (gerber_hid
);
1275 gerber_hid
.name
= "gerber";
1276 gerber_hid
.description
= "RS-274X (Gerber) export";
1277 gerber_hid
.exporter
= 1;
1279 gerber_hid
.get_export_options
= gerber_get_export_options
;
1280 gerber_hid
.do_export
= gerber_do_export
;
1281 gerber_hid
.parse_arguments
= gerber_parse_arguments
;
1282 gerber_hid
.set_layer
= gerber_set_layer
;
1283 gerber_hid
.calibrate
= gerber_calibrate
;
1284 gerber_hid
.set_crosshair
= gerber_set_crosshair
;
1286 gerber_hid
.graphics
= &gerber_graphics
;
1288 gerber_graphics
.make_gc
= gerber_make_gc
;
1289 gerber_graphics
.destroy_gc
= gerber_destroy_gc
;
1290 gerber_graphics
.use_mask
= gerber_use_mask
;
1291 gerber_graphics
.set_color
= gerber_set_color
;
1292 gerber_graphics
.set_line_cap
= gerber_set_line_cap
;
1293 gerber_graphics
.set_line_width
= gerber_set_line_width
;
1294 gerber_graphics
.set_draw_xor
= gerber_set_draw_xor
;
1295 gerber_graphics
.draw_line
= gerber_draw_line
;
1296 gerber_graphics
.draw_arc
= gerber_draw_arc
;
1297 gerber_graphics
.draw_rect
= gerber_draw_rect
;
1298 gerber_graphics
.fill_circle
= gerber_fill_circle
;
1299 gerber_graphics
.fill_polygon
= gerber_fill_polygon
;
1300 gerber_graphics
.fill_rect
= gerber_fill_rect
;
1302 hid_register_hid (&gerber_hid
);