27 #include "pcb-printf.h"
31 #include "../hidint.h"
32 #include "hid/common/hidnogui.h"
33 #include "hid/common/draw_helpers.h"
34 #include "hid/common/hidinit.h"
36 #ifdef HAVE_LIBDMALLOC
40 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented Gerber function %s.\n", __FUNCTION__); abort()
42 /*----------------------------------------------------------------------------*/
43 /* Function prototypes */
44 /*----------------------------------------------------------------------------*/
46 static HID_Attribute
* gerber_get_export_options (int *n
);
47 static void gerber_do_export (HID_Attr_Val
* options
);
48 static void gerber_parse_arguments (int *argc
, char ***argv
);
49 static int gerber_set_layer (const char *name
, int group
, int empty
);
50 static hidGC
gerber_make_gc (void);
51 static void gerber_destroy_gc (hidGC gc
);
52 static void gerber_use_mask (enum mask_mode mode
);
53 static void gerber_set_color (hidGC gc
, const char *name
);
54 static void gerber_set_line_cap (hidGC gc
, EndCapStyle style
);
55 static void gerber_set_line_width (hidGC gc
, Coord width
);
56 static void gerber_set_draw_xor (hidGC gc
, int _xor
);
57 static void gerber_draw_line (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
);
58 static void gerber_draw_arc (hidGC gc
, Coord cx
, Coord cy
, Coord width
, Coord height
, Angle start_angle
, Angle delta_angle
);
59 static void gerber_draw_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
);
60 static void gerber_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
);
61 static void gerber_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
);
62 static void gerber_calibrate (double xval
, double yval
);
63 static void gerber_set_crosshair (int x
, int y
, int action
);
64 static void gerber_fill_polygon (hidGC gc
, int n_coords
, Coord
*x
, Coord
*y
);
66 /*----------------------------------------------------------------------------*/
67 /* Utility routines */
68 /*----------------------------------------------------------------------------*/
70 /* These are for films */
71 #define gerberX(pcb, x) ((Coord) (x))
72 #define gerberY(pcb, y) ((Coord) ((pcb)->MaxHeight - (y)))
73 #define gerberXOffset(pcb, x) ((Coord) (x))
74 #define gerberYOffset(pcb, y) ((Coord) (-(y)))
76 /* These are for drills */
77 #define gerberDrX(pcb, x) ((Coord) (x))
78 #define gerberDrY(pcb, y) ((Coord) ((pcb)->MaxHeight - (y)))
80 /*----------------------------------------------------------------------------*/
81 /* Private data structures */
82 /*----------------------------------------------------------------------------*/
85 static int all_layers
;
87 static char *x_convspec
, *y_convspec
;
88 static int is_mask
, was_drill
;
90 static enum mask_mode current_mask
;
91 static int flash_drills
;
92 static int copy_outline_mode
;
93 static int name_style
;
94 static LayerType
*outline_layer
;
96 #define print_xcoord(file, pcb, val)\
97 pcb_fprintf(file, x_convspec, gerberX(pcb, val))
99 #define print_ycoord(file, pcb, val)\
100 pcb_fprintf(file, y_convspec, gerberY(pcb, val))
104 ROUND
, /* Shaped like a circle */
105 OCTAGON
, /* octagonal shape */
106 SQUARE
, /* Shaped like a square */
107 ROUNDCLEAR
, /* clearance in negatives */
109 THERMAL
/* negative thermal relief */
111 typedef enum ApertureShape ApertureShape
;
113 /* This is added to the global aperture array indexes to get gerber
114 dcode and macro numbers. */
115 #define DCODE_BASE 11
117 typedef struct aperture
119 int dCode
; /* The RS-274X D code */
120 Coord width
; /* Size in pcb units */
121 ApertureShape shape
; /* ROUND/SQUARE etc */
122 struct aperture
*next
;
132 static ApertureList
*layer_aptr_list
;
133 static ApertureList
*curr_aptr_list
;
134 static int layer_list_max
;
135 static int layer_list_idx
;
143 PendingDrills
*pending_drills
= NULL
;
144 int n_pending_drills
= 0, max_pending_drills
= 0;
146 /*----------------------------------------------------------------------------*/
147 /* Defined Constants */
148 /*----------------------------------------------------------------------------*/
149 #define AUTO_OUTLINE_WIDTH MIL_TO_COORD(8) /* Auto-geneated outline width of 8 mils */
151 /*----------------------------------------------------------------------------*/
152 /* Aperture Routines */
153 /*----------------------------------------------------------------------------*/
155 /* Initialize aperture list */
157 initApertureList (ApertureList
*list
)
164 deinitApertureList (ApertureList
*list
)
166 Aperture
*search
= list
->data
;
174 initApertureList (list
);
177 static int aperture_count
;
179 static void resetApertures()
182 for (i
= 0; i
< layer_list_max
; ++i
)
183 deinitApertureList (&layer_aptr_list
[i
]);
184 free (layer_aptr_list
);
185 layer_aptr_list
= NULL
;
186 curr_aptr_list
= NULL
;
192 /* Create and add a new aperture to the list */
194 addAperture (ApertureList
*list
, Coord width
, ApertureShape shape
)
197 Aperture
*app
= (Aperture
*) malloc (sizeof *app
);
203 app
->dCode
= DCODE_BASE
+ aperture_count
++;
204 app
->next
= list
->data
;
212 /* Fetch an aperture from the list with the specified
213 * width/shape, creating a new one if none exists */
215 findAperture (ApertureList
*list
, Coord width
, ApertureShape shape
)
219 /* we never draw zero-width lines */
223 /* Search for an appropriate aperture. */
224 for (search
= list
->data
; search
; search
= search
->next
)
225 if (search
->width
== width
&& search
->shape
== shape
)
228 /* Failing that, create a new one */
229 return addAperture (list
, width
, shape
);
232 /* Output aperture data to the file */
234 fprintAperture (FILE *f
, Aperture
*aptr
)
239 pcb_fprintf (f
, metric
? "%%ADD%dC,%.3`mm*%%\r\n" : "%%ADD%dC,%.4`mi*%%\r\n", aptr
->dCode
, aptr
->width
);
242 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
);
245 pcb_fprintf (f
, metric
? "%%AMOCT%d*5,0,8,0,0,%.3`mm,22.5*%%\r\n"
246 "%%ADD%dOCT%d*%%\r\n" : "%%AMOCT%d*5,0,8,0,0,%.3`mm,22.5*%%\r\n"
247 "%%ADD%dOCT%d*%%\r\n", aptr
->dCode
,
248 (Coord
) ((double) aptr
->width
/ COS_22_5_DEGREE
), aptr
->dCode
,
253 fprintf (f
, "%%AMTHERM%d*7,0,0,%.4f,%.4f,%.4f,45*%%\r\n"
254 "%%ADD%dTHERM%d*%%\r\n", dCode
, gap
/ 100000.0,
255 width
/ 100000.0, finger
/ 100000.0, dCode
, dCode
);
258 fprintf (f
, "%%ADD%dC,%.4fX%.4f*%%\r\n",
259 dCode
, gap
/ 100000.0, width
/ 100000.0);
262 fprintf (f
, "%%ADD%dR,%.4fX%.4fX%.4fX%.4f*%%\r\n",
263 dCode
, gap
/ 100000.0, gap
/ 100000.0,
264 width
/ 100000.0, width
/ 100000.0);
273 /* Set the aperture list for the current layer,
274 * expanding the list buffer if needed */
275 static ApertureList
*
276 setLayerApertureList (int layer_idx
)
278 if (layer_idx
>= layer_list_max
)
280 int i
= layer_list_max
;
281 layer_list_max
= 2 * (layer_idx
+ 1);
282 layer_aptr_list
= (ApertureList
*)
283 realloc (layer_aptr_list
, layer_list_max
* sizeof (*layer_aptr_list
));
284 for (; i
< layer_list_max
; ++i
)
285 initApertureList (&layer_aptr_list
[i
]);
287 curr_aptr_list
= &layer_aptr_list
[layer_idx
];
288 return curr_aptr_list
;
291 /* --------------------------------------------------------------------------- */
293 static HID gerber_hid
;
294 static HID_DRAW gerber_graphics
;
295 static HID_DRAW_CLASS gerber_graphics_class
;
297 typedef struct gerber_gc_struct
299 struct hid_gc_struct hid_gc
; /* Parent */
308 static FILE *f
= NULL
;
309 static char *filename
= NULL
;
310 static char *filesuff
= NULL
;
311 static char *layername
= NULL
;
312 static int lncount
= 0;
314 static int finding_apertures
= 0;
315 static int pagecount
= 0;
316 static int linewidth
= -1;
317 static int lastgroup
= -1;
318 static int lastcap
= -1;
319 static int print_group
[MAX_GROUP
];
320 static int print_layer
[MAX_LAYER
];
321 static int lastX
, lastY
; /* the last X and Y coordinate */
323 static const char *copy_outline_names
[] = {
324 #define COPY_OUTLINE_NONE 0
326 #define COPY_OUTLINE_MASK 1
328 #define COPY_OUTLINE_SILK 2
330 #define COPY_OUTLINE_ALL 3
335 static const char *name_style_names
[] = {
336 #define NAME_STYLE_FIXED 0
338 #define NAME_STYLE_SINGLE 1
340 #define NAME_STYLE_FIRST 2
342 #define NAME_STYLE_EAGLE 3
344 #define NAME_STYLE_HACKVANA 4
349 static HID_Attribute gerber_options
[] = {
351 /* %start-doc options "90 Gerber Export"
353 @item --gerberfile <string>
354 Gerber output file prefix. Can include a path.
358 {"gerberfile", "Gerber output file base",
359 HID_String
, 0, 0, {0, 0, 0}, 0, 0},
360 #define HA_gerberfile 0
362 /* %start-doc options "90 Gerber Export"
365 Output contains all layers, even empty ones.
369 {"all-layers", "Output all layers, even empty ones",
370 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
371 #define HA_all_layers 1
373 /* %start-doc options "90 Gerber Export"
376 Print file names and aperture counts on stdout.
380 {"verbose", "Print file names and aperture counts on stdout",
381 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
383 /* %start-doc options "90 Gerber Export"
386 generate metric Gerber and drill files
390 {"metric", "Generate metric Gerber and drill files",
391 HID_Boolean
, 0, 0, {0, 0, 0}, 0, 0},
393 {"copy-outline", "Copy outline onto other layers",
394 HID_Enum
, 0, 0, {0, 0, 0}, copy_outline_names
, 0},
395 #define HA_copy_outline 4
396 {"name-style", "Naming style for individual gerber files",
397 HID_Enum
, 0, 0, {0, 0, 0}, name_style_names
, 0},
398 #define HA_name_style 5
401 #define NUM_OPTIONS (sizeof(gerber_options)/sizeof(gerber_options[0]))
403 static HID_Attr_Val gerber_values
[NUM_OPTIONS
];
405 static HID_Attribute
*
406 gerber_get_export_options (int *n
)
408 static char *last_made_filename
= NULL
;
409 if (PCB
) derive_default_filename(PCB
->Filename
, &gerber_options
[HA_gerberfile
], "", &last_made_filename
);
413 return gerber_options
;
417 layer_stack_sort (const void *va
, const void *vb
)
419 int a_layer
= *(int *) va
;
420 int b_layer
= *(int *) vb
;
421 int a_group
= GetLayerGroupNumberByNumber (a_layer
);
422 int b_group
= GetLayerGroupNumberByNumber (b_layer
);
424 if (b_group
!= a_group
)
425 return b_group
- a_group
;
427 return b_layer
- a_layer
;
431 maybe_close_f (FILE *f
)
436 fprintf (f
, "M30\r\n");
438 fprintf (f
, "M02*\r\n");
443 static BoxType region
;
445 /* Very similar to layer_type_to_file_name() but appends only a
446 three-character suffix compatible with Eagle's defaults. */
448 assign_eagle_file_suffix (char *dest
, int idx
)
456 case SL (SILK
, TOP
): suff
= "plc"; break;
457 case SL (SILK
, BOTTOM
): suff
= "pls"; break;
458 case SL (MASK
, TOP
): suff
= "stc"; break;
459 case SL (MASK
, BOTTOM
): suff
= "sts"; break;
460 case SL (PDRILL
, 0): suff
= "drd"; break;
461 case SL (UDRILL
, 0): suff
= "dru"; break;
462 case SL (PASTE
, TOP
): suff
= "crc"; break;
463 case SL (PASTE
, BOTTOM
): suff
= "crs"; break;
464 case SL (INVISIBLE
, 0): suff
= "inv"; break;
465 case SL (FAB
, 0): suff
= "fab"; break;
466 case SL (ASSY
, TOP
): suff
= "ast"; break;
467 case SL (ASSY
, BOTTOM
): suff
= "asb"; break;
470 group
= GetLayerGroupNumberByNumber(idx
);
471 nlayers
= PCB
->LayerGroups
.Number
[group
];
472 if (group
== GetLayerGroupNumberBySide(TOP_SIDE
)) /* Component */
476 else if (group
== GetLayerGroupNumberBySide(BOTTOM_SIDE
)) /* Solder */
480 else if (nlayers
== 1
481 && (strcmp (PCB
->Data
->Layer
[idx
].Name
, "route") == 0 ||
482 strcmp (PCB
->Data
->Layer
[idx
].Name
, "outline") == 0))
489 sprintf (buf
, "ly%d", group
);
498 /* Very similar to layer_type_to_file_name() but appends only a
499 three-character suffix compatible with Hackvana's naming requirements */
501 assign_hackvana_file_suffix (char *dest
, int idx
)
505 char *suff
= "defau.out";
509 case SL (SILK
, TOP
): suff
= "gto"; break;
510 case SL (SILK
, BOTTOM
): suff
= "gbo"; break;
511 case SL (MASK
, TOP
): suff
= "gts"; break;
512 case SL (MASK
, BOTTOM
): suff
= "gbs"; break;
513 case SL (PDRILL
, 0): suff
= "drl"; break;
517 case SL (PASTE
, TOP
): suff
= "gtp"; break;
518 case SL (PASTE
, BOTTOM
): suff
= "gbp"; break;
519 case SL (INVISIBLE
, 0): suff
= "inv"; break;
520 case SL (FAB
, 0): suff
= "fab"; break;
521 case SL (ASSY
, TOP
): suff
= "ast"; break;
522 case SL (ASSY
, BOTTOM
): suff
= "asb"; break;
525 group
= GetLayerGroupNumberByNumber(idx
);
526 nlayers
= PCB
->LayerGroups
.Number
[group
];
527 if (group
== GetLayerGroupNumberBySide(TOP_SIDE
))
531 else if (group
== GetLayerGroupNumberBySide(BOTTOM_SIDE
))
535 else if (nlayers
== 1
536 && (strcmp (PCB
->Data
->Layer
[idx
].Name
, "route") == 0 ||
537 strcmp (PCB
->Data
->Layer
[idx
].Name
, "outline") == 0))
544 sprintf (buf
, "g%d", group
);
554 assign_file_suffix (char *dest
, int idx
)
557 const char *sext
= ".gbr";
562 case NAME_STYLE_FIXED
: fns_style
= FNS_fixed
; break;
563 case NAME_STYLE_SINGLE
: fns_style
= FNS_single
; break;
564 case NAME_STYLE_FIRST
: fns_style
= FNS_first
; break;
565 case NAME_STYLE_EAGLE
:
566 assign_eagle_file_suffix (dest
, idx
);
568 case NAME_STYLE_HACKVANA
:
569 assign_hackvana_file_suffix (dest
, idx
);
583 strcpy (dest
, layer_type_to_file_name (idx
, fns_style
));
588 gerber_do_export (HID_Attr_Val
* options
)
592 static int saved_layer_stack
[MAX_LAYER
];
593 int save_ons
[MAX_LAYER
+ 2];
594 FlagType save_thindraw
;
596 save_thindraw
= PCB
->Flags
;
597 CLEAR_FLAG(THINDRAWFLAG
, PCB
);
598 CLEAR_FLAG(THINDRAWPOLYFLAG
, PCB
);
599 CLEAR_FLAG(CHECKPLANESFLAG
, PCB
);
603 gerber_get_export_options (NULL
);
604 for (i
= 0; i
< NUM_OPTIONS
; i
++)
605 gerber_values
[i
] = gerber_options
[i
].default_val
;
606 options
= gerber_values
;
609 fnbase
= options
[HA_gerberfile
].str_value
;
613 verbose
= options
[HA_verbose
].int_value
;
614 metric
= options
[HA_metric
].int_value
;
616 x_convspec
= "X%.0mu";
617 y_convspec
= "Y%.0mu";
619 x_convspec
= "X%.0mc";
620 y_convspec
= "Y%.0mc";
622 all_layers
= options
[HA_all_layers
].int_value
;
624 copy_outline_mode
= options
[HA_copy_outline
].int_value
;
625 name_style
= options
[HA_name_style
].int_value
;
627 outline_layer
= NULL
;
629 for (i
= 0; i
< max_copper_layer
; i
++)
631 LayerType
*layer
= PCB
->Data
->Layer
+ i
;
632 if (strcmp (layer
->Name
, "outline") == 0 ||
633 strcmp (layer
->Name
, "route") == 0)
635 outline_layer
= layer
;
640 filename
= (char *)realloc (filename
, i
+ 40);
641 strcpy (filename
, fnbase
);
642 strcat (filename
, ".");
643 filesuff
= filename
+ strlen (filename
);
647 memset (print_group
, 1, sizeof (print_group
));
648 memset (print_layer
, 1, sizeof (print_layer
));
652 memset (print_group
, 0, sizeof (print_group
));
653 memset (print_layer
, 0, sizeof (print_layer
));
656 hid_save_and_show_layer_ons (save_ons
);
657 for (i
= 0; i
< max_copper_layer
; i
++)
659 LayerType
*layer
= PCB
->Data
->Layer
+ i
;
660 if (layer
->LineN
|| layer
->TextN
|| layer
->ArcN
|| layer
->PolygonN
)
661 print_group
[GetLayerGroupNumberByNumber (i
)] = 1;
663 print_group
[GetLayerGroupNumberBySide (BOTTOM_SIDE
)] = 1;
664 print_group
[GetLayerGroupNumberBySide (TOP_SIDE
)] = 1;
665 for (i
= 0; i
< max_copper_layer
; i
++)
666 if (print_group
[GetLayerGroupNumberByNumber (i
)])
669 memcpy (saved_layer_stack
, LayerStack
, sizeof (LayerStack
));
670 qsort (LayerStack
, max_copper_layer
, sizeof (LayerStack
[0]), layer_stack_sort
);
677 region
.X2
= PCB
->MaxWidth
;
678 region
.Y2
= PCB
->MaxHeight
;
685 finding_apertures
= 1;
686 hid_expose_callback (&gerber_hid
, ®ion
, 0);
689 finding_apertures
= 0;
690 hid_expose_callback (&gerber_hid
, ®ion
, 0);
692 memcpy (LayerStack
, saved_layer_stack
, sizeof (LayerStack
));
696 hid_restore_layer_ons (save_ons
);
697 PCB
->Flags
= save_thindraw
;
701 gerber_parse_arguments (int *argc
, char ***argv
)
703 hid_register_attributes (gerber_options
, NUM_OPTIONS
);
704 hid_parse_command_line (argc
, argv
);
708 drill_sort (const void *va
, const void *vb
)
710 PendingDrills
*a
= (PendingDrills
*) va
;
711 PendingDrills
*b
= (PendingDrills
*) vb
;
712 if (a
->diam
!= b
->diam
)
713 return a
->diam
- b
->diam
;
720 gerber_set_layer (const char *name
, int group
, int empty
)
724 int idx
= (group
>= 0
726 max_group
) ? PCB
->LayerGroups
.Entries
[group
][0] : group
;
729 name
= PCB
->Data
->Layer
[idx
].Name
;
731 if (idx
>= 0 && idx
< max_copper_layer
&& !print_layer
[idx
])
734 if (strcmp (name
, "invisible") == 0)
736 if (SL_TYPE (idx
) == SL_ASSY
)
740 if (strcmp (name
, "outline") == 0 ||
741 strcmp (name
, "route") == 0)
744 if (is_drill
&& n_pending_drills
)
747 /* dump pending drills in sequence */
748 qsort (pending_drills
, n_pending_drills
, sizeof (pending_drills
[0]),
750 for (i
= 0; i
< n_pending_drills
; i
++)
752 if (i
== 0 || pending_drills
[i
].diam
!= pending_drills
[i
- 1].diam
)
754 Aperture
*ap
= findAperture (curr_aptr_list
, pending_drills
[i
].diam
, ROUND
);
755 fprintf (f
, "T%02d\r\n", ap
->dCode
);
757 pcb_fprintf (f
, metric
? "X%06.0muY%06.0mu\r\n" : "X%06.0mtY%06.0mt\r\n",
758 gerberDrX (PCB
, pending_drills
[i
].x
),
759 gerberDrY (PCB
, pending_drills
[i
].y
));
761 free (pending_drills
);
762 n_pending_drills
= max_pending_drills
= 0;
763 pending_drills
= NULL
;
766 is_drill
= (SL_TYPE (idx
) == SL_PDRILL
|| SL_TYPE (idx
) == SL_UDRILL
);
767 is_mask
= (SL_TYPE (idx
) == SL_MASK
);
768 current_mask
= HID_MASK_OFF
;
770 printf ("Layer %s group %d drill %d mask %d\n", name
, group
, is_drill
,
774 if (group
< 0 || group
!= lastgroup
)
779 struct passwd
*pwentry
;
781 ApertureList
*aptr_list
;
790 aptr_list
= setLayerApertureList (layer_list_idx
++);
792 if (finding_apertures
)
795 if (aptr_list
->count
== 0 && !all_layers
)
802 assign_file_suffix (filesuff
, idx
);
803 f
= fopen (filename
, "wb"); /* Binary needed to force CR-LF */
806 Message ( "Error: Could not open %s for writing.\n", filename
);
810 was_drill
= is_drill
;
814 int c
= aptr_list
->count
;
815 printf ("Gerber: %d aperture%s in %s\n", c
,
816 c
== 1 ? "" : "s", filename
);
821 /* We omit the ,TZ here because we are not omitting trailing zeros. Our format is
822 always six-digit 0.1 mil or µm resolution (i.e. 001100 = 0.11" or 1.1mm)*/
823 fprintf (f
, "M48\r\n");
824 fprintf (f
, metric
? "METRIC,000.000\r\n" : "INCH\r\n");
825 for (search
= aptr_list
->data
; search
; search
= search
->next
)
826 pcb_fprintf (f
, metric
? "T%02dC%.3`mm\r\n" : "T%02dC%.3`mi\r\n", search
->dCode
, search
->width
);
827 fprintf (f
, "%%\r\n");
832 fprintf (f
, "G04 start of page %d for group %d idx %d *\r\n",
833 pagecount
, group
, idx
);
835 /* Create a portable timestamp. */
836 currenttime
= time (NULL
);
838 /* avoid gcc complaints */
839 const char *fmt
= "%c UTC";
840 strftime (utcTime
, sizeof utcTime
, fmt
, gmtime (¤ttime
));
842 /* Print a cute file header at the beginning of each file. */
843 fprintf (f
, "G04 Title: %s, %s *\r\n", UNKNOWN (PCB
->Name
),
845 fprintf (f
, "G04 Creator: %s " VERSION
" *\r\n", Progname
);
846 fprintf (f
, "G04 CreationDate: %s *\r\n", utcTime
);
850 pwentry
= getpwuid (getuid ());
851 fprintf (f
, "G04 For: %s *\r\n", pwentry
->pw_name
);
854 fprintf (f
, "G04 Format: Gerber/RS-274X *\r\n");
855 pcb_fprintf (f
, metric
? "G04 PCB-Dimensions (mm): %.2mm %.2mm *\r\n" :
856 "G04 PCB-Dimensions (mil): %.2ml %.2ml *\r\n",
857 PCB
->MaxWidth
, PCB
->MaxHeight
);
858 fprintf (f
, "G04 PCB-Coordinate-Origin: lower left *\r\n");
860 /* Signal data in inches. */
861 fprintf (f
, metric
? "%%MOMM*%%\r\n" : "%%MOIN*%%\r\n");
863 /* Signal Leading zero suppression, Absolute Data, 2.5 format in inch, 4.3 in mm */
864 fprintf (f
, metric
? "%%FSLAX43Y43*%%\r\n" : "%%FSLAX25Y25*%%\r\n");
866 /* build a legal identifier. */
869 layername
= strdup (filesuff
);
870 if (strrchr (layername
, '.'))
871 * strrchr (layername
, '.') = 0;
873 for (cp
=layername
; *cp
; cp
++)
875 if (isalnum((int) *cp
))
876 *cp
= toupper((int) *cp
);
880 fprintf (f
, "%%LN%s*%%\r\n", layername
);
883 for (search
= aptr_list
->data
; search
; search
= search
->next
)
884 fprintAperture(f
, search
);
885 if (aptr_list
->count
== 0)
886 /* We need to put *something* in the file to make it be parsed
887 as RS-274X instead of RS-274D. */
888 fprintf (f
, "%%ADD11C,0.0100*%%\r\n");
892 /* If we're printing a copper layer other than the outline layer,
893 and we want to "print outlines", and we have an outline layer,
894 print the outline layer on this layer also. */
896 if (copy_outline_mode
== COPY_OUTLINE_MASK
897 && SL_TYPE (idx
) == SL_MASK
)
899 if (copy_outline_mode
== COPY_OUTLINE_SILK
900 && SL_TYPE (idx
) == SL_SILK
)
902 if (copy_outline_mode
== COPY_OUTLINE_ALL
903 && (SL_TYPE (idx
) == SL_SILK
904 || SL_TYPE (idx
) == SL_MASK
905 || SL_TYPE (idx
) == SL_FAB
906 || SL_TYPE (idx
) == SL_ASSY
907 || SL_TYPE (idx
) == 0))
911 && strcmp (name
, "outline")
912 && strcmp (name
, "route"))
915 && outline_layer
!= PCB
->Data
->Layer
+idx
)
916 DrawLayer (outline_layer
, ®ion
);
917 else if (!outline_layer
)
919 hidGC gc
= hid_draw_make_gc (&gerber_graphics
);
920 printf("name %s idx %d\n", name
, idx
);
921 if (SL_TYPE (idx
) == SL_SILK
)
922 hid_draw_set_line_width (gc
, PCB
->minSlk
);
924 hid_draw_set_line_width (gc
, PCB
->minWid
);
926 hid_draw_set_line_width (gc
, AUTO_OUTLINE_WIDTH
);
927 hid_draw_line (gc
, 0, 0, PCB
->MaxWidth
, 0);
928 hid_draw_line (gc
, 0, 0, 0, PCB
->MaxHeight
);
929 hid_draw_line (gc
, PCB
->MaxWidth
, 0, PCB
->MaxWidth
, PCB
->MaxHeight
);
930 hid_draw_line (gc
, 0, PCB
->MaxHeight
, PCB
->MaxWidth
, PCB
->MaxHeight
);
931 hid_draw_destroy_gc (gc
);
939 gerber_make_gc (void)
941 hidGC gc
= (hidGC
) calloc (1, sizeof (struct gerber_gc_struct
));
942 gerberGC gerber_gc
= (gerberGC
)gc
;
944 gc
->hid
= &gerber_hid
;
945 gc
->hid_draw
= &gerber_graphics
;
947 gerber_gc
->cap
= Trace_Cap
;
953 gerber_destroy_gc (hidGC gc
)
959 gerber_use_mask (enum mask_mode mode
)
965 gerber_set_color (hidGC gc
, const char *name
)
967 gerberGC gerber_gc
= (gerberGC
)gc
;
969 if (strcmp (name
, "erase") == 0)
971 gerber_gc
->color
= 1;
972 gerber_gc
->erase
= 1;
973 gerber_gc
->drill
= 0;
975 else if (strcmp (name
, "drill") == 0)
977 gerber_gc
->color
= 1;
978 gerber_gc
->erase
= 0;
979 gerber_gc
->drill
= 1;
983 gerber_gc
->color
= 0;
984 gerber_gc
->erase
= 0;
985 gerber_gc
->drill
= 0;
990 gerber_set_line_cap (hidGC gc
, EndCapStyle style
)
992 gerberGC gerber_gc
= (gerberGC
)gc
;
994 gerber_gc
->cap
= style
;
998 gerber_set_line_width (hidGC gc
, Coord width
)
1000 gerberGC gerber_gc
= (gerberGC
)gc
;
1002 gerber_gc
->width
= width
;
1006 gerber_set_draw_xor (hidGC gc
, int xor_
)
1012 use_gc (hidGC gc
, int radius
)
1014 gerberGC gerber_gc
= (gerberGC
)gc
;
1019 if (radius
!= linewidth
|| lastcap
!= Round_Cap
)
1021 Aperture
*aptr
= findAperture (curr_aptr_list
, radius
, ROUND
);
1023 pcb_fprintf (stderr
, "error: aperture for radius %$mS type ROUND is null\n", radius
);
1024 else if (f
&& !is_drill
)
1025 fprintf (f
, "G54D%d*", aptr
->dCode
);
1027 lastcap
= Round_Cap
;
1030 else if (linewidth
!= gerber_gc
->width
|| lastcap
!= gerber_gc
->cap
)
1033 ApertureShape shape
;
1035 linewidth
= gerber_gc
->width
;
1036 lastcap
= gerber_gc
->cap
;
1037 switch (gerber_gc
->cap
)
1048 aptr
= findAperture (curr_aptr_list
, linewidth
, shape
);
1050 pcb_fprintf (stderr
, "error: aperture for width %$mS type %s is null\n",
1051 linewidth
, shape
== ROUND
? "ROUND" : "SQUARE");
1053 fprintf (f
, "G54D%d*", aptr
->dCode
);
1058 gerber_draw_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
1060 gerber_draw_line (gc
, x1
, y1
, x1
, y2
);
1061 gerber_draw_line (gc
, x1
, y1
, x2
, y1
);
1062 gerber_draw_line (gc
, x1
, y2
, x2
, y2
);
1063 gerber_draw_line (gc
, x2
, y1
, x2
, y2
);
1067 gerber_draw_line (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
1069 gerberGC gerber_gc
= (gerberGC
)gc
;
1072 if (x1
!= x2
&& y1
!= y2
&& gerber_gc
->cap
== Square_Cap
)
1075 double tx
, ty
, theta
;
1077 theta
= atan2 (y2
-y1
, x2
-x1
);
1079 /* T is a vector half a thickness long, in the direction of
1080 one of the corners. */
1081 tx
= gerber_gc
->width
/ 2.0 * cos (theta
+ M_PI
/4) * sqrt(2.0);
1082 ty
= gerber_gc
->width
/ 2.0 * sin (theta
+ M_PI
/4) * sqrt(2.0);
1084 x
[0] = x1
- tx
; y
[0] = y1
- ty
;
1085 x
[1] = x2
+ ty
; y
[1] = y2
- tx
;
1086 x
[2] = x2
+ tx
; y
[2] = y2
+ ty
;
1087 x
[3] = x1
- ty
; y
[3] = y1
+ tx
;
1089 x
[4] = x
[0]; y
[4] = y
[0];
1090 gerber_fill_polygon (gc
, 5, x
, y
);
1102 print_xcoord (f
, PCB
, lastX
);
1108 print_ycoord (f
, PCB
, lastY
);
1110 if ((x1
== x2
) && (y1
== y2
))
1111 fprintf (f
, "D03*\r\n");
1115 fprintf (f
, "D02*");
1119 print_xcoord (f
, PCB
, lastX
);
1124 print_ycoord (f
, PCB
, lastY
);
1126 fprintf (f
, "D01*\r\n");
1132 gerber_draw_arc (hidGC gc
, Coord cx
, Coord cy
, Coord width
, Coord height
,
1133 Angle start_angle
, Angle delta_angle
)
1135 gerberGC gerber_gc
= (gerberGC
)gc
;
1137 double arcStartX
, arcStopX
, arcStartY
, arcStopY
;
1139 /* we never draw zero-width lines */
1140 if (gerber_gc
->width
== 0)
1147 arcStartX
= cx
- width
* cos (TO_RADIANS (start_angle
));
1148 arcStartY
= cy
+ height
* sin (TO_RADIANS (start_angle
));
1150 /* I checked three different gerber viewers, and they all disagreed
1151 on how ellipses should be drawn. The spec just calls G74/G75
1152 "circular interpolation" so there's a chance it just doesn't
1153 support ellipses at all. Thus, we draw them out with line
1154 segments. Note that most arcs in pcb are circles anyway. */
1155 if (width
!= height
)
1158 Coord max
= width
> height
? width
: height
;
1159 Coord minr
= max
- gerber_gc
->width
/ 10;
1161 Coord x0
, y0
, x1
, y1
;
1165 step
= acos((double)minr
/(double)max
) * 180.0/M_PI
;
1168 nsteps
= abs(delta_angle
) / step
+ 1;
1169 step
= (double)delta_angle
/ nsteps
;
1173 angle
= start_angle
;
1177 x1
= cx
- width
* cos (TO_RADIANS (angle
+step
));
1178 y1
= cy
+ height
* sin (TO_RADIANS (angle
+step
));
1179 gerber_draw_line (gc
, x0
, y0
, x1
, y1
);
1187 arcStopX
= cx
- width
* cos (TO_RADIANS (start_angle
+ delta_angle
));
1188 arcStopY
= cy
+ height
* sin (TO_RADIANS (start_angle
+ delta_angle
));
1189 if (arcStartX
!= lastX
)
1193 print_xcoord (f
, PCB
, lastX
);
1195 if (arcStartY
!= lastY
)
1199 print_ycoord (f
, PCB
, lastY
);
1202 fprintf (f
, "D02*");
1204 metric
? "G75*G0%1dX%.0muY%.0muI%.0muJ%.0muD01*G01*\r\n" :
1205 "G75*G0%1dX%.0mcY%.0mcI%.0mcJ%.0mcD01*G01*\r\n",
1206 (delta_angle
< 0) ? 2 : 3,
1207 gerberX (PCB
, arcStopX
), gerberY (PCB
, arcStopY
),
1208 gerberXOffset (PCB
, cx
- arcStartX
),
1209 gerberYOffset (PCB
, cy
- arcStartY
));
1215 gerber_fill_circle (hidGC gc
, Coord cx
, Coord cy
, Coord radius
)
1217 gerberGC gerber_gc
= (gerberGC
)gc
;
1222 radius
= 50 * round (radius
/ 50.0);
1223 use_gc (gc
, radius
);
1228 if (n_pending_drills
>= max_pending_drills
)
1230 max_pending_drills
+= 100;
1231 pending_drills
= (PendingDrills
*) realloc(pending_drills
,
1232 max_pending_drills
*
1233 sizeof (pending_drills
[0]));
1235 pending_drills
[n_pending_drills
].x
= cx
;
1236 pending_drills
[n_pending_drills
].y
= cy
;
1237 pending_drills
[n_pending_drills
].diam
= radius
* 2;
1241 else if (gerber_gc
->drill
&& !flash_drills
)
1246 print_xcoord (f
, PCB
, lastX
);
1251 print_ycoord (f
, PCB
, lastY
);
1253 fprintf (f
, "D03*\r\n");
1257 gerber_fill_polygon (hidGC gc
, int n_coords
, Coord
*x
, Coord
*y
)
1262 Coord startX
= 0, startY
= 0;
1264 if (is_mask
&& current_mask
== HID_MASK_BEFORE
)
1267 use_gc (gc
, 10 * 100);
1270 fprintf (f
, "G36*\r\n");
1271 for (i
= 0; i
< n_coords
; i
++)
1277 print_xcoord (f
, PCB
, lastX
);
1283 print_ycoord (f
, PCB
, lastY
);
1291 fprintf (f
, "D02*");
1294 fprintf (f
, "D01*\r\n");
1297 if (startX
!= lastX
)
1301 print_xcoord (f
, PCB
, startX
);
1303 if (startY
!= lastY
)
1307 print_ycoord (f
, PCB
, lastY
);
1310 fprintf (f
, "D01*\r\n");
1311 fprintf (f
, "G37*\r\n");
1315 gerber_fill_rect (hidGC gc
, Coord x1
, Coord y1
, Coord x2
, Coord y2
)
1327 gerber_fill_polygon (gc
, 5, x
, y
);
1331 gerber_calibrate (double xval
, double yval
)
1337 gerber_set_crosshair (int x
, int y
, int action
)
1344 memset (&gerber_hid
, 0, sizeof (gerber_hid
));
1345 memset (&gerber_graphics
, 0, sizeof (gerber_graphics
));
1346 memset (&gerber_graphics_class
, 0, sizeof (gerber_graphics_class
));
1348 common_nogui_init (&gerber_hid
);
1350 gerber_hid
.struct_size
= sizeof (gerber_hid
);
1351 gerber_hid
.name
= "gerber";
1352 gerber_hid
.description
= "RS-274X (Gerber) export";
1353 gerber_hid
.exporter
= 1;
1355 gerber_hid
.get_export_options
= gerber_get_export_options
;
1356 gerber_hid
.do_export
= gerber_do_export
;
1357 gerber_hid
.parse_arguments
= gerber_parse_arguments
;
1358 gerber_hid
.calibrate
= gerber_calibrate
;
1359 gerber_hid
.set_crosshair
= gerber_set_crosshair
;
1361 gerber_hid
.graphics
= &gerber_graphics
;
1363 common_draw_helpers_class_init (&gerber_graphics_class
);
1365 gerber_graphics_class
.set_layer
= gerber_set_layer
;
1366 gerber_graphics_class
.make_gc
= gerber_make_gc
;
1367 gerber_graphics_class
.destroy_gc
= gerber_destroy_gc
;
1368 gerber_graphics_class
.use_mask
= gerber_use_mask
;
1369 gerber_graphics_class
.set_color
= gerber_set_color
;
1370 gerber_graphics_class
.set_line_cap
= gerber_set_line_cap
;
1371 gerber_graphics_class
.set_line_width
= gerber_set_line_width
;
1372 gerber_graphics_class
.set_draw_xor
= gerber_set_draw_xor
;
1373 gerber_graphics_class
.draw_line
= gerber_draw_line
;
1374 gerber_graphics_class
.draw_arc
= gerber_draw_arc
;
1375 gerber_graphics_class
.draw_rect
= gerber_draw_rect
;
1376 gerber_graphics_class
.fill_circle
= gerber_fill_circle
;
1377 gerber_graphics_class
.fill_polygon
= gerber_fill_polygon
;
1378 gerber_graphics_class
.fill_rect
= gerber_fill_rect
;
1380 gerber_graphics
.klass
= &gerber_graphics_class
;
1381 common_draw_helpers_init (&gerber_graphics
);
1383 hid_register_hid (&gerber_hid
);