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
;
292 typedef struct hid_gc_struct
301 static FILE *f
= NULL
;
302 static char *filename
= NULL
;
303 static char *filesuff
= NULL
;
304 static char *layername
= NULL
;
305 static int lncount
= 0;
307 static int finding_apertures
= 0;
308 static int pagecount
= 0;
309 static int linewidth
= -1;
310 static int lastgroup
= -1;
311 static int lastcap
= -1;
312 static int print_group
[MAX_LAYER
];
313 static int print_layer
[MAX_LAYER
];
314 static int lastX
, lastY
; /* the last X and Y coordinate */
316 static const char *copy_outline_names
[] = {
317 #define COPY_OUTLINE_NONE 0
319 #define COPY_OUTLINE_MASK 1
321 #define COPY_OUTLINE_SILK 2
323 #define COPY_OUTLINE_ALL 3
328 static const char *name_style_names
[] = {
329 #define NAME_STYLE_FIXED 0
331 #define NAME_STYLE_SINGLE 1
333 #define NAME_STYLE_FIRST 2
335 #define NAME_STYLE_EAGLE 3
340 static HID_Attribute gerber_options
[] = {
342 /* %start-doc options "90 Gerber Export"
344 @item --gerberfile <string>
345 Gerber output file prefix. Can include a path.
349 {"gerberfile", "Gerber output file base",
350 HID_String
, 0, 0, {0, 0, 0}, 0, 0},
351 #define HA_gerberfile 0
353 /* %start-doc options "90 Gerber Export"
356 Output contains all layers, even empty ones.
360 {"all-layers", "Output all layers, even empty ones",
361 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
362 #define HA_all_layers 1
364 /* %start-doc options "90 Gerber Export"
367 Print file names and aperture counts on stdout.
371 {"verbose", "Print file names and aperture counts on stdout",
372 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
374 /* %start-doc options "90 Gerber Export"
377 generate metric Gerber and drill files
381 {"metric", "Generate metric Gerber and drill files",
382 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
384 {"copy-outline", "Copy outline onto other layers",
385 HID_Enum
, 0, 0, {0, 0, 0}, copy_outline_names
, 0},
386 #define HA_copy_outline 4
387 {"name-style", "Naming style for individual gerber files",
388 HID_Enum
, 0, 0, {0, 0, 0}, name_style_names
, 0},
389 #define HA_name_style 5
392 #define NUM_OPTIONS (sizeof(gerber_options)/sizeof(gerber_options[0]))
394 static HID_Attr_Val gerber_values
[NUM_OPTIONS
];
396 static HID_Attribute
*
397 gerber_get_export_options (int *n
)
399 static char *last_made_filename
= NULL
;
400 if (PCB
) derive_default_filename(PCB
->Filename
, &gerber_options
[HA_gerberfile
], "", &last_made_filename
);
404 return gerber_options
;
408 group_for_layer (int l
)
410 if (l
< max_copper_layer
+ 2 && l
>= 0)
411 return GetLayerGroupNumberByNumber (l
);
412 /* else something unique */
413 return max_group
+ 3 + l
;
417 layer_sort (const void *va
, const void *vb
)
421 int d
= group_for_layer (b
) - group_for_layer (a
);
428 maybe_close_f (FILE *f
)
433 fprintf (f
, "M30\r\n");
435 fprintf (f
, "M02*\r\n");
440 static BoxType region
;
442 /* Very similar to layer_type_to_file_name() but appends only a
443 three-character suffix compatible with Eagle's defaults. */
445 assign_eagle_file_suffix (char *dest
, int idx
)
453 case SL (SILK
, TOP
): suff
= "plc"; break;
454 case SL (SILK
, BOTTOM
): suff
= "pls"; break;
455 case SL (MASK
, TOP
): suff
= "stc"; break;
456 case SL (MASK
, BOTTOM
): suff
= "sts"; break;
457 case SL (PDRILL
, 0): suff
= "drd"; break;
458 case SL (UDRILL
, 0): suff
= "dru"; break;
459 case SL (PASTE
, TOP
): suff
= "crc"; break;
460 case SL (PASTE
, BOTTOM
): suff
= "crs"; break;
461 case SL (INVISIBLE
, 0): suff
= "inv"; break;
462 case SL (FAB
, 0): suff
= "fab"; break;
463 case SL (ASSY
, TOP
): suff
= "ast"; break;
464 case SL (ASSY
, BOTTOM
): suff
= "asb"; break;
467 group
= GetLayerGroupNumberByNumber(idx
);
468 nlayers
= PCB
->LayerGroups
.Number
[group
];
469 if (group
== GetLayerGroupNumberByNumber(component_silk_layer
))
473 else if (group
== GetLayerGroupNumberByNumber(solder_silk_layer
))
477 else if (nlayers
== 1
478 && (strcmp (PCB
->Data
->Layer
[idx
].Name
, "route") == 0 ||
479 strcmp (PCB
->Data
->Layer
[idx
].Name
, "outline") == 0))
486 sprintf (buf
, "ly%d", group
);
496 assign_file_suffix (char *dest
, int idx
)
499 const char *sext
= ".gbr";
504 case NAME_STYLE_FIXED
: fns_style
= FNS_fixed
; break;
505 case NAME_STYLE_SINGLE
: fns_style
= FNS_single
; break;
506 case NAME_STYLE_FIRST
: fns_style
= FNS_first
; break;
507 case NAME_STYLE_EAGLE
:
508 assign_eagle_file_suffix (dest
, idx
);
522 strcpy (dest
, layer_type_to_file_name (idx
, fns_style
));
527 gerber_do_export (HID_Attr_Val
* options
)
531 static int saved_layer_stack
[MAX_LAYER
];
532 int save_ons
[MAX_LAYER
+ 2];
533 FlagType save_thindraw
;
535 save_thindraw
= PCB
->Flags
;
536 CLEAR_FLAG(THINDRAWFLAG
, PCB
);
537 CLEAR_FLAG(THINDRAWPOLYFLAG
, PCB
);
538 CLEAR_FLAG(CHECKPLANESFLAG
, PCB
);
542 gerber_get_export_options (NULL
);
543 for (i
= 0; i
< NUM_OPTIONS
; i
++)
544 gerber_values
[i
] = gerber_options
[i
].default_val
;
545 options
= gerber_values
;
548 fnbase
= options
[HA_gerberfile
].str_value
;
552 verbose
= options
[HA_verbose
].int_value
;
553 metric
= options
[HA_metric
].int_value
;
555 x_convspec
= "X%.0mu";
556 y_convspec
= "Y%.0mu";
558 x_convspec
= "X%.0mc";
559 y_convspec
= "Y%.0mc";
561 all_layers
= options
[HA_all_layers
].int_value
;
563 copy_outline_mode
= options
[HA_copy_outline
].int_value
;
564 name_style
= options
[HA_name_style
].int_value
;
566 outline_layer
= NULL
;
568 for (i
= 0; i
< max_copper_layer
; i
++)
570 LayerType
*layer
= PCB
->Data
->Layer
+ i
;
571 if (strcmp (layer
->Name
, "outline") == 0 ||
572 strcmp (layer
->Name
, "route") == 0)
574 outline_layer
= layer
;
579 filename
= (char *)realloc (filename
, i
+ 40);
580 strcpy (filename
, fnbase
);
581 strcat (filename
, ".");
582 filesuff
= filename
+ strlen (filename
);
586 memset (print_group
, 1, sizeof (print_group
));
587 memset (print_layer
, 1, sizeof (print_layer
));
591 memset (print_group
, 0, sizeof (print_group
));
592 memset (print_layer
, 0, sizeof (print_layer
));
595 hid_save_and_show_layer_ons (save_ons
);
596 for (i
= 0; i
< max_copper_layer
; i
++)
598 LayerType
*layer
= PCB
->Data
->Layer
+ i
;
599 if (layer
->LineN
|| layer
->TextN
|| layer
->ArcN
|| layer
->PolygonN
)
600 print_group
[GetLayerGroupNumberByNumber (i
)] = 1;
602 print_group
[GetLayerGroupNumberByNumber (solder_silk_layer
)] = 1;
603 print_group
[GetLayerGroupNumberByNumber (component_silk_layer
)] = 1;
604 for (i
= 0; i
< max_copper_layer
; i
++)
605 if (print_group
[GetLayerGroupNumberByNumber (i
)])
608 memcpy (saved_layer_stack
, LayerStack
, sizeof (LayerStack
));
609 qsort (LayerStack
, max_copper_layer
, sizeof (LayerStack
[0]), layer_sort
);
616 region
.X2
= PCB
->MaxWidth
;
617 region
.Y2
= PCB
->MaxHeight
;
624 finding_apertures
= 1;
625 hid_expose_callback (&gerber_hid
, ®ion
, 0);
628 finding_apertures
= 0;
629 hid_expose_callback (&gerber_hid
, ®ion
, 0);
631 memcpy (LayerStack
, saved_layer_stack
, sizeof (LayerStack
));
635 hid_restore_layer_ons (save_ons
);
636 PCB
->Flags
= save_thindraw
;
640 gerber_parse_arguments (int *argc
, char ***argv
)
642 hid_register_attributes (gerber_options
, NUM_OPTIONS
);
643 hid_parse_command_line (argc
, argv
);
647 drill_sort (const void *va
, const void *vb
)
649 PendingDrills
*a
= (PendingDrills
*) va
;
650 PendingDrills
*b
= (PendingDrills
*) vb
;
651 if (a
->diam
!= b
->diam
)
652 return a
->diam
- b
->diam
;
659 gerber_set_layer (const char *name
, int group
, int empty
)
663 int idx
= (group
>= 0
665 max_group
) ? PCB
->LayerGroups
.Entries
[group
][0] : group
;
668 name
= PCB
->Data
->Layer
[idx
].Name
;
670 if (idx
>= 0 && idx
< max_copper_layer
&& !print_layer
[idx
])
673 if (strcmp (name
, "invisible") == 0)
675 if (SL_TYPE (idx
) == SL_ASSY
)
679 if (strcmp (name
, "outline") == 0 ||
680 strcmp (name
, "route") == 0)
683 if (is_drill
&& n_pending_drills
)
686 /* dump pending drills in sequence */
687 qsort (pending_drills
, n_pending_drills
, sizeof (pending_drills
[0]),
689 for (i
= 0; i
< n_pending_drills
; i
++)
691 if (i
== 0 || pending_drills
[i
].diam
!= pending_drills
[i
- 1].diam
)
693 Aperture
*ap
= findAperture (curr_aptr_list
, pending_drills
[i
].diam
, ROUND
);
694 fprintf (f
, "T%02d\r\n", ap
->dCode
);
696 /* Notice the last zeroes are literal zeroes here, a x10 scale factor. *
698 pcb_fprintf (f
, metric
? "X%06.0muY%06.0mu\r\n" : "X%06.0ml0Y%06.0ml0\r\n",
699 gerberDrX (PCB
, pending_drills
[i
].x
),
700 gerberDrY (PCB
, pending_drills
[i
].y
));
702 free (pending_drills
);
703 n_pending_drills
= max_pending_drills
= 0;
704 pending_drills
= NULL
;
707 is_drill
= (SL_TYPE (idx
) == SL_PDRILL
|| SL_TYPE (idx
) == SL_UDRILL
);
708 is_mask
= (SL_TYPE (idx
) == SL_MASK
);
709 current_mask
= HID_MASK_OFF
;
711 printf ("Layer %s group %d drill %d mask %d\n", name
, group
, is_drill
,
715 if (group
< 0 || group
!= lastgroup
)
720 struct passwd
*pwentry
;
722 ApertureList
*aptr_list
;
731 aptr_list
= setLayerApertureList (layer_list_idx
++);
733 if (finding_apertures
)
736 if (aptr_list
->count
== 0 && !all_layers
)
743 assign_file_suffix (filesuff
, idx
);
744 f
= fopen (filename
, "wb"); /* Binary needed to force CR-LF */
747 Message ( "Error: Could not open %s for writing.\n", filename
);
751 was_drill
= is_drill
;
755 int c
= aptr_list
->count
;
756 printf ("Gerber: %d aperture%s in %s\n", c
,
757 c
== 1 ? "" : "s", filename
);
762 /* We omit the ,TZ here because we are not omitting trailing zeros. Our format is
763 always six-digit 0.1 mil or µm resolution (i.e. 001100 = 0.11" or 1.1mm)*/
764 fprintf (f
, "M48\r\n");
765 fprintf (f
, metric
? "METRIC,000.000\r\n" : "INCH\r\n");
766 for (search
= aptr_list
->data
; search
; search
= search
->next
)
767 pcb_fprintf (f
, metric
? "T%02dC%.3`mm\r\n" : "T%02dC%.3`mi\r\n", search
->dCode
, search
->width
);
768 fprintf (f
, "%%\r\n");
773 fprintf (f
, "G04 start of page %d for group %d idx %d *\r\n",
774 pagecount
, group
, idx
);
776 /* Create a portable timestamp. */
777 currenttime
= time (NULL
);
779 /* avoid gcc complaints */
780 const char *fmt
= "%c UTC";
781 strftime (utcTime
, sizeof utcTime
, fmt
, gmtime (¤ttime
));
783 /* Print a cute file header at the beginning of each file. */
784 fprintf (f
, "G04 Title: %s, %s *\r\n", UNKNOWN (PCB
->Name
),
786 fprintf (f
, "G04 Creator: %s " VERSION
" *\r\n", Progname
);
787 fprintf (f
, "G04 CreationDate: %s *\r\n", utcTime
);
791 pwentry
= getpwuid (getuid ());
792 fprintf (f
, "G04 For: %s *\r\n", pwentry
->pw_name
);
795 fprintf (f
, "G04 Format: Gerber/RS-274X *\r\n");
796 pcb_fprintf (f
, metric
? "G04 PCB-Dimensions (mm): %.2mm %.2mm *\r\n" :
797 "G04 PCB-Dimensions (mil): %.2ml %.2ml *\r\n",
798 PCB
->MaxWidth
, PCB
->MaxHeight
);
799 fprintf (f
, "G04 PCB-Coordinate-Origin: lower left *\r\n");
801 /* Signal data in inches. */
802 fprintf (f
, metric
? "%%MOMM*%%\r\n" : "%%MOIN*%%\r\n");
804 /* Signal Leading zero suppression, Absolute Data, 2.5 format in inch, 4.3 in mm */
805 fprintf (f
, metric
? "%%FSLAX43Y43*%%\r\n" : "%%FSLAX25Y25*%%\r\n");
807 /* build a legal identifier. */
810 layername
= strdup (filesuff
);
811 if (strrchr (layername
, '.'))
812 * strrchr (layername
, '.') = 0;
814 for (cp
=layername
; *cp
; cp
++)
816 if (isalnum((int) *cp
))
817 *cp
= toupper((int) *cp
);
821 fprintf (f
, "%%LN%s*%%\r\n", layername
);
824 for (search
= aptr_list
->data
; search
; search
= search
->next
)
825 fprintAperture(f
, search
);
826 if (aptr_list
->count
== 0)
827 /* We need to put *something* in the file to make it be parsed
828 as RS-274X instead of RS-274D. */
829 fprintf (f
, "%%ADD11C,0.0100*%%\r\n");
833 /* If we're printing a copper layer other than the outline layer,
834 and we want to "print outlines", and we have an outline layer,
835 print the outline layer on this layer also. */
837 if (copy_outline_mode
== COPY_OUTLINE_MASK
838 && SL_TYPE (idx
) == SL_MASK
)
840 if (copy_outline_mode
== COPY_OUTLINE_SILK
841 && SL_TYPE (idx
) == SL_SILK
)
843 if (copy_outline_mode
== COPY_OUTLINE_ALL
844 && (SL_TYPE (idx
) == SL_SILK
845 || SL_TYPE (idx
) == SL_MASK
846 || SL_TYPE (idx
) == SL_FAB
847 || SL_TYPE (idx
) == SL_ASSY
848 || SL_TYPE (idx
) == 0))
852 && strcmp (name
, "outline")
853 && strcmp (name
, "route"))
856 && outline_layer
!= PCB
->Data
->Layer
+idx
)
857 DrawLayer (outline_layer
, ®ion
);
858 else if (!outline_layer
)
860 hidGC gc
= gui
->make_gc ();
861 printf("name %s idx %d\n", name
, idx
);
862 if (SL_TYPE (idx
) == SL_SILK
)
863 gui
->set_line_width (gc
, PCB
->minSlk
);
865 gui
->set_line_width (gc
, PCB
->minWid
);
867 gui
->set_line_width (gc
, AUTO_OUTLINE_WIDTH
);
868 gui
->draw_line (gc
, 0, 0, PCB
->MaxWidth
, 0);
869 gui
->draw_line (gc
, 0, 0, 0, PCB
->MaxHeight
);
870 gui
->draw_line (gc
, PCB
->MaxWidth
, 0, PCB
->MaxWidth
, PCB
->MaxHeight
);
871 gui
->draw_line (gc
, 0, PCB
->MaxHeight
, PCB
->MaxWidth
, PCB
->MaxHeight
);
872 gui
->destroy_gc (gc
);
880 gerber_make_gc (void)
882 hidGC rv
= (hidGC
) calloc (1, sizeof (*rv
));
888 gerber_destroy_gc (hidGC gc
)
894 gerber_use_mask (enum mask_mode mode
)
900 gerber_set_color (hidGC gc
, const char *name
)
902 if (strcmp (name
, "erase") == 0)
908 else if (strcmp (name
, "drill") == 0)
923 gerber_set_line_cap (hidGC gc
, EndCapStyle style
)
929 gerber_set_line_width (hidGC gc
, Coord width
)
935 gerber_set_draw_xor (hidGC gc
, int xor_
)
941 use_gc (hidGC gc
, int radius
)
946 if (radius
!= linewidth
|| lastcap
!= Round_Cap
)
948 Aperture
*aptr
= findAperture (curr_aptr_list
, radius
, ROUND
);
950 pcb_fprintf (stderr
, "error: aperture for radius %$mS type ROUND is null\n", radius
);
951 else if (f
&& !is_drill
)
952 fprintf (f
, "G54D%d*", aptr
->dCode
);
957 else if (linewidth
!= gc
->width
|| lastcap
!= gc
->cap
)
962 linewidth
= gc
->width
;
975 aptr
= findAperture (curr_aptr_list
, linewidth
, shape
);
977 pcb_fprintf (stderr
, "error: aperture for width %$mS type %s is null\n",
978 linewidth
, shape
== ROUND
? "ROUND" : "SQUARE");
980 fprintf (f
, "G54D%d*", aptr
->dCode
);
985 gerber_draw_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
987 gerber_draw_line (gc
, x1
, y1
, x1
, y2
);
988 gerber_draw_line (gc
, x1
, y1
, x2
, y1
);
989 gerber_draw_line (gc
, x1
, y2
, x2
, y2
);
990 gerber_draw_line (gc
, x2
, y1
, x2
, y2
);
994 gerber_draw_line (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
998 if (x1
!= x2
&& y1
!= y2
&& gc
->cap
== Square_Cap
)
1001 double tx
, ty
, theta
;
1003 theta
= atan2 (y2
-y1
, x2
-x1
);
1005 /* T is a vector half a thickness long, in the direction of
1006 one of the corners. */
1007 tx
= gc
->width
/ 2.0 * cos (theta
+ M_PI
/4) * sqrt(2.0);
1008 ty
= gc
->width
/ 2.0 * sin (theta
+ M_PI
/4) * sqrt(2.0);
1010 x
[0] = x1
- tx
; y
[0] = y1
- ty
;
1011 x
[1] = x2
+ ty
; y
[1] = y2
- tx
;
1012 x
[2] = x2
+ tx
; y
[2] = y2
+ ty
;
1013 x
[3] = x1
- ty
; y
[3] = y1
+ tx
;
1015 x
[4] = x
[0]; y
[4] = y
[0];
1016 gerber_fill_polygon (gc
, 5, x
, y
);
1028 print_xcoord (f
, PCB
, lastX
);
1034 print_ycoord (f
, PCB
, lastY
);
1036 if ((x1
== x2
) && (y1
== y2
))
1037 fprintf (f
, "D03*\r\n");
1041 fprintf (f
, "D02*");
1045 print_xcoord (f
, PCB
, lastX
);
1050 print_ycoord (f
, PCB
, lastY
);
1052 fprintf (f
, "D01*\r\n");
1058 gerber_draw_arc (hidGC gc
, Coord cx
, Coord cy
, Coord width
, Coord height
,
1059 Angle start_angle
, Angle delta_angle
)
1062 double arcStartX
, arcStopX
, arcStartY
, arcStopY
;
1064 /* we never draw zero-width lines */
1072 arcStartX
= cx
- width
* cos (TO_RADIANS (start_angle
));
1073 arcStartY
= cy
+ height
* sin (TO_RADIANS (start_angle
));
1075 /* I checked three different gerber viewers, and they all disagreed
1076 on how ellipses should be drawn. The spec just calls G74/G75
1077 "circular interpolation" so there's a chance it just doesn't
1078 support ellipses at all. Thus, we draw them out with line
1079 segments. Note that most arcs in pcb are circles anyway. */
1080 if (width
!= height
)
1083 Coord max
= width
> height
? width
: height
;
1084 Coord minr
= max
- gc
->width
/ 10;
1086 Coord x0
, y0
, x1
, y1
;
1090 step
= acos((double)minr
/(double)max
) * 180.0/M_PI
;
1093 nsteps
= abs(delta_angle
) / step
+ 1;
1094 step
= (double)delta_angle
/ nsteps
;
1098 angle
= start_angle
;
1102 x1
= cx
- width
* cos (TO_RADIANS (angle
+step
));
1103 y1
= cy
+ height
* sin (TO_RADIANS (angle
+step
));
1104 gerber_draw_line (gc
, x0
, y0
, x1
, y1
);
1112 arcStopX
= cx
- width
* cos (TO_RADIANS (start_angle
+ delta_angle
));
1113 arcStopY
= cy
+ height
* sin (TO_RADIANS (start_angle
+ delta_angle
));
1114 if (arcStartX
!= lastX
)
1118 print_xcoord (f
, PCB
, lastX
);
1120 if (arcStartY
!= lastY
)
1124 print_ycoord (f
, PCB
, lastY
);
1127 fprintf (f
, "D02*");
1129 metric
? "G75*G0%1dX%.0muY%.0muI%.0muJ%.0muD01*G01*\r\n" :
1130 "G75*G0%1dX%.0mcY%.0mcI%.0mcJ%.0mcD01*G01*\r\n",
1131 (delta_angle
< 0) ? 2 : 3,
1132 gerberX (PCB
, arcStopX
), gerberY (PCB
, arcStopY
),
1133 gerberXOffset (PCB
, cx
- arcStartX
),
1134 gerberYOffset (PCB
, cy
- arcStartY
));
1140 gerber_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
)
1145 radius
= 50 * round (radius
/ 50.0);
1146 use_gc (gc
, radius
);
1151 if (n_pending_drills
>= max_pending_drills
)
1153 max_pending_drills
+= 100;
1154 pending_drills
= (PendingDrills
*) realloc(pending_drills
,
1155 max_pending_drills
*
1156 sizeof (pending_drills
[0]));
1158 pending_drills
[n_pending_drills
].x
= cx
;
1159 pending_drills
[n_pending_drills
].y
= cy
;
1160 pending_drills
[n_pending_drills
].diam
= radius
* 2;
1164 else if (gc
->drill
&& !flash_drills
)
1169 print_xcoord (f
, PCB
, lastX
);
1174 print_ycoord (f
, PCB
, lastY
);
1176 fprintf (f
, "D03*\r\n");
1180 gerber_fill_polygon (hidGC gc
, int n_coords
, Coord
*x
, Coord
*y
)
1185 Coord startX
= 0, startY
= 0;
1187 if (is_mask
&& current_mask
== HID_MASK_BEFORE
)
1190 use_gc (gc
, 10 * 100);
1193 fprintf (f
, "G36*\r\n");
1194 for (i
= 0; i
< n_coords
; i
++)
1200 print_xcoord (f
, PCB
, lastX
);
1206 print_ycoord (f
, PCB
, lastY
);
1214 fprintf (f
, "D02*");
1217 fprintf (f
, "D01*\r\n");
1220 if (startX
!= lastX
)
1224 print_xcoord (f
, PCB
, startX
);
1226 if (startY
!= lastY
)
1230 print_ycoord (f
, PCB
, lastY
);
1233 fprintf (f
, "D01*\r\n");
1234 fprintf (f
, "G37*\r\n");
1238 gerber_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
1250 gerber_fill_polygon (gc
, 5, x
, y
);
1254 gerber_calibrate (double xval
, double yval
)
1260 gerber_set_crosshair (int x
, int y
, int action
)
1267 memset (&gerber_hid
, 0, sizeof (gerber_hid
));
1269 common_nogui_init (&gerber_hid
);
1270 common_draw_helpers_init (&gerber_hid
);
1272 gerber_hid
.struct_size
= sizeof (gerber_hid
);
1273 gerber_hid
.name
= "gerber";
1274 gerber_hid
.description
= "RS-274X (Gerber) export";
1275 gerber_hid
.exporter
= 1;
1277 gerber_hid
.get_export_options
= gerber_get_export_options
;
1278 gerber_hid
.do_export
= gerber_do_export
;
1279 gerber_hid
.parse_arguments
= gerber_parse_arguments
;
1280 gerber_hid
.set_layer
= gerber_set_layer
;
1281 gerber_hid
.make_gc
= gerber_make_gc
;
1282 gerber_hid
.destroy_gc
= gerber_destroy_gc
;
1283 gerber_hid
.use_mask
= gerber_use_mask
;
1284 gerber_hid
.set_color
= gerber_set_color
;
1285 gerber_hid
.set_line_cap
= gerber_set_line_cap
;
1286 gerber_hid
.set_line_width
= gerber_set_line_width
;
1287 gerber_hid
.set_draw_xor
= gerber_set_draw_xor
;
1288 gerber_hid
.draw_line
= gerber_draw_line
;
1289 gerber_hid
.draw_arc
= gerber_draw_arc
;
1290 gerber_hid
.draw_rect
= gerber_draw_rect
;
1291 gerber_hid
.fill_circle
= gerber_fill_circle
;
1292 gerber_hid
.fill_polygon
= gerber_fill_polygon
;
1293 gerber_hid
.fill_rect
= gerber_fill_rect
;
1294 gerber_hid
.calibrate
= gerber_calibrate
;
1295 gerber_hid
.set_crosshair
= gerber_set_crosshair
;
1297 hid_register_hid (&gerber_hid
);