pcb 4.1.1
An interactive printed circuit board layout editor.

gerber.c

Go to the documentation of this file.
00001 #ifdef HAVE_CONFIG_H
00002 #include "config.h"
00003 #endif
00004 
00005 #include <stdio.h>
00006 #include <stdarg.h>
00007 #include <stdlib.h>
00008 #include <unistd.h>
00009 #include <sys/types.h>
00010 #include <string.h>
00011 #include <assert.h>
00012 #include <ctype.h>
00013 #include <math.h>
00014 
00015 #ifdef HAVE_PWD_H
00016 #include <pwd.h>
00017 #endif
00018 
00019 #include <time.h>
00020 
00021 #include "config.h"
00022 #include "global.h"
00023 #include "data.h"
00024 #include "misc.h"
00025 #include "error.h"
00026 #include "draw.h"
00027 #include "pcb-printf.h"
00028 
00029 #include "hid.h"
00030 #include "hid_draw.h"
00031 #include "../hidint.h"
00032 #include "hid/common/hidnogui.h"
00033 #include "hid/common/draw_helpers.h"
00034 #include "hid/common/hidinit.h"
00035 
00036 #ifdef HAVE_LIBDMALLOC
00037 #include <dmalloc.h>
00038 #endif
00039 
00040 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented Gerber function %s.\n", __FUNCTION__); abort()
00041 
00042 /*----------------------------------------------------------------------------*/
00043 /* Function prototypes                                                        */
00044 /*----------------------------------------------------------------------------*/
00045 
00046 static HID_Attribute * gerber_get_export_options (int *n);
00047 static void gerber_do_export (HID_Attr_Val * options);
00048 static void gerber_parse_arguments (int *argc, char ***argv);
00049 static int gerber_set_layer (const char *name, int group, int empty);
00050 static hidGC gerber_make_gc (void);
00051 static void gerber_destroy_gc (hidGC gc);
00052 static void gerber_use_mask (enum mask_mode mode);
00053 static void gerber_set_color (hidGC gc, const char *name);
00054 static void gerber_set_line_cap (hidGC gc, EndCapStyle style);
00055 static void gerber_set_line_width (hidGC gc, Coord width);
00056 static void gerber_set_draw_xor (hidGC gc, int _xor);
00057 static void gerber_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2);
00058 static void gerber_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle);
00059 static void gerber_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2);
00060 static void gerber_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius);
00061 static void gerber_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2);
00062 static void gerber_calibrate (double xval, double yval);
00063 static void gerber_set_crosshair (int x, int y, int action);
00064 static void gerber_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y);
00065 
00066 /*----------------------------------------------------------------------------*/
00067 /* Utility routines                                                           */
00068 /*----------------------------------------------------------------------------*/
00069 
00070 /* These are for films */
00071 #define gerberX(pcb, x) ((Coord) (x))
00072 #define gerberY(pcb, y) ((Coord) ((pcb)->MaxHeight - (y)))
00073 #define gerberXOffset(pcb, x) ((Coord) (x))
00074 #define gerberYOffset(pcb, y) ((Coord) (-(y)))
00075 
00076 /* These are for drills */
00077 #define gerberDrX(pcb, x) ((Coord) (x))
00078 #define gerberDrY(pcb, y) ((Coord) ((pcb)->MaxHeight - (y)))
00079 
00080 /*----------------------------------------------------------------------------*/
00081 /* Private data structures                                                    */
00082 /*----------------------------------------------------------------------------*/
00083 
00084 static int verbose;
00085 static int all_layers;
00086 static int metric;
00087 static char *x_convspec, *y_convspec;
00088 static int is_mask, was_drill;
00089 static int is_drill;
00090 static enum mask_mode current_mask;
00091 static int flash_drills;
00092 static int copy_outline_mode;
00093 static int name_style;
00094 static LayerType *outline_layer;
00095 
00096 #define print_xcoord(file, pcb, val)\
00097         pcb_fprintf(file, x_convspec, gerberX(pcb, val))
00098 
00099 #define print_ycoord(file, pcb, val)\
00100         pcb_fprintf(file, y_convspec, gerberY(pcb, val))
00101 
00102 enum ApertureShape
00103 {
00104   ROUND,                        /* Shaped like a circle */
00105   OCTAGON,                      /* octagonal shape */
00106   SQUARE,                       /* Shaped like a square */
00107   ROUNDCLEAR,                   /* clearance in negatives */
00108   SQUARECLEAR,
00109   THERMAL                       /* negative thermal relief */
00110 };
00111 typedef enum ApertureShape ApertureShape;
00112 
00113 /* This is added to the global aperture array indexes to get gerber
00114    dcode and macro numbers.  */
00115 #define DCODE_BASE 11
00116 
00117 typedef struct aperture
00118 {
00119   int dCode;                    /* The RS-274X D code */
00120   Coord width;          /* Size in pcb units */
00121   ApertureShape shape;          /* ROUND/SQUARE etc */
00122   struct aperture *next;
00123 }
00124 Aperture;
00125 
00126 typedef struct 
00127 {
00128   Aperture *data;
00129   int count;
00130 } ApertureList;
00131 
00132 static ApertureList *layer_aptr_list;
00133 static ApertureList *curr_aptr_list;
00134 static int layer_list_max;
00135 static int layer_list_idx;
00136 
00137 typedef struct
00138 {
00139   Coord diam;
00140   Coord x;
00141   Coord y;
00142 } PendingDrills;
00143 PendingDrills *pending_drills = NULL;
00144 int n_pending_drills = 0, max_pending_drills = 0;
00145 
00146 /*----------------------------------------------------------------------------*/
00147 /* Defined Constants                                                          */
00148 /*----------------------------------------------------------------------------*/
00149 #define AUTO_OUTLINE_WIDTH MIL_TO_COORD(8)       /* Auto-geneated outline width of 8 mils */
00150 
00151 /*----------------------------------------------------------------------------*/
00152 /* Aperture Routines                                                          */
00153 /*----------------------------------------------------------------------------*/
00154 
00155 /* Initialize aperture list */
00156 static void
00157 initApertureList (ApertureList *list)
00158 {
00159   list->data = NULL;
00160   list->count = 0;
00161 }
00162 
00163 static void
00164 deinitApertureList (ApertureList *list)
00165 {
00166   Aperture *search = list->data;
00167   Aperture *next;
00168   while (search)
00169     {
00170       next = search->next;
00171       free(search);
00172       search = next;
00173     }
00174   initApertureList (list);
00175 }
00176 
00177 static int aperture_count;
00178 
00179 static void resetApertures()
00180 {
00181   int i;
00182   for (i = 0; i < layer_list_max; ++i)
00183     deinitApertureList (&layer_aptr_list[i]);
00184   free (layer_aptr_list);
00185   layer_aptr_list = NULL;
00186   curr_aptr_list  = NULL;
00187   layer_list_max = 0;
00188   layer_list_idx = 0;
00189   aperture_count = 0;
00190 }
00191 
00192 /* Create and add a new aperture to the list */
00193 static Aperture *
00194 addAperture (ApertureList *list, Coord width, ApertureShape shape)
00195 {
00196 
00197   Aperture *app = (Aperture *) malloc (sizeof *app);
00198   if (app == NULL)
00199     return NULL;
00200 
00201   app->width = width;
00202   app->shape = shape;
00203   app->dCode = DCODE_BASE + aperture_count++;
00204   app->next  = list->data;
00205 
00206   list->data = app;
00207   ++list->count;
00208 
00209   return app;
00210 }
00211 
00212 /* Fetch an aperture from the list with the specified
00213  *  width/shape, creating a new one if none exists */
00214 static Aperture *
00215 findAperture (ApertureList *list, Coord width, ApertureShape shape)
00216 {
00217   Aperture *search;
00218 
00219   /* we never draw zero-width lines */
00220   if (width == 0)
00221     return NULL;
00222 
00223   /* Search for an appropriate aperture. */
00224   for (search = list->data; search; search = search->next)
00225     if (search->width == width && search->shape == shape)
00226       return search;
00227 
00228   /* Failing that, create a new one */
00229   return addAperture (list, width, shape);
00230 }
00231 
00232 /* Output aperture data to the file */
00233 static void
00234 fprintAperture (FILE *f, Aperture *aptr)
00235 {
00236   switch (aptr->shape)
00237     {
00238     case ROUND:
00239       pcb_fprintf (f, metric ? "%%ADD%dC,%.3`mm*%%\r\n" : "%%ADD%dC,%.4`mi*%%\r\n", aptr->dCode, aptr->width);
00240       break;
00241     case SQUARE:
00242       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);
00243       break;
00244     case OCTAGON:
00245       pcb_fprintf (f, metric ? "%%AMOCT%d*5,0,8,0,0,%.3`mm,22.5*%%\r\n"
00246                "%%ADD%dOCT%d*%%\r\n" : "%%AMOCT%d*5,0,8,0,0,%.3`mm,22.5*%%\r\n"
00247                "%%ADD%dOCT%d*%%\r\n", aptr->dCode,
00248                (Coord) ((double) aptr->width / COS_22_5_DEGREE), aptr->dCode,
00249                aptr->dCode);
00250       break;
00251 #if 0
00252     case THERMAL:
00253       fprintf (f, "%%AMTHERM%d*7,0,0,%.4f,%.4f,%.4f,45*%%\r\n"
00254                "%%ADD%dTHERM%d*%%\r\n", dCode, gap / 100000.0,
00255                width / 100000.0, finger / 100000.0, dCode, dCode);
00256       break;
00257     case ROUNDCLEAR:
00258       fprintf (f, "%%ADD%dC,%.4fX%.4f*%%\r\n",
00259                dCode, gap / 100000.0, width / 100000.0);
00260       break;
00261     case SQUARECLEAR:
00262       fprintf (f, "%%ADD%dR,%.4fX%.4fX%.4fX%.4f*%%\r\n",
00263                dCode, gap / 100000.0, gap / 100000.0,
00264                width / 100000.0, width / 100000.0);
00265       break;
00266 #else
00267     default:
00268       break;
00269 #endif
00270     }
00271 }
00272 
00273 /* Set the aperture list for the current layer,
00274  * expanding the list buffer if needed  */
00275 static ApertureList *
00276 setLayerApertureList (int layer_idx)
00277 {
00278   if (layer_idx >= layer_list_max)
00279     {
00280       int i = layer_list_max;
00281       layer_list_max  = 2 * (layer_idx + 1);
00282       layer_aptr_list = (ApertureList *)
00283                         realloc (layer_aptr_list, layer_list_max * sizeof (*layer_aptr_list));
00284       for (; i < layer_list_max; ++i)
00285         initApertureList (&layer_aptr_list[i]);
00286     }
00287   curr_aptr_list = &layer_aptr_list[layer_idx];
00288   return curr_aptr_list;
00289 }
00290 
00291 /* --------------------------------------------------------------------------- */
00292 
00293 static HID gerber_hid;
00294 static HID_DRAW gerber_graphics;
00295 
00296 typedef struct hid_gc_struct
00297 {
00298   EndCapStyle cap;
00299   int width;
00300   int color;
00301   int erase;
00302   int drill;
00303 } hid_gc_struct;
00304 
00305 static FILE *f = NULL;
00306 static char *filename = NULL;
00307 static char *filesuff = NULL;
00308 static char *layername = NULL;
00309 static int lncount = 0;
00310 
00311 static int finding_apertures = 0;
00312 static int pagecount = 0;
00313 static int linewidth = -1;
00314 static int lastgroup = -1;
00315 static int lastcap = -1;
00316 static int print_group[MAX_GROUP];
00317 static int print_layer[MAX_ALL_LAYER];
00318 static int lastX, lastY;        /* the last X and Y coordinate */
00319 
00320 static const char *copy_outline_names[] = {
00321 #define COPY_OUTLINE_NONE 0
00322   "none",
00323 #define COPY_OUTLINE_MASK 1
00324   "mask",
00325 #define COPY_OUTLINE_SILK 2
00326   "silk",
00327 #define COPY_OUTLINE_ALL 3
00328   "all",
00329   NULL
00330 };
00331 
00332 static const char *name_style_names[] = {
00333 #define NAME_STYLE_FIXED 0
00334   "fixed",
00335 #define NAME_STYLE_SINGLE 1
00336   "single",
00337 #define NAME_STYLE_FIRST 2
00338   "first",
00339 #define NAME_STYLE_EAGLE 3
00340   "eagle",
00341 #define NAME_STYLE_HACKVANA 4
00342   "hackvana",
00343 #define NAME_STYLE_OSHPARK 5
00344   "oshpark",
00345   NULL
00346 };
00347 
00348 static HID_Attribute gerber_options[] = {
00349 
00350 /* %start-doc options "90 Gerber Export"
00351 @ftable @code
00352 @item --gerberfile <string>
00353 Gerber output file prefix. Parameter @code{<string>} can include a path.
00354 @end ftable
00355 %end-doc
00356 */
00357   {"gerberfile", "Gerber output file base",
00358    HID_String, 0, 0, {0, 0, 0}, 0, 0},
00359 #define HA_gerberfile 0
00360 
00361 /* %start-doc options "90 Gerber Export"
00362 @ftable @code
00363 @item --all-layers
00364 Output contains all layers, even empty ones.
00365 @end ftable
00366 %end-doc
00367 */
00368   {"all-layers", "Output all layers, even empty ones",
00369    HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
00370 #define HA_all_layers 1
00371 
00372 /* %start-doc options "90 Gerber Export"
00373 @ftable @code
00374 @item --verbose
00375 Print file names and aperture counts on stdout.
00376 @end ftable
00377 %end-doc
00378 */
00379   {"verbose", "Print file names and aperture counts on stdout",
00380    HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
00381 #define HA_verbose 2
00382 
00383 /* %start-doc options "90 Gerber Export"
00384 @ftable @code
00385 @item --metric
00386 Generate metric Gerber and drill files
00387 @end ftable
00388 %end-doc
00389 */
00390   {"metric", "Generate metric Gerber and drill files",
00391    HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
00392 #define HA_metric 3
00393 
00394 /* %start-doc options "90 Gerber Export"
00395 @ftable @code
00396 @item --copy-outline <string>
00397 Copy the outline onto other layers.
00398 Parameter @code{<string>} can be @samp{none}, @samp{mask},
00399 @samp{silk} or @samp{all}.
00400 @end ftable
00401 %end-doc
00402 */
00403   {"copy-outline", "Copy outline onto other layers",
00404    HID_Enum, 0, 0, {0, 0, 0}, copy_outline_names, 0},
00405 #define HA_copy_outline 4
00406 
00407 /* %start-doc options "90 Gerber Export"
00408 @ftable @code
00409 @item --name-style <string>
00410 Naming style for individual gerber files.
00411 Parameter @code{<string>} can be @samp{fixed}, @samp{single},
00412 @samp{first}, @samp{eagle}, @samp{hackvana} or @samp{oshpark}.
00413 @end ftable
00414 %end-doc
00415 */
00416   {"name-style", "Naming style for individual gerber files",
00417    HID_Enum, 0, 0, {0, 0, 0}, name_style_names, 0},
00418 #define HA_name_style 5
00419 };
00420 
00421 #define NUM_OPTIONS (sizeof(gerber_options)/sizeof(gerber_options[0]))
00422 
00423 static HID_Attr_Val gerber_values[NUM_OPTIONS];
00424 
00425 static HID_Attribute *
00426 gerber_get_export_options (int *n)
00427 {
00428   static char *last_made_filename = NULL;
00429   if (PCB) derive_default_filename(PCB->Filename, &gerber_options[HA_gerberfile], "", &last_made_filename);
00430 
00431   if (n)
00432     *n = NUM_OPTIONS;
00433   return gerber_options;
00434 }
00435 
00436 static int
00437 layer_stack_sort (const void *va, const void *vb)
00438 {
00439   int a_layer = *(int *) va;
00440   int b_layer = *(int *) vb;
00441   int a_group = GetLayerGroupNumberByNumber (a_layer);
00442   int b_group = GetLayerGroupNumberByNumber (b_layer);
00443 
00444   if (b_group != a_group)
00445     return b_group - a_group;
00446 
00447   return b_layer - a_layer;
00448 }
00449 
00450 static void
00451 maybe_close_f (FILE *f)
00452 {
00453   if (f)
00454     {
00455       if (was_drill)
00456         fprintf (f, "M30\r\n");
00457       else
00458         fprintf (f, "M02*\r\n");
00459       fclose (f);
00460     }
00461 }
00462 
00463 static BoxType region;
00464 
00465 /* Very similar to layer_type_to_file_name() but appends only a
00466    three-character suffix compatible with Eagle's defaults.  */
00467 static void
00468 assign_eagle_file_suffix (char *dest, int idx)
00469 {
00470   int group;
00471   int nlayers;
00472   char *suff = "out";
00473 
00474   switch (idx)
00475     {
00476     case SL (SILK,      TOP):    suff = "plc"; break;
00477     case SL (SILK,      BOTTOM): suff = "pls"; break;
00478     case SL (MASK,      TOP):    suff = "stc"; break;
00479     case SL (MASK,      BOTTOM): suff = "sts"; break;
00480     case SL (PDRILL,    0):      suff = "drd"; break;
00481     case SL (UDRILL,    0):      suff = "dru"; break;
00482     case SL (PASTE,     TOP):    suff = "crc"; break;
00483     case SL (PASTE,     BOTTOM): suff = "crs"; break;
00484     case SL (INVISIBLE, 0):      suff = "inv"; break;
00485     case SL (FAB,       0):      suff = "fab"; break;
00486     case SL (ASSY,      TOP):    suff = "ast"; break;
00487     case SL (ASSY,      BOTTOM): suff = "asb"; break;
00488 
00489     default:
00490       group = GetLayerGroupNumberByNumber(idx);
00491       nlayers = PCB->LayerGroups.Number[group];
00492       if (group == GetLayerGroupNumberBySide(TOP_SIDE)) /* Component */
00493         {
00494           suff = "cmp";
00495         }
00496       else if (group == GetLayerGroupNumberBySide(BOTTOM_SIDE)) /* Solder */
00497         {
00498           suff = "sol";
00499         }
00500       else if (nlayers == 1
00501                && (strcmp (PCB->Data->Layer[idx].Name, "route") == 0 ||
00502                    strcmp (PCB->Data->Layer[idx].Name, "outline") == 0))
00503         {
00504           suff = "oln";
00505         }
00506       else
00507         {
00508           static char buf[20];
00509           sprintf (buf, "ly%d", group);
00510           suff = buf;
00511         }
00512       break;
00513     }
00514 
00515   strcpy (dest, suff);
00516 }
00517 
00518 /* Very similar to layer_type_to_file_name() but appends only a
00519    three-character suffix compatible with Hackvana's naming requirements  */
00520 static void
00521 assign_hackvana_file_suffix (char *dest, int idx)
00522 {
00523   int group;
00524   int nlayers;
00525   char *suff = "defau.out";
00526 
00527   switch (idx)
00528     {
00529     case SL (SILK,      TOP):    suff = "gto"; break;
00530     case SL (SILK,      BOTTOM): suff = "gbo"; break;
00531     case SL (MASK,      TOP):    suff = "gts"; break;
00532     case SL (MASK,      BOTTOM): suff = "gbs"; break;
00533     case SL (PDRILL,    0):      suff = "drl"; break;
00534     case SL (UDRILL,    0):
00535       suff = "_NPTH.drl";
00536       break;
00537     case SL (PASTE,     TOP):    suff = "gtp"; break;
00538     case SL (PASTE,     BOTTOM): suff = "gbp"; break;
00539     case SL (INVISIBLE, 0):      suff = "inv"; break;
00540     case SL (FAB,       0):      suff = "fab"; break;
00541     case SL (ASSY,      TOP):    suff = "ast"; break;
00542     case SL (ASSY,      BOTTOM): suff = "asb"; break;
00543 
00544     default:
00545       group = GetLayerGroupNumberByNumber(idx);
00546       nlayers = PCB->LayerGroups.Number[group];
00547       if (group == GetLayerGroupNumberBySide(TOP_SIDE))
00548       {
00549         suff = "gtl";
00550       }
00551       else if (group == GetLayerGroupNumberBySide(BOTTOM_SIDE))
00552       {
00553         suff = "gbl";
00554       }
00555       else if (nlayers == 1
00556         && (strcmp (PCB->Data->Layer[idx].Name, "route") == 0 ||
00557             strcmp (PCB->Data->Layer[idx].Name, "outline") == 0))
00558       {
00559         suff = "gm1";
00560       }
00561       else
00562       {
00563         static char buf[20];
00564         sprintf (buf, "g%d", group);
00565         suff = buf;
00566       }
00567       break;
00568     }
00569 
00570   strcpy (dest, suff);
00571 }
00572 
00584 static void
00585 assign_oshpark_file_suffix (char *dest, int idx)
00586 {
00587   int group;
00588   int nlayers;
00589   char *suff = "default.out";
00590 
00591   switch (idx)
00592     {
00593     case SL (SILK,      TOP):    suff = "GTO"; break;
00594     case SL (SILK,      BOTTOM): suff = "GBO"; break;
00595     case SL (MASK,      TOP):    suff = "GTS"; break;
00596     case SL (MASK,      BOTTOM): suff = "GBS"; break;
00597     case SL (PDRILL,    0):      suff = "XLN"; break;
00598     case SL (UDRILL,    0):      suff = "TXT"; break;
00599     case SL (PASTE,     TOP):    suff = "gtp"; break;
00600     case SL (PASTE,     BOTTOM): suff = "gbp"; break;
00601     case SL (INVISIBLE, 0):      suff = "inv"; break;
00602     case SL (FAB,       0):      suff = "fab"; break;
00603     case SL (ASSY,      TOP):    suff = "ast"; break;
00604     case SL (ASSY,      BOTTOM): suff = "asb"; break;
00605 
00606     default:
00607       group = GetLayerGroupNumberByNumber(idx);
00608       nlayers = PCB->LayerGroups.Number[group];
00609       if (group == GetLayerGroupNumberBySide(TOP_SIDE))
00610       {
00611         suff = "GTL";
00612       }
00613       else if (group == GetLayerGroupNumberBySide(BOTTOM_SIDE))
00614       {
00615         suff = "GBL";
00616       }
00617       else if (nlayers == 1
00618         && (strcmp (PCB->Data->Layer[idx].Name, "route") == 0 ||
00619             strcmp (PCB->Data->Layer[idx].Name, "outline") == 0))
00620       {
00621         suff = "GKO";
00622       }
00623       else
00624       {
00625         static char buf[20];
00626         sprintf (buf, "G%dL", group);
00627         suff = buf;
00628       }
00629       break;
00630     }
00631 
00632   strcpy (dest, suff);
00633 }
00634 
00635 static void
00636 assign_file_suffix (char *dest, int idx, const char *layer_name)
00637 {
00638   int fns_style;
00639   const char *sext = ".gbr";
00640 
00641   switch (name_style)
00642     {
00643     default:
00644     case NAME_STYLE_FIXED:  fns_style = FNS_fixed;  break;
00645     case NAME_STYLE_SINGLE: fns_style = FNS_single; break;
00646     case NAME_STYLE_FIRST:  fns_style = FNS_first;  break;
00647     case NAME_STYLE_EAGLE:
00648       assign_eagle_file_suffix (dest, idx);
00649       return;
00650     case NAME_STYLE_HACKVANA:
00651       assign_hackvana_file_suffix (dest, idx);
00652       return;
00653     case NAME_STYLE_OSHPARK:
00654       assign_oshpark_file_suffix (dest, idx);
00655       return;
00656     }
00657 
00658   switch (idx)
00659     {
00660     case SL (PDRILL, 0):
00661       sext = ".cnc";
00662       break;
00663     case SL (UDRILL, 0):
00664       sext = ".cnc";
00665       break;
00666     }
00667 
00668   strcpy (dest, layer_type_to_file_name_ex (idx, fns_style, layer_name));
00669   strcat (dest, sext);
00670 }
00671 
00672 static void
00673 gerber_do_export (HID_Attr_Val * options)
00674 {
00675   const char *fnbase;
00676   int i;
00677   static int saved_layer_stack[MAX_LAYER];
00678   int save_ons[MAX_ALL_LAYER];
00679   FlagType save_thindraw;
00680 
00681   save_thindraw = PCB->Flags;
00682   CLEAR_FLAG(THINDRAWFLAG, PCB);
00683   CLEAR_FLAG(THINDRAWPOLYFLAG, PCB);
00684   CLEAR_FLAG(CHECKPLANESFLAG, PCB);
00685 
00686   if (!options)
00687     {
00688       gerber_get_export_options (NULL);
00689       for (i = 0; i < NUM_OPTIONS; i++)
00690         gerber_values[i] = gerber_options[i].default_val;
00691       options = gerber_values;
00692     }
00693 
00694   fnbase = options[HA_gerberfile].str_value;
00695   if (!fnbase)
00696     fnbase = "pcb-out";
00697 
00698   verbose = options[HA_verbose].int_value;
00699   metric = options[HA_metric].int_value;
00700   if (metric) {
00701           x_convspec = "X%.0mu";
00702           y_convspec = "Y%.0mu";
00703   } else {
00704           x_convspec = "X%.0mc";
00705           y_convspec = "Y%.0mc";
00706   }
00707   all_layers = options[HA_all_layers].int_value;
00708 
00709   copy_outline_mode = options[HA_copy_outline].int_value;
00710   name_style = options[HA_name_style].int_value;
00711 
00712   outline_layer = NULL;
00713 
00714   for (i = 0; i < max_copper_layer; i++)
00715     {
00716       LayerType *layer = PCB->Data->Layer + i;
00717       if (strcmp (layer->Name, "outline") == 0 ||
00718           strcmp (layer->Name, "route") == 0)
00719         {
00720           outline_layer = layer;
00721         }
00722     }
00723 
00724   i = strlen (fnbase);
00725   filename = (char *)realloc (filename, i + 40);
00726   strcpy (filename, fnbase);
00727   strcat (filename, ".");
00728   filesuff = filename + strlen (filename);
00729 
00730   if (all_layers)
00731     {
00732       memset (print_group, 1, sizeof (print_group));
00733       memset (print_layer, 1, sizeof (print_layer));
00734     }
00735   else
00736     {
00737       memset (print_group, 0, sizeof (print_group));
00738       memset (print_layer, 0, sizeof (print_layer));
00739     }
00740 
00741   hid_save_and_show_layer_ons (save_ons);
00742   for (i = 0; i < max_copper_layer; i++)
00743     {
00744       LayerType *layer = PCB->Data->Layer + i;
00745       if (layer->LineN || layer->TextN || layer->ArcN || layer->PolygonN)
00746         print_group[GetLayerGroupNumberByNumber (i)] = 1;
00747     }
00748   print_group[GetLayerGroupNumberBySide (BOTTOM_SIDE)] = 1;
00749   print_group[GetLayerGroupNumberBySide (TOP_SIDE)] = 1;
00750   for (i = 0; i < max_copper_layer; i++)
00751     if (print_group[GetLayerGroupNumberByNumber (i)])
00752       print_layer[i] = 1;
00753 
00754   memcpy (saved_layer_stack, LayerStack, sizeof (LayerStack));
00755   qsort (LayerStack, max_copper_layer, sizeof (LayerStack[0]), layer_stack_sort);
00756   linewidth = -1;
00757   lastcap = -1;
00758   lastgroup = -1;
00759 
00760   region.X1 = 0;
00761   region.Y1 = 0;
00762   region.X2 = PCB->MaxWidth;
00763   region.Y2 = PCB->MaxHeight;
00764 
00765   pagecount = 1;
00766   resetApertures ();
00767 
00768   lastgroup = -1;
00769   layer_list_idx = 0;
00770   finding_apertures = 1;
00771   hid_expose_callback (&gerber_hid, &region, 0);
00772 
00773   layer_list_idx = 0;
00774   finding_apertures = 0;
00775   hid_expose_callback (&gerber_hid, &region, 0);
00776 
00777   memcpy (LayerStack, saved_layer_stack, sizeof (LayerStack));
00778 
00779   maybe_close_f (f);
00780   f = NULL;
00781   hid_restore_layer_ons (save_ons);
00782   PCB->Flags = save_thindraw;
00783 }
00784 
00785 static void
00786 gerber_parse_arguments (int *argc, char ***argv)
00787 {
00788   hid_register_attributes (gerber_options, NUM_OPTIONS);
00789   hid_parse_command_line (argc, argv);
00790 }
00791 
00792 static int
00793 drill_sort (const void *va, const void *vb)
00794 {
00795   PendingDrills *a = (PendingDrills *) va;
00796   PendingDrills *b = (PendingDrills *) vb;
00797   if (a->diam != b->diam)
00798     return a->diam - b->diam;
00799   if (a->x != b->x)
00800     return a->x - b->x;
00801   return a->y - b->y;
00802 }
00803 
00804 static int
00805 gerber_set_layer (const char *name, int group, int empty)
00806 {
00807   int want_outline;
00808   char *cp;
00809   int idx = (group >= 0
00810              && group <
00811              max_group) ? PCB->LayerGroups.Entries[group][0] : group;
00812 
00813   if (name == NULL)
00814     name = PCB->Data->Layer[idx].Name;
00815 
00816   if (idx >= 0 && idx < max_copper_layer && !print_layer[idx])
00817     return 0;
00818 
00819   if (strcmp (name, "invisible") == 0)
00820     return 0;
00821   if (SL_TYPE (idx) == SL_ASSY)
00822     return 0;
00823 
00824   flash_drills = 0;
00825   if (strcmp (name, "outline") == 0 ||
00826       strcmp (name, "route") == 0)
00827     flash_drills = 1;
00828 
00829   if (is_drill && n_pending_drills)
00830     {
00831       int i;
00832       /* dump pending drills in sequence */
00833       qsort (pending_drills, n_pending_drills, sizeof (pending_drills[0]),
00834              drill_sort);
00835       for (i = 0; i < n_pending_drills; i++)
00836         {
00837           if (i == 0 || pending_drills[i].diam != pending_drills[i - 1].diam)
00838             {
00839               Aperture *ap = findAperture (curr_aptr_list, pending_drills[i].diam, ROUND);
00840               fprintf (f, "T%02d\r\n", ap->dCode);
00841             }
00842           pcb_fprintf (f, metric ? "X%06.0muY%06.0mu\r\n" : "X%06.0mtY%06.0mt\r\n",
00843                    gerberDrX (PCB, pending_drills[i].x),
00844                    gerberDrY (PCB, pending_drills[i].y));
00845         }
00846       free (pending_drills);
00847       n_pending_drills = max_pending_drills = 0;
00848       pending_drills = NULL;
00849     }
00850 
00851   is_drill = (SL_TYPE (idx) == SL_PDRILL || SL_TYPE (idx) == SL_UDRILL);
00852   is_mask = (SL_TYPE (idx) == SL_MASK);
00853   current_mask = HID_MASK_OFF;
00854 #if 0
00855   printf ("Layer %s group %d drill %d mask %d\n", name, group, is_drill,
00856           is_mask);
00857 #endif
00858 
00859   if (group < 0 || group != lastgroup)
00860     {
00861       time_t currenttime;
00862       char utcTime[64];
00863 #ifdef HAVE_GETPWUID
00864       struct passwd *pwentry;
00865 #endif
00866       ApertureList *aptr_list;
00867       Aperture *search;
00868 
00869       lastgroup = group;
00870       lastX = -1;
00871       lastY = -1;
00872       linewidth = -1;
00873       lastcap = -1;
00874 
00875       aptr_list = setLayerApertureList (layer_list_idx++);
00876 
00877       if (finding_apertures)
00878         goto emit_outline;
00879 
00880       if (aptr_list->count == 0 && !all_layers)
00881         return 0;
00882 
00883       maybe_close_f (f);
00884       f = NULL;
00885 
00886       pagecount++;
00887       assign_file_suffix (filesuff, idx, name);
00888       f = fopen (filename, "wb");   /* Binary needed to force CR-LF */
00889       if (f == NULL) 
00890         {
00891           Message ( "Error:  Could not open %s for writing.\n", filename);
00892           return 1;
00893         }
00894 
00895       was_drill = is_drill;
00896 
00897       if (verbose)
00898         {
00899           int c = aptr_list->count;
00900           printf ("Gerber: %d aperture%s in %s\n", c,
00901                   c == 1 ? "" : "s", filename);
00902         }
00903 
00904       if (is_drill)
00905         {
00906           /* We omit the ,TZ here because we are not omitting trailing zeros.  Our format is
00907              always six-digit 0.1 mil or µm resolution (i.e. 001100 = 0.11" or 1.1mm)*/
00908           fprintf (f, "M48\r\n");
00909           fprintf (f, metric ? "METRIC,000.000\r\n" : "INCH\r\n");
00910           for (search = aptr_list->data; search; search = search->next)
00911                   pcb_fprintf (f, metric ? "T%02dC%.3`mm\r\n" : "T%02dC%.3`mi\r\n", search->dCode, search->width);
00912           fprintf (f, "%%\r\n");
00913           /* FIXME */
00914           return 1;
00915         }
00916 
00917       fprintf (f, "G04 start of page %d for group %d idx %d *\r\n",
00918                pagecount, group, idx);
00919 
00920       /* Create a portable timestamp. */
00921       currenttime = time (NULL);
00922       {
00923         /* avoid gcc complaints */
00924         const char *fmt = "%c UTC";
00925         strftime (utcTime, sizeof utcTime, fmt, gmtime (&currenttime));
00926       }
00927       /* Print a cute file header at the beginning of each file. */
00928       fprintf (f, "G04 Title: %s, %s *\r\n", UNKNOWN (PCB->Name),
00929                UNKNOWN (name));
00930       fprintf (f, "G04 Creator: %s " VERSION " *\r\n", Progname);
00931       fprintf (f, "G04 CreationDate: %s *\r\n", utcTime);
00932 
00933 #ifdef HAVE_GETPWUID
00934       /* ID the user. */
00935       pwentry = getpwuid (getuid ());
00936       fprintf (f, "G04 For: %s *\r\n", pwentry->pw_name);
00937 #endif
00938 
00939       fprintf (f, "G04 Format: Gerber/RS-274X *\r\n");
00940       pcb_fprintf (f, metric ? "G04 PCB-Dimensions (mm): %.2mm %.2mm *\r\n" :
00941                "G04 PCB-Dimensions (mil): %.2ml %.2ml *\r\n",
00942                PCB->MaxWidth, PCB->MaxHeight);
00943       fprintf (f, "G04 PCB-Coordinate-Origin: lower left *\r\n");
00944 
00945       /* Signal data in inches. */
00946       fprintf (f, metric ? "%%MOMM*%%\r\n" : "%%MOIN*%%\r\n");
00947 
00948       /* Signal Leading zero suppression, Absolute Data, 2.5 format in inch, 4.3 in mm */
00949       fprintf (f, metric ? "%%FSLAX43Y43*%%\r\n" : "%%FSLAX25Y25*%%\r\n");
00950 
00951       /* build a legal identifier. */
00952       if (layername)
00953         free (layername);
00954       layername = strdup (filesuff);
00955       if (strrchr (layername, '.'))
00956         * strrchr (layername, '.') = 0;
00957 
00958       for (cp=layername; *cp; cp++)
00959         {
00960           if (isalnum((int) *cp))
00961             *cp = toupper((int) *cp);
00962           else
00963             *cp = '_';
00964         }
00965       fprintf (f, "%%LN%s*%%\r\n", layername);
00966       lncount = 1;
00967 
00968       for (search = aptr_list->data; search; search = search->next)
00969         fprintAperture(f, search);
00970       if (aptr_list->count == 0)
00971         /* We need to put *something* in the file to make it be parsed
00972            as RS-274X instead of RS-274D. */
00973         fprintf (f, "%%ADD11C,0.0100*%%\r\n");
00974     }
00975 
00976  emit_outline:
00977   /* If we're printing a copper layer other than the outline layer,
00978      and we want to "print outlines", and we have an outline layer,
00979      print the outline layer on this layer also.  */
00980   want_outline = 0;
00981   if (copy_outline_mode == COPY_OUTLINE_MASK
00982       && SL_TYPE (idx) == SL_MASK)
00983     want_outline = 1;
00984   if (copy_outline_mode == COPY_OUTLINE_SILK
00985       && SL_TYPE (idx) == SL_SILK)
00986     want_outline = 1;
00987   if (copy_outline_mode == COPY_OUTLINE_ALL
00988       && (SL_TYPE (idx) == SL_SILK
00989           || SL_TYPE (idx) == SL_MASK
00990           || SL_TYPE (idx) == SL_FAB
00991           || SL_TYPE (idx) == SL_ASSY
00992           || SL_TYPE (idx) == 0))
00993     want_outline = 1;
00994 
00995   if (want_outline
00996       && strcmp (name, "outline")
00997       && strcmp (name, "route"))
00998     {
00999       if (outline_layer
01000           && outline_layer != PCB->Data->Layer+idx)
01001         DrawLayer (outline_layer, &region);
01002       else if (!outline_layer)
01003         {
01004           hidGC gc = gui->graphics->make_gc ();
01005           printf("name %s idx %d\n", name, idx);
01006           if (SL_TYPE (idx) == SL_SILK)
01007             gui->graphics->set_line_width (gc, PCB->minSlk);
01008           else if (group >= 0)
01009             gui->graphics->set_line_width (gc, PCB->minWid);
01010           else
01011             gui->graphics->set_line_width (gc, AUTO_OUTLINE_WIDTH);
01012           gui->graphics->draw_line (gc, 0, 0, PCB->MaxWidth, 0);
01013           gui->graphics->draw_line (gc, 0, 0, 0, PCB->MaxHeight);
01014           gui->graphics->draw_line (gc, PCB->MaxWidth, 0, PCB->MaxWidth, PCB->MaxHeight);
01015           gui->graphics->draw_line (gc, 0, PCB->MaxHeight, PCB->MaxWidth, PCB->MaxHeight);
01016           gui->graphics->destroy_gc (gc);
01017         }
01018     }
01019 
01020   return 1;
01021 }
01022 
01023 static hidGC
01024 gerber_make_gc (void)
01025 {
01026   hidGC rv = (hidGC) calloc (1, sizeof (*rv));
01027   rv->cap = Trace_Cap;
01028   return rv;
01029 }
01030 
01031 static void
01032 gerber_destroy_gc (hidGC gc)
01033 {
01034   free (gc);
01035 }
01036 
01037 static void
01038 gerber_use_mask (enum mask_mode mode)
01039 {
01040   current_mask = mode;
01041 }
01042 
01043 static void
01044 gerber_set_color (hidGC gc, const char *name)
01045 {
01046   if (strcmp (name, "erase") == 0)
01047     {
01048       gc->color = 1;
01049       gc->erase = 1;
01050       gc->drill = 0;
01051     }
01052   else if (strcmp (name, "drill") == 0)
01053     {
01054       gc->color = 1;
01055       gc->erase = 0;
01056       gc->drill = 1;
01057     }
01058   else
01059     {
01060       gc->color = 0;
01061       gc->erase = 0;
01062       gc->drill = 0;
01063     }
01064 }
01065 
01066 static void
01067 gerber_set_line_cap (hidGC gc, EndCapStyle style)
01068 {
01069   gc->cap = style;
01070 }
01071 
01072 static void
01073 gerber_set_line_width (hidGC gc, Coord width)
01074 {
01075   gc->width = width;
01076 }
01077 
01078 static void
01079 gerber_set_draw_xor (hidGC gc, int xor_)
01080 {
01081   ;
01082 }
01083 
01084 static void
01085 use_gc (hidGC gc, int radius)
01086 {
01087   if (radius)
01088     {
01089       radius *= 2;
01090       if (radius != linewidth || lastcap != Round_Cap)
01091         {
01092           Aperture *aptr = findAperture (curr_aptr_list, radius, ROUND);
01093           if (aptr == NULL)
01094             pcb_fprintf (stderr, "error: aperture for radius %$mS type ROUND is null\n", radius);
01095           else if (f && !is_drill)
01096             fprintf (f, "G54D%d*", aptr->dCode);
01097           linewidth = radius;
01098           lastcap = Round_Cap;
01099         }
01100     }
01101   else if (linewidth != gc->width || lastcap != gc->cap)
01102     {
01103       Aperture *aptr;
01104       ApertureShape shape;
01105 
01106       linewidth = gc->width;
01107       lastcap = gc->cap;
01108       switch (gc->cap)
01109         {
01110         case Round_Cap:
01111         case Trace_Cap:
01112           shape = ROUND;
01113           break;
01114         default:
01115         case Square_Cap:
01116           shape = SQUARE;
01117           break;
01118         }
01119       aptr = findAperture (curr_aptr_list, linewidth, shape);
01120       if (aptr == NULL)
01121         pcb_fprintf (stderr, "error: aperture for width %$mS type %s is null\n",
01122                  linewidth, shape == ROUND ? "ROUND" : "SQUARE");
01123       else if (f)
01124         fprintf (f, "G54D%d*", aptr->dCode);
01125     }
01126 }
01127 
01128 static void
01129 gerber_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
01130 {
01131   gerber_draw_line (gc, x1, y1, x1, y2);
01132   gerber_draw_line (gc, x1, y1, x2, y1);
01133   gerber_draw_line (gc, x1, y2, x2, y2);
01134   gerber_draw_line (gc, x2, y1, x2, y2);
01135 }
01136 
01137 static void
01138 gerber_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
01139 {
01140   bool m = false;
01141 
01142   if (x1 != x2 && y1 != y2 && gc->cap == Square_Cap)
01143     {
01144       Coord x[5], y[5];
01145       double tx, ty, theta;
01146 
01147       theta = atan2 (y2-y1, x2-x1);
01148 
01149       /* T is a vector half a thickness long, in the direction of
01150          one of the corners.  */
01151       tx = gc->width / 2.0 * cos (theta + M_PI/4) * sqrt(2.0);
01152       ty = gc->width / 2.0 * sin (theta + M_PI/4) * sqrt(2.0);
01153 
01154       x[0] = x1 - tx;      y[0] = y1 - ty;
01155       x[1] = x2 + ty;      y[1] = y2 - tx;
01156       x[2] = x2 + tx;      y[2] = y2 + ty;
01157       x[3] = x1 - ty;      y[3] = y1 + tx;
01158 
01159       x[4] = x[0]; y[4] = y[0];
01160       gerber_fill_polygon (gc, 5, x, y);
01161       return;
01162     }
01163 
01164   use_gc (gc, 0);
01165   if (!f)
01166     return;
01167 
01168   if (x1 != lastX)
01169     {
01170       m = true;
01171       lastX = x1;
01172       print_xcoord (f, PCB, lastX);
01173     }
01174   if (y1 != lastY)
01175     {
01176       m = true;
01177       lastY = y1;
01178       print_ycoord (f, PCB, lastY);
01179     }
01180   if ((x1 == x2) && (y1 == y2))
01181     fprintf (f, "D03*\r\n");
01182   else
01183     {
01184       if (m)
01185         fprintf (f, "D02*");
01186       if (x2 != lastX)
01187         {
01188           lastX = x2;
01189           print_xcoord (f, PCB, lastX);
01190         }
01191       if (y2 != lastY)
01192         {
01193           lastY = y2;
01194           print_ycoord (f, PCB, lastY);
01195         }
01196       fprintf (f, "D01*\r\n");
01197     }
01198 
01199 }
01200 
01201 static void
01202 gerber_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height,
01203                  Angle start_angle, Angle delta_angle)
01204 {
01205   bool m = false;
01206   double arcStartX, arcStopX, arcStartY, arcStopY;
01207 
01208   /* we never draw zero-width lines */
01209   if (gc->width == 0)
01210     return;
01211 
01212   use_gc (gc, 0);
01213   if (!f)
01214     return;
01215 
01216   arcStartX = cx - width * cos (TO_RADIANS (start_angle));
01217   arcStartY = cy + height * sin (TO_RADIANS (start_angle));
01218 
01219   /* I checked three different gerber viewers, and they all disagreed
01220      on how ellipses should be drawn.  The spec just calls G74/G75
01221      "circular interpolation" so there's a chance it just doesn't
01222      support ellipses at all.  Thus, we draw them out with line
01223      segments.  Note that most arcs in pcb are circles anyway.  */
01224   if (width != height)
01225     {
01226       double step, angle;
01227       Coord max = width > height ? width : height;
01228       Coord minr = max - gc->width / 10;
01229       int nsteps;
01230       Coord x0, y0, x1, y1;
01231 
01232       if (minr >= max)
01233         minr = max - 1;
01234       step = acos((double)minr/(double)max) * 180.0/M_PI;
01235       if (step > 5)
01236         step = 5;
01237       nsteps = abs(delta_angle) / step + 1;
01238       step = (double)delta_angle / nsteps;
01239 
01240       x0 = arcStartX;
01241       y0 = arcStartY;
01242       angle = start_angle;
01243       while (nsteps > 0)
01244         {
01245           nsteps --;
01246           x1 = cx - width * cos (TO_RADIANS (angle+step));
01247           y1 = cy + height * sin (TO_RADIANS (angle+step));
01248           gerber_draw_line (gc, x0, y0, x1, y1);
01249           x0 = x1;
01250           y0 = y1;
01251           angle += step;
01252         }
01253       return;
01254     }
01255 
01256   arcStopX = cx - width * cos (TO_RADIANS (start_angle + delta_angle));
01257   arcStopY = cy + height * sin (TO_RADIANS (start_angle + delta_angle));
01258   if (arcStartX != lastX)
01259     {
01260       m = true;
01261       lastX = arcStartX;
01262       print_xcoord (f, PCB, lastX);
01263     }
01264   if (arcStartY != lastY)
01265     {
01266       m = true;
01267       lastY = arcStartY;
01268       print_ycoord (f, PCB, lastY);
01269     }
01270   if (m)
01271     fprintf (f, "D02*");
01272   pcb_fprintf (f,
01273            metric ? "G75*G0%1dX%.0muY%.0muI%.0muJ%.0muD01*G01*\r\n" :
01274            "G75*G0%1dX%.0mcY%.0mcI%.0mcJ%.0mcD01*G01*\r\n",
01275            (delta_angle < 0) ? 2 : 3,
01276            gerberX (PCB, arcStopX), gerberY (PCB, arcStopY),
01277            gerberXOffset (PCB, cx - arcStartX),
01278            gerberYOffset (PCB, cy - arcStartY));
01279   lastX = arcStopX;
01280   lastY = arcStopY;
01281 }
01282 
01283 static void
01284 gerber_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
01285 {
01286   if (radius <= 0)
01287     return;
01288   if (is_drill)
01289     radius = 50 * round (radius / 50.0);
01290   use_gc (gc, radius);
01291   if (!f)
01292     return;
01293   if (is_drill)
01294     {
01295       if (n_pending_drills >= max_pending_drills)
01296         {
01297           max_pending_drills += 100;
01298           pending_drills = (PendingDrills *) realloc(pending_drills,
01299                                                      max_pending_drills *
01300                                                      sizeof (pending_drills[0]));
01301         }
01302       pending_drills[n_pending_drills].x = cx;
01303       pending_drills[n_pending_drills].y = cy;
01304       pending_drills[n_pending_drills].diam = radius * 2;
01305       n_pending_drills++;
01306       return;
01307     }
01308   else if (gc->drill && !flash_drills)
01309     return;
01310   if (cx != lastX)
01311     {
01312       lastX = cx;
01313       print_xcoord (f, PCB, lastX);
01314     }
01315   if (cy != lastY)
01316     {
01317       lastY = cy;
01318       print_ycoord (f, PCB, lastY);
01319     }
01320   fprintf (f, "D03*\r\n");
01321 }
01322 
01323 static void
01324 gerber_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
01325 {
01326   bool m = false;
01327   int i;
01328   int firstTime = 1;
01329   Coord startX = 0, startY = 0;
01330 
01331   if (is_mask && current_mask == HID_MASK_BEFORE)
01332     return;
01333 
01334   use_gc (gc, 10 * 100);
01335   if (!f)
01336     return;
01337   fprintf (f, "G36*\r\n");
01338   for (i = 0; i < n_coords; i++)
01339     {
01340       if (x[i] != lastX)
01341         {
01342           m = true;
01343           lastX = x[i];
01344           print_xcoord (f, PCB, lastX);
01345         }
01346       if (y[i] != lastY)
01347         {
01348           m = true;
01349           lastY = y[i];
01350           print_ycoord (f, PCB, lastY);
01351         }
01352       if (firstTime)
01353         {
01354           firstTime = 0;
01355           startX = x[i];
01356           startY = y[i];
01357           if (m)
01358             fprintf (f, "D02*");
01359         }
01360       else if (m)
01361         fprintf (f, "D01*\r\n");
01362       m = false;
01363     }
01364   if (startX != lastX)
01365     {
01366       m = true;
01367       lastX = startX;
01368       print_xcoord (f, PCB, startX);
01369     }
01370   if (startY != lastY)
01371     {
01372       m = true;
01373       lastY = startY;
01374       print_ycoord (f, PCB, lastY);
01375     }
01376   if (m)
01377     fprintf (f, "D01*\r\n");
01378   fprintf (f, "G37*\r\n");
01379 }
01380 
01381 static void
01382 gerber_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
01383 {
01384   Coord x[5];
01385   Coord y[5];
01386   x[0] = x[4] = x1;
01387   y[0] = y[4] = y1;
01388   x[1] = x1;
01389   y[1] = y2;
01390   x[2] = x2;
01391   y[2] = y2;
01392   x[3] = x2;
01393   y[3] = y1;
01394   gerber_fill_polygon (gc, 5, x, y);
01395 }
01396 
01397 static void
01398 gerber_calibrate (double xval, double yval)
01399 {
01400   CRASH;
01401 }
01402 
01403 static void
01404 gerber_set_crosshair (int x, int y, int action)
01405 {
01406 }
01407 
01408 void
01409 hid_gerber_init ()
01410 {
01411   memset (&gerber_hid, 0, sizeof (gerber_hid));
01412   memset (&gerber_graphics, 0, sizeof (gerber_graphics));
01413 
01414   common_nogui_init (&gerber_hid);
01415   common_draw_helpers_init (&gerber_graphics);
01416 
01417   gerber_hid.struct_size         = sizeof (gerber_hid);
01418   gerber_hid.name                = "gerber";
01419   gerber_hid.description         = "RS-274X (Gerber) export";
01420   gerber_hid.exporter            = 1;
01421 
01422   gerber_hid.get_export_options  = gerber_get_export_options;
01423   gerber_hid.do_export           = gerber_do_export;
01424   gerber_hid.parse_arguments     = gerber_parse_arguments;
01425   gerber_hid.set_layer           = gerber_set_layer;
01426   gerber_hid.calibrate           = gerber_calibrate;
01427   gerber_hid.set_crosshair       = gerber_set_crosshair;
01428 
01429   gerber_hid.graphics            = &gerber_graphics;
01430 
01431   gerber_graphics.make_gc        = gerber_make_gc;
01432   gerber_graphics.destroy_gc     = gerber_destroy_gc;
01433   gerber_graphics.use_mask       = gerber_use_mask;
01434   gerber_graphics.set_color      = gerber_set_color;
01435   gerber_graphics.set_line_cap   = gerber_set_line_cap;
01436   gerber_graphics.set_line_width = gerber_set_line_width;
01437   gerber_graphics.set_draw_xor   = gerber_set_draw_xor;
01438   gerber_graphics.draw_line      = gerber_draw_line;
01439   gerber_graphics.draw_arc       = gerber_draw_arc;
01440   gerber_graphics.draw_rect      = gerber_draw_rect;
01441   gerber_graphics.fill_circle    = gerber_fill_circle;
01442   gerber_graphics.fill_polygon   = gerber_fill_polygon;
01443   gerber_graphics.fill_rect      = gerber_fill_rect;
01444 
01445   hid_register_hid (&gerber_hid);
01446 }