pcb 4.1.1
An interactive printed circuit board layout editor.
|
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, ®ion, 0); 00772 00773 layer_list_idx = 0; 00774 finding_apertures = 0; 00775 hid_expose_callback (&gerber_hid, ®ion, 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 (¤ttime)); 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, ®ion); 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 }