pcb 4.1.1
An interactive printed circuit board layout editor.
|
00001 /* 00002 * COPYRIGHT 00003 * 00004 * PCB, interactive printed circuit board design 00005 * 00006 * NELMA (Numerical capacitance calculator) export HID 00007 * Copyright (C) 2006 Tomaz Solc (tomaz.solc@tablix.org) 00008 * 00009 * PNG export code is based on the PNG export HID 00010 * Copyright (C) 2006 Dan McMahill 00011 * 00012 * This program is free software; you can redistribute it and/or modify 00013 * it under the terms of the GNU General Public License as published by 00014 * the Free Software Foundation; either version 2 of the License, or 00015 * (at your option) any later version. 00016 * 00017 * This program is distributed in the hope that it will be useful, 00018 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00019 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00020 * GNU General Public License for more details. 00021 * 00022 * You should have received a copy of the GNU General Public License along 00023 * with this program; if not, write to the Free Software Foundation, Inc., 00024 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00025 * 00026 */ 00027 00028 /* 00029 * This HID exports a PCB layout into: o One layer mask file (PNG format) per 00030 * copper layer. o Nelma configuration file that contains netlist and pin 00031 * information. 00032 */ 00033 00034 /* 00035 * FIXME: 00036 * 00037 * If you have a section of a net that does not contain any pins then that 00038 * section will be missing from the Nelma's copper geometry. 00039 * 00040 * For example: 00041 * 00042 * this section will be ignored by Nelma | | 00043 * 00044 * || ||=======|| || component layer || 00045 * || || || ||=============|| ||============|| 00046 * solder layer 00047 * 00048 * pin1 via via pin2 00049 * 00050 * Single layer layouts are always exported correctly. 00051 * 00052 */ 00053 00054 #ifdef HAVE_CONFIG_H 00055 #include "config.h" 00056 #endif 00057 00058 #include <stdio.h> 00059 #include <stdarg.h> 00060 #include <stdlib.h> 00061 #include <string.h> 00062 #include <assert.h> 00063 00064 #include <time.h> 00065 00066 #include "global.h" 00067 #include "error.h" /* Message() */ 00068 #include "data.h" 00069 #include "misc.h" 00070 #include "rats.h" 00071 00072 #include "hid.h" 00073 #include "hid_draw.h" 00074 #include "../hidint.h" 00075 #include "hid/common/hidnogui.h" 00076 #include "hid/common/draw_helpers.h" 00077 00078 #include <gd.h> 00079 00080 #include "hid/common/hidinit.h" 00081 00082 #ifdef HAVE_LIBDMALLOC 00083 #include <dmalloc.h> 00084 #endif 00085 00086 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented PNG function %s.\n", __FUNCTION__); abort() 00087 00088 /* Needed for PNG export */ 00089 00090 struct color_struct { 00091 /* the descriptor used by the gd library */ 00092 int c; 00093 00094 /* so I can figure out what rgb value c refers to */ 00095 unsigned int r, g, b; 00096 }; 00097 00098 struct hid_gc_struct { 00099 HID *me_pointer; 00100 EndCapStyle cap; 00101 Coord width; 00102 unsigned char r, g, b; 00103 int erase; 00104 struct color_struct *color; 00105 gdImagePtr brush; 00106 }; 00107 00108 static HID nelma_hid; 00109 static HID_DRAW nelma_graphics; 00110 00111 static struct color_struct *black = NULL, *white = NULL; 00112 static Coord linewidth = -1; 00113 static gdImagePtr lastbrush = (gdImagePtr)((void *) -1); 00114 00115 /* gd image and file for PNG export */ 00116 static gdImagePtr nelma_im = NULL; 00117 static FILE *nelma_f = NULL; 00118 00119 static int is_mask; 00120 static int is_drill; 00121 00122 /* 00123 * Which groups of layers to export into PNG layer masks. 1 means export, 0 00124 * means do not export. 00125 */ 00126 static int nelma_export_group[MAX_GROUP]; 00127 00128 /* Group that is currently exported. */ 00129 static int nelma_cur_group; 00130 00131 /* Filename prefix that will be used when saving files. */ 00132 static const char *nelma_basename = NULL; 00133 00134 /* Horizontal DPI (grid points per inch) */ 00135 static int nelma_dpi = -1; 00136 00137 /* Height of the copper layers in micrometers. */ 00138 00139 /* 00140 * The height of the copper layer is currently taken as the vertical grid 00141 * step, since this is the smallest vertical feature in the layout. 00142 */ 00143 static int nelma_copperh = -1; 00144 /* Height of the substrate layers in micrometers. */ 00145 static int nelma_substrateh = -1; 00146 /* Relative permittivity of the substrate. */ 00147 static double nelma_substratee = -1; 00148 00149 /* Permittivity of empty space (As/Vm) */ 00150 static const double nelma_air_epsilon = 8.85e-12; 00151 00152 HID_Attribute nelma_attribute_list[] = { 00153 /* other HIDs expect this to be first. */ 00154 00155 /* %start-doc options "94 Nelma Options" 00156 @ftable @code 00157 @item --basename <string> 00158 File name prefix. 00159 @end ftable 00160 %end-doc 00161 */ 00162 {"basename", "File name prefix", 00163 HID_String, 0, 0, {0, 0, 0}, 0, 0}, 00164 #define HA_basename 0 00165 00166 /* %start-doc options "94 Nelma Options" 00167 @ftable @code 00168 @item --dpi <num> 00169 Horizontal scale factor (grid points/inch). 00170 @end ftable 00171 %end-doc 00172 */ 00173 {"dpi", "Horizontal scale factor (grid points/inch)", 00174 HID_Integer, 0, 1000, {100, 0, 0}, 0, 0}, 00175 #define HA_dpi 1 00176 00177 /* %start-doc options "94 Nelma Options" 00178 @ftable @code 00179 @item --copper-height <num> 00180 Copper layer height (um). 00181 @end ftable 00182 %end-doc 00183 */ 00184 {"copper-height", "Copper layer height (um)", 00185 HID_Integer, 0, 200, {100, 0, 0}, 0, 0}, 00186 #define HA_copperh 2 00187 00188 /* %start-doc options "94 Nelma Options" 00189 @ftable @code 00190 @item --substrate-height <num> 00191 Substrate layer height (um). 00192 @end ftable 00193 %end-doc 00194 */ 00195 {"substrate-height", "Substrate layer height (um)", 00196 HID_Integer, 0, 10000, {2000, 0, 0}, 0, 0}, 00197 #define HA_substrateh 3 00198 00199 /* %start-doc options "94 Nelma Options" 00200 @ftable @code 00201 @item --substrate-epsilon <num> 00202 Substrate relative epsilon. 00203 @end ftable 00204 %end-doc 00205 */ 00206 {"substrate-epsilon", "Substrate relative epsilon", 00207 HID_Real, 0, 100, {0, 0, 4.0}, 0, 0}, 00208 #define HA_substratee 4 00209 }; 00210 00211 #define NUM_OPTIONS (sizeof(nelma_attribute_list)/sizeof(nelma_attribute_list[0])) 00212 00213 REGISTER_ATTRIBUTES(nelma_attribute_list) 00214 static HID_Attr_Val nelma_values[NUM_OPTIONS]; 00215 00216 /* *** Utility funcions **************************************************** */ 00217 00218 /* convert from default PCB units to nelma units */ 00219 static int pcb_to_nelma (Coord pcb) 00220 { 00221 return COORD_TO_INCH(pcb) * nelma_dpi; 00222 } 00223 00224 static char * 00225 nelma_get_png_name(const char *basename, const char *suffix) 00226 { 00227 char *buf; 00228 int len; 00229 00230 len = strlen(basename) + strlen(suffix) + 6; 00231 buf = (char *)malloc(sizeof(*buf) * len); 00232 00233 sprintf(buf, "%s.%s.png", basename, suffix); 00234 00235 return buf; 00236 } 00237 00238 /* Retrieves coordinates (in default PCB units) of a pin or pad. */ 00239 /* Copied from netlist.c */ 00240 static int 00241 pin_name_to_xy (LibraryEntryType * pin, Coord *x, Coord *y) 00242 { 00243 ConnectionType conn; 00244 if (!SeekPad(pin, &conn, false)) 00245 return 1; 00246 switch (conn.type) { 00247 case PIN_TYPE: 00248 *x = ((PinType *) (conn.ptr2))->X; 00249 *y = ((PinType *) (conn.ptr2))->Y; 00250 return 0; 00251 case PAD_TYPE: 00252 *x = ((PadType *) (conn.ptr2))->Point1.X; 00253 *y = ((PadType *) (conn.ptr2))->Point1.Y; 00254 return 0; 00255 } 00256 return 1; 00257 } 00258 00259 /* *** Exporting netlist data and geometry to the nelma config file ******** */ 00260 00261 static void 00262 nelma_write_space(FILE * out) 00263 { 00264 double xh, zh; 00265 00266 int z; 00267 int i, idx; 00268 const char *ext; 00269 00270 xh = 2.54e-2 / ((double) nelma_dpi); 00271 zh = nelma_copperh * 1e-6; 00272 00273 fprintf(out, "\n/* **** Space **** */\n\n"); 00274 00275 fprintf(out, "space pcb {\n"); 00276 fprintf(out, "\tstep = { %e, %e, %e }\n", xh, xh, zh); 00277 fprintf(out, "\tlayers = {\n"); 00278 00279 fprintf(out, "\t\t\"air-top\",\n"); 00280 fprintf(out, "\t\t\"air-bottom\""); 00281 00282 z = 10; 00283 for (i = 0; i < MAX_GROUP; i++) 00284 if (nelma_export_group[i]) { 00285 idx = (i >= 0 && i < max_group) ? 00286 PCB->LayerGroups.Entries[i][0] : i; 00287 ext = layer_type_to_file_name(idx, FNS_fixed); 00288 00289 if (z != 10) { 00290 fprintf(out, ",\n"); 00291 fprintf(out, "\t\t\"substrate-%d\"", z); 00292 z++; 00293 } 00294 fprintf(out, ",\n"); 00295 fprintf(out, "\t\t\"%s\"", ext); 00296 z++; 00297 } 00298 fprintf(out, "\n\t}\n"); 00299 fprintf(out, "}\n"); 00300 } 00301 00302 00303 static void 00304 nelma_write_material(FILE * out, char *name, char *type, double e) 00305 { 00306 fprintf(out, "material %s {\n", name); 00307 fprintf(out, "\ttype = \"%s\"\n", type); 00308 fprintf(out, "\tpermittivity = %e\n", e); 00309 fprintf(out, "\tconductivity = 0.0\n"); 00310 fprintf(out, "\tpermeability = 0.0\n"); 00311 fprintf(out, "}\n"); 00312 } 00313 00314 static void 00315 nelma_write_materials(FILE * out) 00316 { 00317 fprintf(out, "\n/* **** Materials **** */\n\n"); 00318 00319 nelma_write_material(out, "copper", "metal", nelma_air_epsilon); 00320 nelma_write_material(out, "air", "dielectric", nelma_air_epsilon); 00321 nelma_write_material(out, "composite", "dielectric", 00322 nelma_air_epsilon * nelma_substratee); 00323 } 00324 00325 static void 00326 nelma_write_nets(FILE * out) 00327 { 00328 LibraryType netlist; 00329 LibraryMenuType *net; 00330 LibraryEntryType *pin; 00331 00332 int n, m, i, idx; 00333 00334 const char *ext; 00335 00336 netlist = PCB->NetlistLib; 00337 00338 fprintf(out, "\n/* **** Nets **** */\n\n"); 00339 00340 for (n = 0; n < netlist.MenuN; n++) { 00341 net = &netlist.Menu[n]; 00342 00343 /* Weird, but correct */ 00344 fprintf(out, "net %s {\n", &net->Name[2]); 00345 00346 fprintf(out, "\tobjects = {\n"); 00347 00348 for (m = 0; m < net->EntryN; m++) { 00349 pin = &net->Entry[m]; 00350 00351 /* pin_name_to_xy(pin, &x, &y); */ 00352 00353 for (i = 0; i < MAX_GROUP; i++) 00354 if (nelma_export_group[i]) { 00355 idx = (i >= 0 && i < max_group) ? 00356 PCB->LayerGroups.Entries[i][0] : i; 00357 ext = layer_type_to_file_name(idx, FNS_fixed); 00358 00359 if (m != 0 || i != 0) 00360 fprintf(out, ",\n"); 00361 fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry, 00362 ext); 00363 } 00364 } 00365 00366 fprintf(out, "\n"); 00367 fprintf(out, "\t}\n"); 00368 fprintf(out, "}\n"); 00369 } 00370 } 00371 00372 static void 00373 nelma_write_layer(FILE * out, int z, int h, 00374 const char *name, int full, 00375 char *mat) 00376 { 00377 LibraryType netlist; 00378 LibraryMenuType *net; 00379 LibraryEntryType *pin; 00380 00381 int n, m; 00382 00383 fprintf(out, "layer %s {\n", name); 00384 fprintf(out, "\theight = %d\n", h); 00385 fprintf(out, "\tz-order = %d\n", z); 00386 fprintf(out, "\tmaterial = \"%s\"\n", mat); 00387 00388 if (full) { 00389 fprintf(out, "\tobjects = {\n"); 00390 netlist = PCB->NetlistLib; 00391 00392 for (n = 0; n < netlist.MenuN; n++) { 00393 net = &netlist.Menu[n]; 00394 00395 for (m = 0; m < net->EntryN; m++) { 00396 pin = &net->Entry[m]; 00397 00398 if (m != 0 || n != 0) 00399 fprintf(out, ",\n"); 00400 fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry, 00401 name); 00402 } 00403 00404 } 00405 fprintf(out, "\n\t}\n"); 00406 } 00407 fprintf(out, "}\n"); 00408 } 00409 00410 static void 00411 nelma_write_layers(FILE * out) 00412 { 00413 int i, idx; 00414 int z; 00415 00416 const char *ext; 00417 char buf[100]; 00418 00419 int subh; 00420 00421 subh = nelma_substrateh / nelma_copperh; 00422 00423 fprintf(out, "\n/* **** Layers **** */\n\n"); 00424 00425 /* Air layers on top and bottom of the stack */ 00426 /* Their height is double substrate height. */ 00427 nelma_write_layer(out, 1, 2 * subh, "air-top", 0, "air"); 00428 nelma_write_layer(out, 1000, 2 * subh, "air-bottom", 0, "air"); 00429 00430 z = 10; 00431 for (i = 0; i < MAX_GROUP; i++) 00432 if (nelma_export_group[i]) { 00433 idx = (i >= 0 && i < max_group) ? 00434 PCB->LayerGroups.Entries[i][0] : i; 00435 ext = layer_type_to_file_name(idx, FNS_fixed); 00436 00437 if (z != 10) { 00438 sprintf(buf, "substrate-%d", z); 00439 nelma_write_layer(out, 00440 z, 00441 subh, 00442 buf, 00443 0, 00444 "composite"); 00445 z++; 00446 } 00447 /* 00448 * FIXME: for layers that are not on top or bottom, 00449 * the material should be "composite" 00450 */ 00451 nelma_write_layer(out, z, 1, ext, 1, "air"); 00452 00453 z++; 00454 } 00455 } 00456 00457 static void 00458 nelma_write_object(FILE * out, LibraryEntryType *pin) 00459 { 00460 int i, idx; 00461 Coord px = 0, py = 0; 00462 int x, y; 00463 00464 char *f; 00465 const char *ext; 00466 00467 pin_name_to_xy (pin, &px, &py); 00468 00469 x = pcb_to_nelma (px); 00470 y = pcb_to_nelma (py); 00471 00472 for (i = 0; i < MAX_GROUP; i++) 00473 if (nelma_export_group[i]) { 00474 idx = (i >= 0 && i < max_group) ? 00475 PCB->LayerGroups.Entries[i][0] : i; 00476 ext = layer_type_to_file_name(idx, FNS_fixed); 00477 00478 fprintf(out, "object %s-%s {\n", pin->ListEntry, ext); 00479 fprintf(out, "\tposition = { 0, 0 }\n"); 00480 fprintf(out, "\tmaterial = \"copper\"\n"); 00481 fprintf(out, "\ttype = \"image\"\n"); 00482 fprintf(out, "\trole = \"net\"\n"); 00483 00484 f = nelma_get_png_name(nelma_basename, ext); 00485 00486 fprintf(out, "\tfile = \"%s\"\n", f); 00487 00488 free(f); 00489 00490 fprintf(out, "\tfile-pos = { %d, %d }\n", x, y); 00491 fprintf(out, "}\n"); 00492 } 00493 } 00494 00495 static void 00496 nelma_write_objects(FILE * out) 00497 { 00498 LibraryType netlist; 00499 LibraryMenuType *net; 00500 LibraryEntryType *pin; 00501 00502 int n, m; 00503 00504 netlist = PCB->NetlistLib; 00505 00506 fprintf(out, "\n/* **** Objects **** */\n\n"); 00507 00508 for (n = 0; n < netlist.MenuN; n++) { 00509 net = &netlist.Menu[n]; 00510 00511 for (m = 0; m < net->EntryN; m++) { 00512 pin = &net->Entry[m]; 00513 00514 nelma_write_object(out, pin); 00515 } 00516 } 00517 } 00518 00519 /* *** Main export callback ************************************************ */ 00520 00521 static void 00522 nelma_parse_arguments(int *argc, char ***argv) 00523 { 00524 hid_register_attributes(nelma_attribute_list, 00525 sizeof(nelma_attribute_list) / 00526 sizeof(nelma_attribute_list[0])); 00527 hid_parse_command_line(argc, argv); 00528 } 00529 00530 static HID_Attribute * 00531 nelma_get_export_options(int *n) 00532 { 00533 static char *last_made_filename = 0; 00534 00535 if (PCB) { 00536 derive_default_filename(PCB->Filename, 00537 &nelma_attribute_list[HA_basename], 00538 ".nelma", 00539 &last_made_filename); 00540 } 00541 if (n) { 00542 *n = NUM_OPTIONS; 00543 } 00544 return nelma_attribute_list; 00545 } 00546 00547 /* Populates nelma_export_group array */ 00548 void 00549 nelma_choose_groups() 00550 { 00551 int n, m; 00552 LayerType *layer; 00553 00554 /* Set entire array to 0 (don't export any layer groups by default */ 00555 memset(nelma_export_group, 0, sizeof(nelma_export_group)); 00556 00557 for (n = 0; n < max_copper_layer; n++) { 00558 layer = &PCB->Data->Layer[n]; 00559 00560 if (layer->LineN || layer->TextN || layer->ArcN || 00561 layer->PolygonN) { 00562 /* layer isn't empty */ 00563 00564 /* 00565 * is this check necessary? It seems that special 00566 * layers have negative indexes? 00567 */ 00568 00569 if (SL_TYPE(n) == 0) { 00570 /* layer is a copper layer */ 00571 m = GetLayerGroupNumberByNumber(n); 00572 00573 /* the export layer */ 00574 nelma_export_group[m] = 1; 00575 } 00576 } 00577 } 00578 } 00579 00580 static void 00581 nelma_alloc_colors() 00582 { 00583 /* 00584 * Allocate white and black -- the first color allocated becomes the 00585 * background color 00586 */ 00587 00588 white = (struct color_struct *) malloc(sizeof(*white)); 00589 white->r = white->g = white->b = 255; 00590 white->c = gdImageColorAllocate(nelma_im, white->r, white->g, white->b); 00591 00592 black = (struct color_struct *) malloc(sizeof(*black)); 00593 black->r = black->g = black->b = 0; 00594 black->c = gdImageColorAllocate(nelma_im, black->r, black->g, black->b); 00595 } 00596 00597 static void 00598 nelma_start_png(const char *basename, const char *suffix) 00599 { 00600 int h, w; 00601 char *buf; 00602 00603 buf = nelma_get_png_name(basename, suffix); 00604 00605 h = pcb_to_nelma(PCB->MaxHeight); 00606 w = pcb_to_nelma(PCB->MaxWidth); 00607 00608 /* nelma_im = gdImageCreate (w, h); */ 00609 00610 /* Nelma only works with true color images */ 00611 nelma_im = gdImageCreate(w, h); 00612 nelma_f = fopen(buf, "wb"); 00613 00614 nelma_alloc_colors(); 00615 00616 free(buf); 00617 } 00618 00619 static void 00620 nelma_finish_png() 00621 { 00622 #ifdef HAVE_GDIMAGEPNG 00623 gdImagePng(nelma_im, nelma_f); 00624 #else 00625 Message("NELMA: PNG not supported by gd. Can't write layer mask.\n"); 00626 #endif 00627 gdImageDestroy(nelma_im); 00628 fclose(nelma_f); 00629 00630 free(white); 00631 free(black); 00632 00633 nelma_im = NULL; 00634 nelma_f = NULL; 00635 } 00636 00637 void 00638 nelma_start_png_export() 00639 { 00640 BoxType region; 00641 00642 region.X1 = 0; 00643 region.Y1 = 0; 00644 region.X2 = PCB->MaxWidth; 00645 region.Y2 = PCB->MaxHeight; 00646 00647 linewidth = -1; 00648 lastbrush = (gdImagePtr)((void *) -1); 00649 00650 hid_expose_callback(&nelma_hid, ®ion, 0); 00651 } 00652 00653 static void 00654 nelma_do_export(HID_Attr_Val * options) 00655 { 00656 int save_ons[MAX_ALL_LAYER]; 00657 int i, idx; 00658 FILE *nelma_config; 00659 char *buf; 00660 int len; 00661 00662 time_t t; 00663 00664 if (!options) { 00665 nelma_get_export_options(0); 00666 for (i = 0; i < NUM_OPTIONS; i++) { 00667 nelma_values[i] = nelma_attribute_list[i].default_val; 00668 } 00669 options = nelma_values; 00670 } 00671 nelma_basename = options[HA_basename].str_value; 00672 if (!nelma_basename) { 00673 nelma_basename = "pcb-out"; 00674 } 00675 nelma_dpi = options[HA_dpi].int_value; 00676 if (nelma_dpi < 0) { 00677 fprintf(stderr, "ERROR: dpi may not be < 0\n"); 00678 return; 00679 } 00680 nelma_copperh = options[HA_copperh].int_value; 00681 nelma_substrateh = options[HA_substrateh].int_value; 00682 nelma_substratee = options[HA_substratee].real_value; 00683 00684 nelma_choose_groups(); 00685 00686 for (i = 0; i < MAX_GROUP; i++) { 00687 if (nelma_export_group[i]) { 00688 00689 nelma_cur_group = i; 00690 00691 /* magic */ 00692 idx = (i >= 0 && i < max_group) ? 00693 PCB->LayerGroups.Entries[i][0] : i; 00694 00695 nelma_start_png(nelma_basename, 00696 layer_type_to_file_name(idx, FNS_fixed)); 00697 00698 hid_save_and_show_layer_ons(save_ons); 00699 nelma_start_png_export(); 00700 hid_restore_layer_ons(save_ons); 00701 00702 nelma_finish_png(); 00703 } 00704 } 00705 00706 len = strlen(nelma_basename) + 4; 00707 buf = (char *)malloc(sizeof(*buf) * len); 00708 00709 sprintf(buf, "%s.em", nelma_basename); 00710 nelma_config = fopen(buf, "w"); 00711 00712 free(buf); 00713 00714 fprintf(nelma_config, "/* Made with PCB Nelma export HID */"); 00715 t = time(NULL); 00716 fprintf(nelma_config, "/* %s */", ctime(&t)); 00717 00718 nelma_write_nets(nelma_config); 00719 nelma_write_objects(nelma_config); 00720 nelma_write_layers(nelma_config); 00721 nelma_write_materials(nelma_config); 00722 nelma_write_space(nelma_config); 00723 00724 fclose(nelma_config); 00725 } 00726 00727 /* *** PNG export (slightly modified code from PNG export HID) ************* */ 00728 00729 static int 00730 nelma_set_layer(const char *name, int group, int empty) 00731 { 00732 int idx = (group >= 0 && group < max_group) ? 00733 PCB->LayerGroups.Entries[group][0] : group; 00734 00735 if (name == 0) { 00736 name = PCB->Data->Layer[idx].Name; 00737 } 00738 if (strcmp(name, "invisible") == 0) { 00739 return 0; 00740 } 00741 is_drill = (SL_TYPE(idx) == SL_PDRILL || SL_TYPE(idx) == SL_UDRILL); 00742 is_mask = (SL_TYPE(idx) == SL_MASK); 00743 00744 if (is_mask) { 00745 /* Don't print masks */ 00746 return 0; 00747 } 00748 if (is_drill) { 00749 /* 00750 * Print 'holes', so that we can fill gaps in the copper 00751 * layer 00752 */ 00753 return 1; 00754 } 00755 if (group == nelma_cur_group) { 00756 return 1; 00757 } 00758 return 0; 00759 } 00760 00761 static hidGC 00762 nelma_make_gc(void) 00763 { 00764 hidGC rv = (hidGC) malloc(sizeof(struct hid_gc_struct)); 00765 rv->me_pointer = &nelma_hid; 00766 rv->cap = Trace_Cap; 00767 rv->width = 1; 00768 rv->color = (struct color_struct *) malloc(sizeof(*rv->color)); 00769 rv->color->r = rv->color->g = rv->color->b = 0; 00770 rv->color->c = 0; 00771 return rv; 00772 } 00773 00774 static void 00775 nelma_destroy_gc(hidGC gc) 00776 { 00777 free(gc); 00778 } 00779 00780 static void 00781 nelma_use_mask(enum mask_mode mode) 00782 { 00783 /* does nothing */ 00784 } 00785 00786 static void 00787 nelma_set_color(hidGC gc, const char *name) 00788 { 00789 if (nelma_im == NULL) { 00790 return; 00791 } 00792 if (name == NULL) { 00793 name = "#ff0000"; 00794 } 00795 if (!strcmp(name, "drill")) { 00796 gc->color = black; 00797 gc->erase = 0; 00798 return; 00799 } 00800 if (!strcmp(name, "erase")) { 00801 /* FIXME -- should be background, not white */ 00802 gc->color = white; 00803 gc->erase = 1; 00804 return; 00805 } 00806 gc->color = black; 00807 gc->erase = 0; 00808 return; 00809 } 00810 00811 static void 00812 nelma_set_line_cap(hidGC gc, EndCapStyle style) 00813 { 00814 gc->cap = style; 00815 } 00816 00817 static void 00818 nelma_set_line_width(hidGC gc, Coord width) 00819 { 00820 gc->width = width; 00821 } 00822 00823 static void 00824 nelma_set_draw_xor(hidGC gc, int xor_) 00825 { 00826 ; 00827 } 00828 00829 static void 00830 nelma_set_draw_faded(hidGC gc, int faded) 00831 { 00832 } 00833 00834 static void 00835 use_gc(hidGC gc) 00836 { 00837 int need_brush = 0; 00838 00839 if (gc->me_pointer != &nelma_hid) { 00840 fprintf(stderr, "Fatal: GC from another HID passed to nelma HID\n"); 00841 abort(); 00842 } 00843 if (linewidth != gc->width) { 00844 /* Make sure the scaling doesn't erase lines completely */ 00845 /* 00846 if (SCALE (gc->width) == 0 && gc->width > 0) 00847 gdImageSetThickness (im, 1); 00848 else 00849 */ 00850 gdImageSetThickness(nelma_im, pcb_to_nelma(gc->width)); 00851 linewidth = gc->width; 00852 need_brush = 1; 00853 } 00854 if (lastbrush != gc->brush || need_brush) { 00855 static void *bcache = 0; 00856 hidval bval; 00857 char name[256]; 00858 char type; 00859 int r; 00860 00861 switch (gc->cap) { 00862 case Round_Cap: 00863 case Trace_Cap: 00864 type = 'C'; 00865 r = pcb_to_nelma(gc->width / 2); 00866 break; 00867 default: 00868 case Square_Cap: 00869 r = pcb_to_nelma(gc->width); 00870 type = 'S'; 00871 break; 00872 } 00873 sprintf(name, "#%.2x%.2x%.2x_%c_%d", gc->color->r, gc->color->g, 00874 gc->color->b, type, r); 00875 00876 if (hid_cache_color(0, name, &bval, &bcache)) { 00877 gc->brush = (gdImagePtr)bval.ptr; 00878 } else { 00879 int bg, fg; 00880 if (type == 'C') 00881 gc->brush = gdImageCreate(2 * r + 1, 2 * r + 1); 00882 else 00883 gc->brush = gdImageCreate(r + 1, r + 1); 00884 bg = gdImageColorAllocate(gc->brush, 255, 255, 255); 00885 fg = 00886 gdImageColorAllocate(gc->brush, gc->color->r, gc->color->g, 00887 gc->color->b); 00888 gdImageColorTransparent(gc->brush, bg); 00889 00890 /* 00891 * if we shrunk to a radius/box width of zero, then just use 00892 * a single pixel to draw with. 00893 */ 00894 if (r == 0) 00895 gdImageFilledRectangle(gc->brush, 0, 0, 0, 0, fg); 00896 else { 00897 if (type == 'C') 00898 gdImageFilledEllipse(gc->brush, r, r, 2 * r, 2 * r, fg); 00899 else 00900 gdImageFilledRectangle(gc->brush, 0, 0, r, r, fg); 00901 } 00902 bval.ptr = gc->brush; 00903 hid_cache_color(1, name, &bval, &bcache); 00904 } 00905 00906 gdImageSetBrush(nelma_im, gc->brush); 00907 lastbrush = gc->brush; 00908 00909 } 00910 } 00911 00912 static void 00913 nelma_draw_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 00914 { 00915 use_gc(gc); 00916 gdImageRectangle(nelma_im, 00917 pcb_to_nelma(x1), pcb_to_nelma(y1), 00918 pcb_to_nelma(x2), pcb_to_nelma(y2), gc->color->c); 00919 } 00920 00921 static void 00922 nelma_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 00923 { 00924 use_gc(gc); 00925 gdImageSetThickness(nelma_im, 0); 00926 linewidth = 0; 00927 gdImageFilledRectangle(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1), 00928 pcb_to_nelma(x2), pcb_to_nelma(y2), gc->color->c); 00929 } 00930 00931 static void 00932 nelma_draw_line(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2) 00933 { 00934 if (x1 == x2 && y1 == y2) { 00935 Coord w = gc->width / 2; 00936 nelma_fill_rect(gc, x1 - w, y1 - w, x1 + w, y1 + w); 00937 return; 00938 } 00939 use_gc(gc); 00940 00941 gdImageSetThickness(nelma_im, 0); 00942 linewidth = 0; 00943 gdImageLine(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1), 00944 pcb_to_nelma(x2), pcb_to_nelma(y2), gdBrushed); 00945 } 00946 00947 static void 00948 nelma_draw_arc(hidGC gc, Coord cx, Coord cy, Coord width, Coord height, 00949 Angle start_angle, Angle delta_angle) 00950 { 00951 Angle sa, ea; 00952 00953 /* 00954 * in gdImageArc, 0 degrees is to the right and +90 degrees is down 00955 * in pcb, 0 degrees is to the left and +90 degrees is down 00956 */ 00957 start_angle = 180 - start_angle; 00958 delta_angle = -delta_angle; 00959 if (delta_angle > 0) { 00960 sa = start_angle; 00961 ea = start_angle + delta_angle; 00962 } else { 00963 sa = start_angle + delta_angle; 00964 ea = start_angle; 00965 } 00966 00967 /* 00968 * make sure we start between 0 and 360 otherwise gd does strange 00969 * things 00970 */ 00971 sa = NormalizeAngle (sa); 00972 ea = NormalizeAngle (ea); 00973 00974 #if 0 00975 printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n", 00976 cx, cy, width, height, start_angle, delta_angle, sa, ea); 00977 printf("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n", 00978 im, SCALE_X(cx), SCALE_Y(cy), 00979 SCALE(width), SCALE(height), sa, ea, gc->color->c); 00980 #endif 00981 use_gc(gc); 00982 gdImageSetThickness(nelma_im, 0); 00983 linewidth = 0; 00984 gdImageArc(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy), 00985 pcb_to_nelma(2 * width), pcb_to_nelma(2 * height), sa, ea, gdBrushed); 00986 } 00987 00988 static void 00989 nelma_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius) 00990 { 00991 use_gc(gc); 00992 00993 gdImageSetThickness(nelma_im, 0); 00994 linewidth = 0; 00995 gdImageFilledEllipse(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy), 00996 pcb_to_nelma(2 * radius), pcb_to_nelma(2 * radius), gc->color->c); 00997 00998 } 00999 01000 static void 01001 nelma_fill_polygon(hidGC gc, int n_coords, Coord *x, Coord *y) 01002 { 01003 int i; 01004 gdPoint *points; 01005 01006 points = (gdPoint *) malloc(n_coords * sizeof(gdPoint)); 01007 if (points == NULL) { 01008 fprintf(stderr, "ERROR: nelma_fill_polygon(): malloc failed\n"); 01009 exit(1); 01010 } 01011 use_gc(gc); 01012 for (i = 0; i < n_coords; i++) { 01013 points[i].x = pcb_to_nelma(x[i]); 01014 points[i].y = pcb_to_nelma(y[i]); 01015 } 01016 gdImageSetThickness(nelma_im, 0); 01017 linewidth = 0; 01018 gdImageFilledPolygon(nelma_im, points, n_coords, gc->color->c); 01019 free(points); 01020 } 01021 01022 static void 01023 nelma_calibrate(double xval, double yval) 01024 { 01025 CRASH; 01026 } 01027 01028 static void 01029 nelma_set_crosshair(int x, int y, int a) 01030 { 01031 } 01032 01033 /* *** Miscellaneous ******************************************************* */ 01034 01035 #include "dolists.h" 01036 01037 void 01038 hid_nelma_init() 01039 { 01040 memset (&nelma_hid, 0, sizeof (HID)); 01041 memset (&nelma_graphics, 0, sizeof (HID_DRAW)); 01042 01043 common_nogui_init (&nelma_hid); 01044 common_draw_helpers_init (&nelma_graphics); 01045 01046 nelma_hid.struct_size = sizeof (HID); 01047 nelma_hid.name = "nelma"; 01048 nelma_hid.description = "Numerical analysis package export"; 01049 nelma_hid.exporter = 1; 01050 nelma_hid.poly_before = 1; 01051 01052 nelma_hid.get_export_options = nelma_get_export_options; 01053 nelma_hid.do_export = nelma_do_export; 01054 nelma_hid.parse_arguments = nelma_parse_arguments; 01055 nelma_hid.set_layer = nelma_set_layer; 01056 nelma_hid.calibrate = nelma_calibrate; 01057 nelma_hid.set_crosshair = nelma_set_crosshair; 01058 01059 nelma_hid.graphics = &nelma_graphics; 01060 01061 nelma_graphics.make_gc = nelma_make_gc; 01062 nelma_graphics.destroy_gc = nelma_destroy_gc; 01063 nelma_graphics.use_mask = nelma_use_mask; 01064 nelma_graphics.set_color = nelma_set_color; 01065 nelma_graphics.set_line_cap = nelma_set_line_cap; 01066 nelma_graphics.set_line_width = nelma_set_line_width; 01067 nelma_graphics.set_draw_xor = nelma_set_draw_xor; 01068 nelma_graphics.set_draw_faded = nelma_set_draw_faded; 01069 nelma_graphics.draw_line = nelma_draw_line; 01070 nelma_graphics.draw_arc = nelma_draw_arc; 01071 nelma_graphics.draw_rect = nelma_draw_rect; 01072 nelma_graphics.fill_circle = nelma_fill_circle; 01073 nelma_graphics.fill_polygon = nelma_fill_polygon; 01074 nelma_graphics.fill_rect = nelma_fill_rect; 01075 01076 hid_register_hid (&nelma_hid); 01077 01078 #include "nelma_lists.h" 01079 }