Index: trunk/scconfig/Rev.h =================================================================== --- trunk/scconfig/Rev.h (revision 19627) +++ trunk/scconfig/Rev.h (revision 19628) @@ -1 +1 @@ -static const int myrev = 19343; +static const int myrev = 19626; Index: trunk/scconfig/Rev.tab =================================================================== --- trunk/scconfig/Rev.tab (revision 19627) +++ trunk/scconfig/Rev.tab (revision 19628) @@ -1,3 +1,4 @@ +19626 configure retired the nelma exporter 19343 configure export_gerber: plugin configuration for G85 slots 19048 configure gtk: command line source cleanup/rename and centralize history handling 18668 configure ddraft: sphash for constraints Index: trunk/scconfig/plugins.h =================================================================== --- trunk/scconfig/plugins.h (revision 19627) +++ trunk/scconfig/plugins.h (revision 19628) @@ -87,7 +87,6 @@ plugin_def("export_gerber", "Gerber pcb_exporter", sbuildin, 1) plugin_def("export_ipcd356", "IPC-D-356 Netlist pcb_exporter", sbuildin, 1) plugin_def("export_lpr", "lpr pcb_exporter (printer)", sbuildin, 1) -plugin_def("export_nelma", "nelma pcb_exporter", sdisable, 1) plugin_def("export_openems", "openems exporter", sdisable, 1) plugin_def("export_openscad", "openscad pcb_exporter", sbuildin, 1) plugin_def("export_png", "png/gif/jpg pcb_exporter", sbuildin, 1) Index: trunk/src_plugins/export_nelma/export_nelma.pup =================================================================== --- trunk/src_plugins/export_nelma/export_nelma.pup (revision 19627) +++ trunk/src_plugins/export_nelma/export_nelma.pup (nonexistent) @@ -1,9 +0,0 @@ -$class export -$short nelma pcb_exporter -$long Export to nelma (Numerical capacitance calculator) - the 3rd party software, Nelma is not maintained any more. -$state deprecated -$fmt-native no -$fmt-feature-w export a board in the nelma format for Numerical capacitance calculation -#$package export-sim -default disable -autoload 1 Index: trunk/src_plugins/export_nelma/Plug.tmpasm =================================================================== --- trunk/src_plugins/export_nelma/Plug.tmpasm (revision 19627) +++ trunk/src_plugins/export_nelma/Plug.tmpasm (nonexistent) @@ -1,16 +0,0 @@ -put /local/pcb/mod {export_nelma} -put /local/pcb/mod/OBJS [@ $(PLUGDIR)/export_nelma/nelma.o @] - -switch /local/pcb/export_nelma/controls - case {disable} end; - default - put /local/pcb/mod/LDFLAGS libs/gui/gd/ldflags - put /local/pcb/mod/CFLAGS libs/gui/gd/cflags - end -end - -switch /local/pcb/export_nelma/controls - case {buildin} include /local/pcb/tmpasm/buildin; end; - case {plugin} include /local/pcb/tmpasm/plugin; end; - case {disable} include /local/pcb/tmpasm/disable; end; -end Index: trunk/src_plugins/export_nelma/nelma.c =================================================================== --- trunk/src_plugins/export_nelma/nelma.c (revision 19627) +++ trunk/src_plugins/export_nelma/nelma.c (nonexistent) @@ -1,1018 +0,0 @@ -/* - * COPYRIGHT - * - * pcb-rnd, interactive printed circuit board design - * (this file is based on PCB, interactive printed circuit board design) - * - * NELMA (Numerical capacitance calculator) export HID - * Copyright (C) 2006 Tomaz Solc (tomaz.solc@tablix.org) - * - * PNG export code is based on the PNG export HID - * Copyright (C) 2006 Dan McMahill - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact: - * Project page: http://repo.hu/projects/pcb-rnd - * lead developer: email to pcb-rnd (at) igor2.repo.hu - * mailing list: pcb-rnd (at) list.repo.hu (send "subscribe") - */ - -/* - * This HID exports a PCB layout into: o One layer mask file (PNG format) per - * copper layer. o Nelma configuration file that contains netlist and pin - * information. - */ - -/* - * FIXME: - * - * If you have a section of a net that does not contain any pins then that - * section will be missing from the Nelma's copper geometry. - * - * For example: - * - * this section will be ignored by Nelma | | - * - * || ||=======|| || component layer || - * || || || ||=============|| ||============|| - * solder layer - * - * pin1 via via pin2 - * - * Single layer layouts are always exported correctly. - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include - -#include "board.h" -#include "error.h" -#include "data.h" -#include "layer.h" -#include "rats.h" -#include "plugins.h" -#include "hid_cam.h" -#include "safe_fs.h" -#include "funchash_core.h" - -#include "hid.h" -#include "hid_nogui.h" -#include "hid_draw_helpers.h" - -#include - -#include "hid_init.h" -#include "hid_attrib.h" -#include "hid_flags.h" -#include "hid_color.h" - -const char *nelma_cookie = "nelma HID"; - -#define CRASH(func) fprintf(stderr, "HID error: pcb called unimplemented PNG function %s.\n", func); abort() - -/* Needed for PNG export */ - -struct color_struct { - /* the descriptor used by the gd library */ - int c; - - /* so I can figure out what rgb value c refers to */ - unsigned int r, g, b; -}; - -struct hid_gc_s { - pcb_core_gc_t core_gc; - pcb_hid_t *me_pointer; - pcb_cap_style_t cap; - pcb_coord_t width; - unsigned char r, g, b; - int erase; - int faded; - struct color_struct *color; - gdImagePtr brush; -}; - -static pcb_hid_t nelma_hid; - -static struct color_struct *black = NULL, *white = NULL; -static pcb_coord_t linewidth = -1; -static gdImagePtr lastbrush = (gdImagePtr) ((void *) -1); -static int lastcolor = -1; - -/* gd image and file for PNG export */ -static gdImagePtr nelma_im = NULL; -static FILE *nelma_f = NULL; - -static int is_mask; -static int is_drill; - -/* - * Which groups of layers to export into PNG layer masks. 1 means export, 0 - * means do not export. - */ -static int nelma_export_group[PCB_MAX_LAYERGRP]; - -/* Group that is currently exported. */ -static int nelma_cur_group; - -/* Filename prefix that will be used when saving files. */ -static const char *nelma_basename = NULL; - -/* Horizontal DPI (grid points per inch) */ -static int nelma_dpi = -1; - -/* Height of the copper layers in micrometers. */ - -/* - * The height of the copper layer is currently taken as the vertical grid - * step, since this is the smallest vertical feature in the layout. - */ -static int nelma_copperh = -1; -/* Height of the substrate layers in micrometers. */ -static int nelma_substrateh = -1; -/* Relative permittivity of the substrate. */ -static double nelma_substratee = -1; - -/* Permittivity of empty space (As/Vm) */ -static const double nelma_air_epsilon = 8.85e-12; - -pcb_hid_attribute_t nelma_attribute_list[] = { - /* other HIDs expect this to be first. */ - -/* %start-doc options "nelma Options" -@ftable @code -@item -- basename -File name prefix. -@end ftable -%end-doc -*/ - {"basename", "File name prefix", - PCB_HATT_STRING, 0, 0, {0, 0, 0}, 0, 0}, -#define HA_basename 0 - -/* %start-doc options "nelma Options" -@ftable @code -@item --dpi -Horizontal scale factor (grid points/inch). -@end ftable -%end-doc -*/ - {"dpi", "Horizontal scale factor (grid points/inch)", - PCB_HATT_INTEGER, 0, 1000, {100, 0, 0}, 0, 0}, -#define HA_dpi 1 - -/* %start-doc options "nelma Options" -@ftable @code -@item --copper-height -Copper layer height (um). -@end ftable -%end-doc -*/ - {"copper-height", "Copper layer height (um)", - PCB_HATT_INTEGER, 0, 200, {100, 0, 0}, 0, 0}, -#define HA_copperh 2 - -/* %start-doc options "nelma Options" -@ftable @code -@item --substrate-height -Substrate layer height (um). -@end ftable -%end-doc -*/ - {"substrate-height", "Substrate layer height (um)", - PCB_HATT_INTEGER, 0, 10000, {2000, 0, 0}, 0, 0}, -#define HA_substrateh 3 - -/* %start-doc options "nelma Options" -@ftable @code -@item --substrate-epsilon -Substrate relative epsilon. -@end ftable -%end-doc -*/ - {"substrate-epsilon", "Substrate relative epsilon", - PCB_HATT_REAL, 0, 100, {0, 0, 4.0}, 0, 0}, -#define HA_substratee 4 -}; - -#define NUM_OPTIONS (sizeof(nelma_attribute_list)/sizeof(nelma_attribute_list[0])) - -PCB_REGISTER_ATTRIBUTES(nelma_attribute_list, nelma_cookie) - static pcb_hid_attr_val_t nelma_values[NUM_OPTIONS]; - -/* *** Utility funcions **************************************************** */ - -/* convert from default PCB units to nelma units */ - static int pcb_to_nelma(pcb_coord_t pcb) -{ - return PCB_COORD_TO_INCH(pcb) * nelma_dpi; -} - -static char *nelma_get_png_name(const char *basename, const char *suffix) -{ - char *buf; - int len; - - len = strlen(basename) + strlen(suffix) + 6; - buf = (char *) malloc(sizeof(*buf) * len); - - sprintf(buf, "%s.%s.png", basename, suffix); - - return buf; -} - -/* *** Exporting netlist data and geometry to the nelma config file ******** */ - -static void nelma_write_space(FILE * out) -{ - double xh, zh; - int z, i; - - xh = 2.54e-2 / ((double) nelma_dpi); - zh = nelma_copperh * 1e-6; - - fprintf(out, "\n/* **** Space **** */\n\n"); - - fprintf(out, "space pcb {\n"); - fprintf(out, "\tstep = { %e, %e, %e }\n", xh, xh, zh); - fprintf(out, "\tlayers = {\n"); - - fprintf(out, "\t\t\"air-top\",\n"); - fprintf(out, "\t\t\"air-bottom\""); - - z = 10; - for (i = 0; i < PCB_MAX_LAYERGRP; i++) - if (nelma_export_group[i]) { - char tmp_ln[PCB_PATH_MAX]; - const char *ext = pcb_layer_to_file_name(tmp_ln, -1, pcb_layergrp_flags(PCB, i), PCB->LayerGroups.grp[i].purpose, PCB->LayerGroups.grp[i].purpi, PCB_FNS_fixed); - - if (z != 10) { - fprintf(out, ",\n"); - fprintf(out, "\t\t\"substrate-%d\"", z); - z++; - } - fprintf(out, ",\n"); - fprintf(out, "\t\t\"%s\"", ext); - z++; - } - fprintf(out, "\n\t}\n"); - fprintf(out, "}\n"); -} - - -static void nelma_write_material(FILE * out, const char *name, const char *type, double e) -{ - fprintf(out, "material %s {\n", name); - fprintf(out, "\ttype = \"%s\"\n", type); - fprintf(out, "\tpermittivity = %e\n", e); - fprintf(out, "\tconductivity = 0.0\n"); - fprintf(out, "\tpermeability = 0.0\n"); - fprintf(out, "}\n"); -} - -static void nelma_write_materials(FILE * out) -{ - fprintf(out, "\n/* **** Materials **** */\n\n"); - - nelma_write_material(out, "copper", "metal", nelma_air_epsilon); - nelma_write_material(out, "air", "dielectric", nelma_air_epsilon); - nelma_write_material(out, "composite", "dielectric", nelma_air_epsilon * nelma_substratee); -} - -static void nelma_write_nets(FILE * out) -{ - pcb_lib_t netlist; - pcb_lib_menu_t *net; - pcb_lib_entry_t *pin; - - int n, m, i; - - netlist = PCB->NetlistLib[PCB_NETLIST_EDITED]; - - fprintf(out, "\n/* **** Nets **** */\n\n"); - - for (n = 0; n < netlist.MenuN; n++) { - net = &netlist.Menu[n]; - - /* Weird, but correct */ - fprintf(out, "net %s {\n", &net->Name[2]); - - fprintf(out, "\tobjects = {\n"); - - for (m = 0; m < net->EntryN; m++) { - pin = &net->Entry[m]; - - /* pcb_pin_name_to_xy(pin, &x, &y); */ - - for (i = 0; i < PCB_MAX_LAYERGRP; i++) - if (nelma_export_group[i]) { - char tmp_ln[PCB_PATH_MAX]; - const char *ext = pcb_layer_to_file_name(tmp_ln, -1, pcb_layergrp_flags(PCB, i), PCB->LayerGroups.grp[i].purpose, PCB->LayerGroups.grp[i].purpi, PCB_FNS_fixed); - - if (m != 0 || i != 0) - fprintf(out, ",\n"); - fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry, ext); - } - } - - fprintf(out, "\n"); - fprintf(out, "\t}\n"); - fprintf(out, "}\n"); - } -} - -static void nelma_write_layer(FILE * out, int z, int h, const char *name, int full, const char *mat) -{ - pcb_lib_t netlist; - pcb_lib_menu_t *net; - pcb_lib_entry_t *pin; - - int n, m; - - fprintf(out, "layer %s {\n", name); - fprintf(out, "\theight = %d\n", h); - fprintf(out, "\tz-order = %d\n", z); - fprintf(out, "\tmaterial = \"%s\"\n", mat); - - if (full) { - fprintf(out, "\tobjects = {\n"); - netlist = PCB->NetlistLib[PCB_NETLIST_EDITED]; - - for (n = 0; n < netlist.MenuN; n++) { - net = &netlist.Menu[n]; - - for (m = 0; m < net->EntryN; m++) { - pin = &net->Entry[m]; - - if (m != 0 || n != 0) - fprintf(out, ",\n"); - fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry, name); - } - - } - fprintf(out, "\n\t}\n"); - } - fprintf(out, "}\n"); -} - -static void nelma_write_layers(FILE * out) -{ - int i, subh, z; - char buf[100]; - - subh = nelma_substrateh / nelma_copperh; - - fprintf(out, "\n/* **** Layers **** */\n\n"); - - /* Air layers on top and bottom of the stack */ - /* Their height is double substrate height. */ - nelma_write_layer(out, 1, 2 * subh, "air-top", 0, "air"); - nelma_write_layer(out, 1000, 2 * subh, "air-bottom", 0, "air"); - - z = 10; - for (i = 0; i < PCB_MAX_LAYERGRP; i++) - if (nelma_export_group[i]) { - char tmp_ln[PCB_PATH_MAX]; - const char *ext = pcb_layer_to_file_name(tmp_ln, -1, pcb_layergrp_flags(PCB, i), PCB->LayerGroups.grp[i].purpose, PCB->LayerGroups.grp[i].purpi, PCB_FNS_fixed); - - if (z != 10) { - sprintf(buf, "substrate-%d", z); - nelma_write_layer(out, z, subh, buf, 0, "composite"); - z++; - } - /* - * FIXME: for layers that are not on top or bottom, - * the material should be "composite" - */ - nelma_write_layer(out, z, 1, ext, 1, "air"); - - z++; - } -} - -static void nelma_write_object(FILE * out, pcb_lib_entry_t *pin) -{ - pcb_coord_t px = 0, py = 0; - int x, y, i; - char *f; - - pcb_pin_name_to_xy(pin, &px, &py); - - x = pcb_to_nelma(px); - y = pcb_to_nelma(py); - - for (i = 0; i < PCB_MAX_LAYERGRP; i++) - if (nelma_export_group[i]) { - char tmp_ln[PCB_PATH_MAX]; - const char *ext = pcb_layer_to_file_name(tmp_ln, -1, pcb_layergrp_flags(PCB, i), PCB->LayerGroups.grp[i].purpose, PCB->LayerGroups.grp[i].purpi, PCB_FNS_fixed); - - fprintf(out, "object %s-%s {\n", pin->ListEntry, ext); - fprintf(out, "\tposition = { 0, 0 }\n"); - fprintf(out, "\tmaterial = \"copper\"\n"); - fprintf(out, "\ttype = \"image\"\n"); - fprintf(out, "\trole = \"net\"\n"); - - f = nelma_get_png_name(nelma_basename, ext); - - fprintf(out, "\tfile = \"%s\"\n", f); - - free(f); - - fprintf(out, "\tfile-pos = { %d, %d }\n", x, y); - fprintf(out, "}\n"); - } -} - -static void nelma_write_objects(FILE * out) -{ - pcb_lib_t netlist; - pcb_lib_menu_t *net; - pcb_lib_entry_t *pin; - - int n, m; - - netlist = PCB->NetlistLib[PCB_NETLIST_EDITED]; - - fprintf(out, "\n/* **** Objects **** */\n\n"); - - for (n = 0; n < netlist.MenuN; n++) { - net = &netlist.Menu[n]; - - for (m = 0; m < net->EntryN; m++) { - pin = &net->Entry[m]; - - nelma_write_object(out, pin); - } - } -} - -/* *** Main export callback ************************************************ */ - -static int nelma_parse_arguments(int *argc, char ***argv) -{ - pcb_hid_register_attributes(nelma_attribute_list, sizeof(nelma_attribute_list) / sizeof(nelma_attribute_list[0]), nelma_cookie, 0); - return pcb_hid_parse_command_line(argc, argv); -} - -static pcb_hid_attribute_t *nelma_get_export_options(int *n) -{ - static char *last_made_filename = 0; - - if (PCB) { - pcb_derive_default_filename(PCB->Filename, &nelma_attribute_list[HA_basename], ".nelma", &last_made_filename); - } - if (n) { - *n = NUM_OPTIONS; - } - return nelma_attribute_list; -} - -/* Populates nelma_export_group array */ -void nelma_choose_groups() -{ - int n, m; - pcb_layer_t *layer; - - /* Set entire array to 0 (don't export any layer groups by default */ - memset(nelma_export_group, 0, sizeof(nelma_export_group)); - - for (n = 0; n < pcb_max_layer; n++) { - unsigned int flags = pcb_layer_flags(PCB, n); - if (flags & PCB_LYT_SILK) - continue; - layer = &PCB->Data->Layer[n]; - - if (!pcb_layer_is_empty_(PCB, layer)) { - /* layer isn't empty */ - if ((flags & PCB_LYT_COPPER) || PCB_LAYER_IS_ROUTE(flags, pcb_layer_purpose_(layer, NULL))) { - /* layer is a copper layer */ - m = pcb_layer_get_group(PCB, n); - - /* the export layer */ - nelma_export_group[m] = 1; - } - } - } -} - -static void nelma_alloc_colors() -{ - /* - * Allocate white and black -- the first color allocated becomes the - * background color - */ - - white = (struct color_struct *) malloc(sizeof(*white)); - white->r = white->g = white->b = 255; - white->c = gdImageColorAllocate(nelma_im, white->r, white->g, white->b); - - black = (struct color_struct *) malloc(sizeof(*black)); - black->r = black->g = black->b = 0; - black->c = gdImageColorAllocate(nelma_im, black->r, black->g, black->b); -} - -static void nelma_start_png(const char *basename, const char *suffix) -{ - int h, w; - char *buf; - - buf = nelma_get_png_name(basename, suffix); - - h = pcb_to_nelma(PCB->MaxHeight); - w = pcb_to_nelma(PCB->MaxWidth); - - /* nelma_im = gdImageCreate (w, h); */ - - /* Nelma only works with true color images */ - nelma_im = gdImageCreate(w, h); - nelma_f = pcb_fopen(buf, "wb"); - - nelma_alloc_colors(); - - free(buf); -} - -static void nelma_finish_png() -{ -#ifdef HAVE_GDIMAGEPNG - gdImagePng(nelma_im, nelma_f); -#else - pcb_message(PCB_MSG_WARNING, "NELMA: PNG not supported by gd. Can't write layer mask.\n"); -#endif - gdImageDestroy(nelma_im); - fclose(nelma_f); - - free(white); - free(black); - - nelma_im = NULL; - nelma_f = NULL; -} - -void nelma_start_png_export() -{ - pcb_hid_expose_ctx_t ctx; - - ctx.view.X1 = 0; - ctx.view.Y1 = 0; - ctx.view.X2 = PCB->MaxWidth; - ctx.view.Y2 = PCB->MaxHeight; - - linewidth = -1; - lastbrush = (gdImagePtr) ((void *) -1); - lastcolor = -1; - - pcb_hid_expose_all(&nelma_hid, &ctx); -} - -static void nelma_do_export(pcb_hid_attr_val_t * options) -{ - int save_ons[PCB_MAX_LAYER + 2]; - int i, len; - FILE *nelma_config; - char *buf; - time_t t; - - if (!options) { - nelma_get_export_options(0); - for (i = 0; i < NUM_OPTIONS; i++) { - nelma_values[i] = nelma_attribute_list[i].default_val; - } - options = nelma_values; - } - nelma_basename = options[HA_basename].str_value; - if (!nelma_basename) { - nelma_basename = "pcb-out"; - } - nelma_dpi = options[HA_dpi].int_value; - if (nelma_dpi < 0) { - fprintf(stderr, "ERROR: dpi may not be < 0\n"); - return; - } - nelma_copperh = options[HA_copperh].int_value; - nelma_substrateh = options[HA_substrateh].int_value; - nelma_substratee = options[HA_substratee].real_value; - - nelma_choose_groups(); - - for (i = 0; i < PCB_MAX_LAYERGRP; i++) { - if (nelma_export_group[i]) { - char tmp_ln[PCB_PATH_MAX]; - const char *ext = pcb_layer_to_file_name(tmp_ln, -1, pcb_layergrp_flags(PCB, i), PCB->LayerGroups.grp[i].purpose, PCB->LayerGroups.grp[i].purpi, PCB_FNS_fixed); - - nelma_cur_group = i; - - nelma_start_png(nelma_basename, ext); - - pcb_hid_save_and_show_layer_ons(save_ons); - nelma_start_png_export(); - pcb_hid_restore_layer_ons(save_ons); - - nelma_finish_png(); - } - } - - len = strlen(nelma_basename) + 4; - buf = (char *) malloc(sizeof(*buf) * len); - - sprintf(buf, "%s.em", nelma_basename); - nelma_config = pcb_fopen(buf, "w"); - - free(buf); - - fprintf(nelma_config, "/* Made with PCB Nelma export HID */"); - t = time(NULL); - fprintf(nelma_config, "/* %s */", ctime(&t)); - - nelma_write_nets(nelma_config); - nelma_write_objects(nelma_config); - nelma_write_layers(nelma_config); - nelma_write_materials(nelma_config); - nelma_write_space(nelma_config); - - fclose(nelma_config); -} - -/* *** PNG export (slightly modified code from PNG export HID) ************* */ - -static int nelma_set_layer_group(pcb_layergrp_id_t group, const char *purpose, int purpi, pcb_layer_id_t layer, unsigned int flags, int is_empty, pcb_xform_t **xform) -{ - if (flags & PCB_LYT_INVIS) - return 0; - - if ((flags & PCB_LYT_ANYTHING) == PCB_LYT_SILK) - return 0; - - is_drill = PCB_LAYER_IS_DRILL(flags, purpi); - is_mask = !!(flags & PCB_LYT_MASK); - - if (is_mask) { - /* Don't print masks */ - return 0; - } - if (is_drill) { - /* - * Print 'holes', so that we can fill gaps in the copper - * layer - */ - return 1; - } - if (group == nelma_cur_group) { - return 1; - } - return 0; -} - -static pcb_hid_gc_t nelma_make_gc(void) -{ - pcb_hid_gc_t rv = (pcb_hid_gc_t) malloc(sizeof(struct hid_gc_s)); - rv->me_pointer = &nelma_hid; - rv->cap = pcb_cap_round; - rv->width = 1; - rv->color = (struct color_struct *) malloc(sizeof(*rv->color)); - rv->color->r = rv->color->g = rv->color->b = 0; - rv->color->c = 0; - return rv; -} - -static void nelma_destroy_gc(pcb_hid_gc_t gc) -{ - free(gc); -} - -static void nelma_set_color(pcb_hid_gc_t gc, const char *name) -{ - if (nelma_im == NULL) { - return; - } - if (name == NULL) { - name = "#ff0000"; - } - if (!strcmp(name, "drill")) { - gc->color = black; - gc->erase = 0; - return; - } - gc->color = black; - gc->erase = 0; - return; -} - -static void nelma_set_line_cap(pcb_hid_gc_t gc, pcb_cap_style_t style) -{ - gc->cap = style; -} - -static void nelma_set_line_width(pcb_hid_gc_t gc, pcb_coord_t width) -{ - gc->width = width; -} - -static void nelma_set_draw_xor(pcb_hid_gc_t gc, int xor_) -{ - ; -} - -static void nelma_set_draw_faded(pcb_hid_gc_t gc, int faded) -{ - gc->faded = faded; -} - -static void use_gc(pcb_hid_gc_t gc) -{ - int need_brush = 0; - - if (gc->me_pointer != &nelma_hid) { - fprintf(stderr, "Fatal: GC from another HID passed to nelma HID\n"); - abort(); - } - if (linewidth != gc->width) { - /* Make sure the scaling doesn't erase lines completely */ - /* - if (SCALE (gc->width) == 0 && gc->width > 0) - gdImageSetThickness (im, 1); - else - */ - gdImageSetThickness(nelma_im, pcb_to_nelma(gc->width)); - linewidth = gc->width; - need_brush = 1; - } - if (lastbrush != gc->brush || need_brush) { - static void *bcache = 0; - pcb_hidval_t bval; - char name[256]; - char type; - int r; - - switch (gc->cap) { - case pcb_cap_round: - type = 'C'; - r = pcb_to_nelma(gc->width / 2); - break; - case pcb_cap_square: - r = pcb_to_nelma(gc->width); - type = 'S'; - break; - default: - assert(!"unhandled cap"); - type = 'C'; - r = 1; - } - sprintf(name, "#%.2x%.2x%.2x_%c_%d", gc->color->r, gc->color->g, gc->color->b, type, r); - - if (pcb_hid_cache_color(0, name, &bval, &bcache)) { - gc->brush = (gdImagePtr) bval.ptr; - } - else { - int bg, fg; - if (type == 'C') - gc->brush = gdImageCreate(2 * r + 1, 2 * r + 1); - else - gc->brush = gdImageCreate(r + 1, r + 1); - bg = gdImageColorAllocate(gc->brush, 255, 255, 255); - fg = gdImageColorAllocate(gc->brush, gc->color->r, gc->color->g, gc->color->b); - gdImageColorTransparent(gc->brush, bg); - - /* - * if we shrunk to a radius/box width of zero, then just use - * a single pixel to draw with. - */ - if (r == 0) - gdImageFilledRectangle(gc->brush, 0, 0, 0, 0, fg); - else { - if (type == 'C') - gdImageFilledEllipse(gc->brush, r, r, 2 * r, 2 * r, fg); - else - gdImageFilledRectangle(gc->brush, 0, 0, r, r, fg); - } - bval.ptr = gc->brush; - pcb_hid_cache_color(1, name, &bval, &bcache); - } - - gdImageSetBrush(nelma_im, gc->brush); - lastbrush = gc->brush; - - } -#define CBLEND(gc) (((gc->r)<<24)|((gc->g)<<16)|((gc->b)<<8)|(gc->faded)) - if (lastcolor != CBLEND(gc)) { - if (is_drill || is_mask) { -#ifdef FIXME - fprintf(f, "%d gray\n", gc->erase ? 0 : 1); -#endif - lastcolor = 0; - } - else { - double r, g, b; - r = gc->r; - g = gc->g; - b = gc->b; - if (gc->faded) { - r = 0.8 * 255 + 0.2 * r; - g = 0.8 * 255 + 0.2 * g; - b = 0.8 * 255 + 0.2 * b; - } -#ifdef FIXME - if (gc->r == gc->g && gc->g == gc->b) - fprintf(f, "%g gray\n", r / 255.0); - else - fprintf(f, "%g %g %g rgb\n", r / 255.0, g / 255.0, b / 255.0); -#endif - lastcolor = CBLEND(gc); - } - } -} - -static void nelma_draw_rect(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2, pcb_coord_t y2) -{ - use_gc(gc); - gdImageRectangle(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1), pcb_to_nelma(x2), pcb_to_nelma(y2), gc->color->c); -} - -static void nelma_fill_rect(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2, pcb_coord_t y2) -{ - use_gc(gc); - gdImageSetThickness(nelma_im, 0); - linewidth = 0; - gdImageFilledRectangle(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1), pcb_to_nelma(x2), pcb_to_nelma(y2), gc->color->c); -} - -static void nelma_draw_line(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2, pcb_coord_t y2) -{ - if (x1 == x2 && y1 == y2) { - pcb_coord_t w = gc->width / 2; - nelma_fill_rect(gc, x1 - w, y1 - w, x1 + w, y1 + w); - return; - } - use_gc(gc); - - gdImageSetThickness(nelma_im, 0); - linewidth = 0; - gdImageLine(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1), pcb_to_nelma(x2), pcb_to_nelma(y2), gdBrushed); -} - -static void nelma_draw_arc(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t width, pcb_coord_t height, pcb_angle_t start_angle, pcb_angle_t delta_angle) -{ - pcb_angle_t sa, ea; - - /* - * in gdImageArc, 0 degrees is to the right and +90 degrees is down - * in pcb, 0 degrees is to the left and +90 degrees is down - */ - start_angle = 180 - start_angle; - delta_angle = -delta_angle; - if (delta_angle > 0) { - sa = start_angle; - ea = start_angle + delta_angle; - } - else { - sa = start_angle + delta_angle; - ea = start_angle; - } - - /* - * make sure we start between 0 and 360 otherwise gd does strange - * things - */ - sa = pcb_normalize_angle(sa); - ea = pcb_normalize_angle(ea); - -#if 0 - printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n", cx, cy, width, height, start_angle, delta_angle, sa, ea); - printf("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n", - (void *)im, SCALE_X(cx), SCALE_Y(cy), SCALE(width), SCALE(height), sa, ea, gc->color->c); -#endif - use_gc(gc); - gdImageSetThickness(nelma_im, 0); - linewidth = 0; - gdImageArc(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy), - pcb_to_nelma(2 * width), pcb_to_nelma(2 * height), sa, ea, gdBrushed); -} - -static void nelma_fill_circle(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t radius) -{ - use_gc(gc); - - gdImageSetThickness(nelma_im, 0); - linewidth = 0; - gdImageFilledEllipse(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy), - pcb_to_nelma(2 * radius), pcb_to_nelma(2 * radius), gc->color->c); - -} - -static void nelma_fill_polygon_offs(pcb_hid_gc_t gc, int n_coords, pcb_coord_t *x, pcb_coord_t *y, pcb_coord_t dx, pcb_coord_t dy) -{ - int i; - gdPoint *points; - - points = (gdPoint *) malloc(n_coords * sizeof(gdPoint)); - if (points == NULL) { - fprintf(stderr, "ERROR: nelma_fill_polygon(): malloc failed\n"); - exit(1); - } - use_gc(gc); - for (i = 0; i < n_coords; i++) { - points[i].x = pcb_to_nelma(x[i]+dx); - points[i].y = pcb_to_nelma(y[i]+dy); - } - gdImageSetThickness(nelma_im, 0); - linewidth = 0; - gdImageFilledPolygon(nelma_im, points, n_coords, gc->color->c); - free(points); -} - -static void nelma_fill_polygon(pcb_hid_gc_t gc, int n_coords, pcb_coord_t *x, pcb_coord_t *y) -{ - nelma_fill_polygon_offs(gc, n_coords, x, y, 0, 0); -} - - -static void nelma_calibrate(double xval, double yval) -{ - CRASH("nelma_calibrate"); -} - -static void nelma_set_crosshair(pcb_coord_t x, pcb_coord_t y, int a) -{ -} - -static int nelma_usage(const char *topic) -{ - fprintf(stderr, "\nnelma exporter command line arguments:\n\n"); - pcb_hid_usage(nelma_attribute_list, sizeof(nelma_attribute_list) / sizeof(nelma_attribute_list[0])); - fprintf(stderr, "\nUsage: pcb-rnd [generic_options] -x nelma [nelma options] foo.pcb\n\n"); - return 0; -} - -/* *** Miscellaneous ******************************************************* */ - -#include "dolists.h" - -int pplg_check_ver_export_nelma(int ver_needed) { return 0; } - -int pplg_uninit_export_nelma(void) -{ - pcb_hid_remove_attributes_by_cookie(nelma_cookie); - return 0; -} - -int pplg_init_export_nelma(void) -{ - PCB_API_CHK_VER; - - memset(&nelma_hid, 0, sizeof(pcb_hid_t)); - - pcb_hid_nogui_init(&nelma_hid); - pcb_dhlp_draw_helpers_init(&nelma_hid); - - nelma_hid.struct_size = sizeof(pcb_hid_t); - nelma_hid.name = "nelma"; - nelma_hid.description = "Numerical analysis package export"; - nelma_hid.exporter = 1; - - nelma_hid.get_export_options = nelma_get_export_options; - nelma_hid.do_export = nelma_do_export; - nelma_hid.parse_arguments = nelma_parse_arguments; - nelma_hid.set_layer_group = nelma_set_layer_group; - nelma_hid.make_gc = nelma_make_gc; - nelma_hid.destroy_gc = nelma_destroy_gc; - nelma_hid.set_color = nelma_set_color; - nelma_hid.set_line_cap = nelma_set_line_cap; - nelma_hid.set_line_width = nelma_set_line_width; - nelma_hid.set_draw_xor = nelma_set_draw_xor; - nelma_hid.set_draw_faded = nelma_set_draw_faded; - nelma_hid.draw_line = nelma_draw_line; - nelma_hid.draw_arc = nelma_draw_arc; - nelma_hid.draw_rect = nelma_draw_rect; - nelma_hid.fill_circle = nelma_fill_circle; - nelma_hid.fill_polygon = nelma_fill_polygon; - nelma_hid.fill_polygon_offs = nelma_fill_polygon_offs; - nelma_hid.fill_rect = nelma_fill_rect; - nelma_hid.calibrate = nelma_calibrate; - nelma_hid.set_crosshair = nelma_set_crosshair; - - nelma_hid.usage = nelma_usage; - - pcb_hid_register_hid(&nelma_hid); - return 0; -} Index: trunk/src_plugins/export_nelma/Makefile =================================================================== --- trunk/src_plugins/export_nelma/Makefile (revision 19627) +++ trunk/src_plugins/export_nelma/Makefile (nonexistent) @@ -1,5 +0,0 @@ -all: - cd ../../src && $(MAKE) mod_export_nelma - -clean: - rm *.o *.so 2>/dev/null ; true Index: trunk/src_plugins/plugins_ALL.tmpasm =================================================================== --- trunk/src_plugins/plugins_ALL.tmpasm (revision 19627) +++ trunk/src_plugins/plugins_ALL.tmpasm (revision 19628) @@ -24,7 +24,6 @@ include {../src_plugins/export_gerber/Plug.tmpasm} include {../src_plugins/export_ipcd356/Plug.tmpasm} include {../src_plugins/export_lpr/Plug.tmpasm} -include {../src_plugins/export_nelma/Plug.tmpasm} include {../src_plugins/export_openems/Plug.tmpasm} include {../src_plugins/export_openscad/Plug.tmpasm} include {../src_plugins/export_png/Plug.tmpasm} Index: work/obsolete/export_nelma/Makefile =================================================================== --- work/obsolete/export_nelma/Makefile (nonexistent) +++ work/obsolete/export_nelma/Makefile (revision 19628) @@ -0,0 +1,5 @@ +all: + cd ../../src && $(MAKE) mod_export_nelma + +clean: + rm *.o *.so 2>/dev/null ; true Index: work/obsolete/export_nelma/Plug.tmpasm =================================================================== --- work/obsolete/export_nelma/Plug.tmpasm (nonexistent) +++ work/obsolete/export_nelma/Plug.tmpasm (revision 19628) @@ -0,0 +1,16 @@ +put /local/pcb/mod {export_nelma} +put /local/pcb/mod/OBJS [@ $(PLUGDIR)/export_nelma/nelma.o @] + +switch /local/pcb/export_nelma/controls + case {disable} end; + default + put /local/pcb/mod/LDFLAGS libs/gui/gd/ldflags + put /local/pcb/mod/CFLAGS libs/gui/gd/cflags + end +end + +switch /local/pcb/export_nelma/controls + case {buildin} include /local/pcb/tmpasm/buildin; end; + case {plugin} include /local/pcb/tmpasm/plugin; end; + case {disable} include /local/pcb/tmpasm/disable; end; +end Index: work/obsolete/export_nelma/export_nelma.pup =================================================================== --- work/obsolete/export_nelma/export_nelma.pup (nonexistent) +++ work/obsolete/export_nelma/export_nelma.pup (revision 19628) @@ -0,0 +1,9 @@ +$class export +$short nelma pcb_exporter +$long Export to nelma (Numerical capacitance calculator) - the 3rd party software, Nelma is not maintained any more. +$state deprecated +$fmt-native no +$fmt-feature-w export a board in the nelma format for Numerical capacitance calculation +#$package export-sim +default disable +autoload 1 Index: work/obsolete/export_nelma/nelma.c =================================================================== --- work/obsolete/export_nelma/nelma.c (nonexistent) +++ work/obsolete/export_nelma/nelma.c (revision 19628) @@ -0,0 +1,1018 @@ +/* + * COPYRIGHT + * + * pcb-rnd, interactive printed circuit board design + * (this file is based on PCB, interactive printed circuit board design) + * + * NELMA (Numerical capacitance calculator) export HID + * Copyright (C) 2006 Tomaz Solc (tomaz.solc@tablix.org) + * + * PNG export code is based on the PNG export HID + * Copyright (C) 2006 Dan McMahill + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Contact: + * Project page: http://repo.hu/projects/pcb-rnd + * lead developer: email to pcb-rnd (at) igor2.repo.hu + * mailing list: pcb-rnd (at) list.repo.hu (send "subscribe") + */ + +/* + * This HID exports a PCB layout into: o One layer mask file (PNG format) per + * copper layer. o Nelma configuration file that contains netlist and pin + * information. + */ + +/* + * FIXME: + * + * If you have a section of a net that does not contain any pins then that + * section will be missing from the Nelma's copper geometry. + * + * For example: + * + * this section will be ignored by Nelma | | + * + * || ||=======|| || component layer || + * || || || ||=============|| ||============|| + * solder layer + * + * pin1 via via pin2 + * + * Single layer layouts are always exported correctly. + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include + +#include "board.h" +#include "error.h" +#include "data.h" +#include "layer.h" +#include "rats.h" +#include "plugins.h" +#include "hid_cam.h" +#include "safe_fs.h" +#include "funchash_core.h" + +#include "hid.h" +#include "hid_nogui.h" +#include "hid_draw_helpers.h" + +#include + +#include "hid_init.h" +#include "hid_attrib.h" +#include "hid_flags.h" +#include "hid_color.h" + +const char *nelma_cookie = "nelma HID"; + +#define CRASH(func) fprintf(stderr, "HID error: pcb called unimplemented PNG function %s.\n", func); abort() + +/* Needed for PNG export */ + +struct color_struct { + /* the descriptor used by the gd library */ + int c; + + /* so I can figure out what rgb value c refers to */ + unsigned int r, g, b; +}; + +struct hid_gc_s { + pcb_core_gc_t core_gc; + pcb_hid_t *me_pointer; + pcb_cap_style_t cap; + pcb_coord_t width; + unsigned char r, g, b; + int erase; + int faded; + struct color_struct *color; + gdImagePtr brush; +}; + +static pcb_hid_t nelma_hid; + +static struct color_struct *black = NULL, *white = NULL; +static pcb_coord_t linewidth = -1; +static gdImagePtr lastbrush = (gdImagePtr) ((void *) -1); +static int lastcolor = -1; + +/* gd image and file for PNG export */ +static gdImagePtr nelma_im = NULL; +static FILE *nelma_f = NULL; + +static int is_mask; +static int is_drill; + +/* + * Which groups of layers to export into PNG layer masks. 1 means export, 0 + * means do not export. + */ +static int nelma_export_group[PCB_MAX_LAYERGRP]; + +/* Group that is currently exported. */ +static int nelma_cur_group; + +/* Filename prefix that will be used when saving files. */ +static const char *nelma_basename = NULL; + +/* Horizontal DPI (grid points per inch) */ +static int nelma_dpi = -1; + +/* Height of the copper layers in micrometers. */ + +/* + * The height of the copper layer is currently taken as the vertical grid + * step, since this is the smallest vertical feature in the layout. + */ +static int nelma_copperh = -1; +/* Height of the substrate layers in micrometers. */ +static int nelma_substrateh = -1; +/* Relative permittivity of the substrate. */ +static double nelma_substratee = -1; + +/* Permittivity of empty space (As/Vm) */ +static const double nelma_air_epsilon = 8.85e-12; + +pcb_hid_attribute_t nelma_attribute_list[] = { + /* other HIDs expect this to be first. */ + +/* %start-doc options "nelma Options" +@ftable @code +@item -- basename +File name prefix. +@end ftable +%end-doc +*/ + {"basename", "File name prefix", + PCB_HATT_STRING, 0, 0, {0, 0, 0}, 0, 0}, +#define HA_basename 0 + +/* %start-doc options "nelma Options" +@ftable @code +@item --dpi +Horizontal scale factor (grid points/inch). +@end ftable +%end-doc +*/ + {"dpi", "Horizontal scale factor (grid points/inch)", + PCB_HATT_INTEGER, 0, 1000, {100, 0, 0}, 0, 0}, +#define HA_dpi 1 + +/* %start-doc options "nelma Options" +@ftable @code +@item --copper-height +Copper layer height (um). +@end ftable +%end-doc +*/ + {"copper-height", "Copper layer height (um)", + PCB_HATT_INTEGER, 0, 200, {100, 0, 0}, 0, 0}, +#define HA_copperh 2 + +/* %start-doc options "nelma Options" +@ftable @code +@item --substrate-height +Substrate layer height (um). +@end ftable +%end-doc +*/ + {"substrate-height", "Substrate layer height (um)", + PCB_HATT_INTEGER, 0, 10000, {2000, 0, 0}, 0, 0}, +#define HA_substrateh 3 + +/* %start-doc options "nelma Options" +@ftable @code +@item --substrate-epsilon +Substrate relative epsilon. +@end ftable +%end-doc +*/ + {"substrate-epsilon", "Substrate relative epsilon", + PCB_HATT_REAL, 0, 100, {0, 0, 4.0}, 0, 0}, +#define HA_substratee 4 +}; + +#define NUM_OPTIONS (sizeof(nelma_attribute_list)/sizeof(nelma_attribute_list[0])) + +PCB_REGISTER_ATTRIBUTES(nelma_attribute_list, nelma_cookie) + static pcb_hid_attr_val_t nelma_values[NUM_OPTIONS]; + +/* *** Utility funcions **************************************************** */ + +/* convert from default PCB units to nelma units */ + static int pcb_to_nelma(pcb_coord_t pcb) +{ + return PCB_COORD_TO_INCH(pcb) * nelma_dpi; +} + +static char *nelma_get_png_name(const char *basename, const char *suffix) +{ + char *buf; + int len; + + len = strlen(basename) + strlen(suffix) + 6; + buf = (char *) malloc(sizeof(*buf) * len); + + sprintf(buf, "%s.%s.png", basename, suffix); + + return buf; +} + +/* *** Exporting netlist data and geometry to the nelma config file ******** */ + +static void nelma_write_space(FILE * out) +{ + double xh, zh; + int z, i; + + xh = 2.54e-2 / ((double) nelma_dpi); + zh = nelma_copperh * 1e-6; + + fprintf(out, "\n/* **** Space **** */\n\n"); + + fprintf(out, "space pcb {\n"); + fprintf(out, "\tstep = { %e, %e, %e }\n", xh, xh, zh); + fprintf(out, "\tlayers = {\n"); + + fprintf(out, "\t\t\"air-top\",\n"); + fprintf(out, "\t\t\"air-bottom\""); + + z = 10; + for (i = 0; i < PCB_MAX_LAYERGRP; i++) + if (nelma_export_group[i]) { + char tmp_ln[PCB_PATH_MAX]; + const char *ext = pcb_layer_to_file_name(tmp_ln, -1, pcb_layergrp_flags(PCB, i), PCB->LayerGroups.grp[i].purpose, PCB->LayerGroups.grp[i].purpi, PCB_FNS_fixed); + + if (z != 10) { + fprintf(out, ",\n"); + fprintf(out, "\t\t\"substrate-%d\"", z); + z++; + } + fprintf(out, ",\n"); + fprintf(out, "\t\t\"%s\"", ext); + z++; + } + fprintf(out, "\n\t}\n"); + fprintf(out, "}\n"); +} + + +static void nelma_write_material(FILE * out, const char *name, const char *type, double e) +{ + fprintf(out, "material %s {\n", name); + fprintf(out, "\ttype = \"%s\"\n", type); + fprintf(out, "\tpermittivity = %e\n", e); + fprintf(out, "\tconductivity = 0.0\n"); + fprintf(out, "\tpermeability = 0.0\n"); + fprintf(out, "}\n"); +} + +static void nelma_write_materials(FILE * out) +{ + fprintf(out, "\n/* **** Materials **** */\n\n"); + + nelma_write_material(out, "copper", "metal", nelma_air_epsilon); + nelma_write_material(out, "air", "dielectric", nelma_air_epsilon); + nelma_write_material(out, "composite", "dielectric", nelma_air_epsilon * nelma_substratee); +} + +static void nelma_write_nets(FILE * out) +{ + pcb_lib_t netlist; + pcb_lib_menu_t *net; + pcb_lib_entry_t *pin; + + int n, m, i; + + netlist = PCB->NetlistLib[PCB_NETLIST_EDITED]; + + fprintf(out, "\n/* **** Nets **** */\n\n"); + + for (n = 0; n < netlist.MenuN; n++) { + net = &netlist.Menu[n]; + + /* Weird, but correct */ + fprintf(out, "net %s {\n", &net->Name[2]); + + fprintf(out, "\tobjects = {\n"); + + for (m = 0; m < net->EntryN; m++) { + pin = &net->Entry[m]; + + /* pcb_pin_name_to_xy(pin, &x, &y); */ + + for (i = 0; i < PCB_MAX_LAYERGRP; i++) + if (nelma_export_group[i]) { + char tmp_ln[PCB_PATH_MAX]; + const char *ext = pcb_layer_to_file_name(tmp_ln, -1, pcb_layergrp_flags(PCB, i), PCB->LayerGroups.grp[i].purpose, PCB->LayerGroups.grp[i].purpi, PCB_FNS_fixed); + + if (m != 0 || i != 0) + fprintf(out, ",\n"); + fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry, ext); + } + } + + fprintf(out, "\n"); + fprintf(out, "\t}\n"); + fprintf(out, "}\n"); + } +} + +static void nelma_write_layer(FILE * out, int z, int h, const char *name, int full, const char *mat) +{ + pcb_lib_t netlist; + pcb_lib_menu_t *net; + pcb_lib_entry_t *pin; + + int n, m; + + fprintf(out, "layer %s {\n", name); + fprintf(out, "\theight = %d\n", h); + fprintf(out, "\tz-order = %d\n", z); + fprintf(out, "\tmaterial = \"%s\"\n", mat); + + if (full) { + fprintf(out, "\tobjects = {\n"); + netlist = PCB->NetlistLib[PCB_NETLIST_EDITED]; + + for (n = 0; n < netlist.MenuN; n++) { + net = &netlist.Menu[n]; + + for (m = 0; m < net->EntryN; m++) { + pin = &net->Entry[m]; + + if (m != 0 || n != 0) + fprintf(out, ",\n"); + fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry, name); + } + + } + fprintf(out, "\n\t}\n"); + } + fprintf(out, "}\n"); +} + +static void nelma_write_layers(FILE * out) +{ + int i, subh, z; + char buf[100]; + + subh = nelma_substrateh / nelma_copperh; + + fprintf(out, "\n/* **** Layers **** */\n\n"); + + /* Air layers on top and bottom of the stack */ + /* Their height is double substrate height. */ + nelma_write_layer(out, 1, 2 * subh, "air-top", 0, "air"); + nelma_write_layer(out, 1000, 2 * subh, "air-bottom", 0, "air"); + + z = 10; + for (i = 0; i < PCB_MAX_LAYERGRP; i++) + if (nelma_export_group[i]) { + char tmp_ln[PCB_PATH_MAX]; + const char *ext = pcb_layer_to_file_name(tmp_ln, -1, pcb_layergrp_flags(PCB, i), PCB->LayerGroups.grp[i].purpose, PCB->LayerGroups.grp[i].purpi, PCB_FNS_fixed); + + if (z != 10) { + sprintf(buf, "substrate-%d", z); + nelma_write_layer(out, z, subh, buf, 0, "composite"); + z++; + } + /* + * FIXME: for layers that are not on top or bottom, + * the material should be "composite" + */ + nelma_write_layer(out, z, 1, ext, 1, "air"); + + z++; + } +} + +static void nelma_write_object(FILE * out, pcb_lib_entry_t *pin) +{ + pcb_coord_t px = 0, py = 0; + int x, y, i; + char *f; + + pcb_pin_name_to_xy(pin, &px, &py); + + x = pcb_to_nelma(px); + y = pcb_to_nelma(py); + + for (i = 0; i < PCB_MAX_LAYERGRP; i++) + if (nelma_export_group[i]) { + char tmp_ln[PCB_PATH_MAX]; + const char *ext = pcb_layer_to_file_name(tmp_ln, -1, pcb_layergrp_flags(PCB, i), PCB->LayerGroups.grp[i].purpose, PCB->LayerGroups.grp[i].purpi, PCB_FNS_fixed); + + fprintf(out, "object %s-%s {\n", pin->ListEntry, ext); + fprintf(out, "\tposition = { 0, 0 }\n"); + fprintf(out, "\tmaterial = \"copper\"\n"); + fprintf(out, "\ttype = \"image\"\n"); + fprintf(out, "\trole = \"net\"\n"); + + f = nelma_get_png_name(nelma_basename, ext); + + fprintf(out, "\tfile = \"%s\"\n", f); + + free(f); + + fprintf(out, "\tfile-pos = { %d, %d }\n", x, y); + fprintf(out, "}\n"); + } +} + +static void nelma_write_objects(FILE * out) +{ + pcb_lib_t netlist; + pcb_lib_menu_t *net; + pcb_lib_entry_t *pin; + + int n, m; + + netlist = PCB->NetlistLib[PCB_NETLIST_EDITED]; + + fprintf(out, "\n/* **** Objects **** */\n\n"); + + for (n = 0; n < netlist.MenuN; n++) { + net = &netlist.Menu[n]; + + for (m = 0; m < net->EntryN; m++) { + pin = &net->Entry[m]; + + nelma_write_object(out, pin); + } + } +} + +/* *** Main export callback ************************************************ */ + +static int nelma_parse_arguments(int *argc, char ***argv) +{ + pcb_hid_register_attributes(nelma_attribute_list, sizeof(nelma_attribute_list) / sizeof(nelma_attribute_list[0]), nelma_cookie, 0); + return pcb_hid_parse_command_line(argc, argv); +} + +static pcb_hid_attribute_t *nelma_get_export_options(int *n) +{ + static char *last_made_filename = 0; + + if (PCB) { + pcb_derive_default_filename(PCB->Filename, &nelma_attribute_list[HA_basename], ".nelma", &last_made_filename); + } + if (n) { + *n = NUM_OPTIONS; + } + return nelma_attribute_list; +} + +/* Populates nelma_export_group array */ +void nelma_choose_groups() +{ + int n, m; + pcb_layer_t *layer; + + /* Set entire array to 0 (don't export any layer groups by default */ + memset(nelma_export_group, 0, sizeof(nelma_export_group)); + + for (n = 0; n < pcb_max_layer; n++) { + unsigned int flags = pcb_layer_flags(PCB, n); + if (flags & PCB_LYT_SILK) + continue; + layer = &PCB->Data->Layer[n]; + + if (!pcb_layer_is_empty_(PCB, layer)) { + /* layer isn't empty */ + if ((flags & PCB_LYT_COPPER) || PCB_LAYER_IS_ROUTE(flags, pcb_layer_purpose_(layer, NULL))) { + /* layer is a copper layer */ + m = pcb_layer_get_group(PCB, n); + + /* the export layer */ + nelma_export_group[m] = 1; + } + } + } +} + +static void nelma_alloc_colors() +{ + /* + * Allocate white and black -- the first color allocated becomes the + * background color + */ + + white = (struct color_struct *) malloc(sizeof(*white)); + white->r = white->g = white->b = 255; + white->c = gdImageColorAllocate(nelma_im, white->r, white->g, white->b); + + black = (struct color_struct *) malloc(sizeof(*black)); + black->r = black->g = black->b = 0; + black->c = gdImageColorAllocate(nelma_im, black->r, black->g, black->b); +} + +static void nelma_start_png(const char *basename, const char *suffix) +{ + int h, w; + char *buf; + + buf = nelma_get_png_name(basename, suffix); + + h = pcb_to_nelma(PCB->MaxHeight); + w = pcb_to_nelma(PCB->MaxWidth); + + /* nelma_im = gdImageCreate (w, h); */ + + /* Nelma only works with true color images */ + nelma_im = gdImageCreate(w, h); + nelma_f = pcb_fopen(buf, "wb"); + + nelma_alloc_colors(); + + free(buf); +} + +static void nelma_finish_png() +{ +#ifdef HAVE_GDIMAGEPNG + gdImagePng(nelma_im, nelma_f); +#else + pcb_message(PCB_MSG_WARNING, "NELMA: PNG not supported by gd. Can't write layer mask.\n"); +#endif + gdImageDestroy(nelma_im); + fclose(nelma_f); + + free(white); + free(black); + + nelma_im = NULL; + nelma_f = NULL; +} + +void nelma_start_png_export() +{ + pcb_hid_expose_ctx_t ctx; + + ctx.view.X1 = 0; + ctx.view.Y1 = 0; + ctx.view.X2 = PCB->MaxWidth; + ctx.view.Y2 = PCB->MaxHeight; + + linewidth = -1; + lastbrush = (gdImagePtr) ((void *) -1); + lastcolor = -1; + + pcb_hid_expose_all(&nelma_hid, &ctx); +} + +static void nelma_do_export(pcb_hid_attr_val_t * options) +{ + int save_ons[PCB_MAX_LAYER + 2]; + int i, len; + FILE *nelma_config; + char *buf; + time_t t; + + if (!options) { + nelma_get_export_options(0); + for (i = 0; i < NUM_OPTIONS; i++) { + nelma_values[i] = nelma_attribute_list[i].default_val; + } + options = nelma_values; + } + nelma_basename = options[HA_basename].str_value; + if (!nelma_basename) { + nelma_basename = "pcb-out"; + } + nelma_dpi = options[HA_dpi].int_value; + if (nelma_dpi < 0) { + fprintf(stderr, "ERROR: dpi may not be < 0\n"); + return; + } + nelma_copperh = options[HA_copperh].int_value; + nelma_substrateh = options[HA_substrateh].int_value; + nelma_substratee = options[HA_substratee].real_value; + + nelma_choose_groups(); + + for (i = 0; i < PCB_MAX_LAYERGRP; i++) { + if (nelma_export_group[i]) { + char tmp_ln[PCB_PATH_MAX]; + const char *ext = pcb_layer_to_file_name(tmp_ln, -1, pcb_layergrp_flags(PCB, i), PCB->LayerGroups.grp[i].purpose, PCB->LayerGroups.grp[i].purpi, PCB_FNS_fixed); + + nelma_cur_group = i; + + nelma_start_png(nelma_basename, ext); + + pcb_hid_save_and_show_layer_ons(save_ons); + nelma_start_png_export(); + pcb_hid_restore_layer_ons(save_ons); + + nelma_finish_png(); + } + } + + len = strlen(nelma_basename) + 4; + buf = (char *) malloc(sizeof(*buf) * len); + + sprintf(buf, "%s.em", nelma_basename); + nelma_config = pcb_fopen(buf, "w"); + + free(buf); + + fprintf(nelma_config, "/* Made with PCB Nelma export HID */"); + t = time(NULL); + fprintf(nelma_config, "/* %s */", ctime(&t)); + + nelma_write_nets(nelma_config); + nelma_write_objects(nelma_config); + nelma_write_layers(nelma_config); + nelma_write_materials(nelma_config); + nelma_write_space(nelma_config); + + fclose(nelma_config); +} + +/* *** PNG export (slightly modified code from PNG export HID) ************* */ + +static int nelma_set_layer_group(pcb_layergrp_id_t group, const char *purpose, int purpi, pcb_layer_id_t layer, unsigned int flags, int is_empty, pcb_xform_t **xform) +{ + if (flags & PCB_LYT_INVIS) + return 0; + + if ((flags & PCB_LYT_ANYTHING) == PCB_LYT_SILK) + return 0; + + is_drill = PCB_LAYER_IS_DRILL(flags, purpi); + is_mask = !!(flags & PCB_LYT_MASK); + + if (is_mask) { + /* Don't print masks */ + return 0; + } + if (is_drill) { + /* + * Print 'holes', so that we can fill gaps in the copper + * layer + */ + return 1; + } + if (group == nelma_cur_group) { + return 1; + } + return 0; +} + +static pcb_hid_gc_t nelma_make_gc(void) +{ + pcb_hid_gc_t rv = (pcb_hid_gc_t) malloc(sizeof(struct hid_gc_s)); + rv->me_pointer = &nelma_hid; + rv->cap = pcb_cap_round; + rv->width = 1; + rv->color = (struct color_struct *) malloc(sizeof(*rv->color)); + rv->color->r = rv->color->g = rv->color->b = 0; + rv->color->c = 0; + return rv; +} + +static void nelma_destroy_gc(pcb_hid_gc_t gc) +{ + free(gc); +} + +static void nelma_set_color(pcb_hid_gc_t gc, const char *name) +{ + if (nelma_im == NULL) { + return; + } + if (name == NULL) { + name = "#ff0000"; + } + if (!strcmp(name, "drill")) { + gc->color = black; + gc->erase = 0; + return; + } + gc->color = black; + gc->erase = 0; + return; +} + +static void nelma_set_line_cap(pcb_hid_gc_t gc, pcb_cap_style_t style) +{ + gc->cap = style; +} + +static void nelma_set_line_width(pcb_hid_gc_t gc, pcb_coord_t width) +{ + gc->width = width; +} + +static void nelma_set_draw_xor(pcb_hid_gc_t gc, int xor_) +{ + ; +} + +static void nelma_set_draw_faded(pcb_hid_gc_t gc, int faded) +{ + gc->faded = faded; +} + +static void use_gc(pcb_hid_gc_t gc) +{ + int need_brush = 0; + + if (gc->me_pointer != &nelma_hid) { + fprintf(stderr, "Fatal: GC from another HID passed to nelma HID\n"); + abort(); + } + if (linewidth != gc->width) { + /* Make sure the scaling doesn't erase lines completely */ + /* + if (SCALE (gc->width) == 0 && gc->width > 0) + gdImageSetThickness (im, 1); + else + */ + gdImageSetThickness(nelma_im, pcb_to_nelma(gc->width)); + linewidth = gc->width; + need_brush = 1; + } + if (lastbrush != gc->brush || need_brush) { + static void *bcache = 0; + pcb_hidval_t bval; + char name[256]; + char type; + int r; + + switch (gc->cap) { + case pcb_cap_round: + type = 'C'; + r = pcb_to_nelma(gc->width / 2); + break; + case pcb_cap_square: + r = pcb_to_nelma(gc->width); + type = 'S'; + break; + default: + assert(!"unhandled cap"); + type = 'C'; + r = 1; + } + sprintf(name, "#%.2x%.2x%.2x_%c_%d", gc->color->r, gc->color->g, gc->color->b, type, r); + + if (pcb_hid_cache_color(0, name, &bval, &bcache)) { + gc->brush = (gdImagePtr) bval.ptr; + } + else { + int bg, fg; + if (type == 'C') + gc->brush = gdImageCreate(2 * r + 1, 2 * r + 1); + else + gc->brush = gdImageCreate(r + 1, r + 1); + bg = gdImageColorAllocate(gc->brush, 255, 255, 255); + fg = gdImageColorAllocate(gc->brush, gc->color->r, gc->color->g, gc->color->b); + gdImageColorTransparent(gc->brush, bg); + + /* + * if we shrunk to a radius/box width of zero, then just use + * a single pixel to draw with. + */ + if (r == 0) + gdImageFilledRectangle(gc->brush, 0, 0, 0, 0, fg); + else { + if (type == 'C') + gdImageFilledEllipse(gc->brush, r, r, 2 * r, 2 * r, fg); + else + gdImageFilledRectangle(gc->brush, 0, 0, r, r, fg); + } + bval.ptr = gc->brush; + pcb_hid_cache_color(1, name, &bval, &bcache); + } + + gdImageSetBrush(nelma_im, gc->brush); + lastbrush = gc->brush; + + } +#define CBLEND(gc) (((gc->r)<<24)|((gc->g)<<16)|((gc->b)<<8)|(gc->faded)) + if (lastcolor != CBLEND(gc)) { + if (is_drill || is_mask) { +#ifdef FIXME + fprintf(f, "%d gray\n", gc->erase ? 0 : 1); +#endif + lastcolor = 0; + } + else { + double r, g, b; + r = gc->r; + g = gc->g; + b = gc->b; + if (gc->faded) { + r = 0.8 * 255 + 0.2 * r; + g = 0.8 * 255 + 0.2 * g; + b = 0.8 * 255 + 0.2 * b; + } +#ifdef FIXME + if (gc->r == gc->g && gc->g == gc->b) + fprintf(f, "%g gray\n", r / 255.0); + else + fprintf(f, "%g %g %g rgb\n", r / 255.0, g / 255.0, b / 255.0); +#endif + lastcolor = CBLEND(gc); + } + } +} + +static void nelma_draw_rect(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2, pcb_coord_t y2) +{ + use_gc(gc); + gdImageRectangle(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1), pcb_to_nelma(x2), pcb_to_nelma(y2), gc->color->c); +} + +static void nelma_fill_rect(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2, pcb_coord_t y2) +{ + use_gc(gc); + gdImageSetThickness(nelma_im, 0); + linewidth = 0; + gdImageFilledRectangle(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1), pcb_to_nelma(x2), pcb_to_nelma(y2), gc->color->c); +} + +static void nelma_draw_line(pcb_hid_gc_t gc, pcb_coord_t x1, pcb_coord_t y1, pcb_coord_t x2, pcb_coord_t y2) +{ + if (x1 == x2 && y1 == y2) { + pcb_coord_t w = gc->width / 2; + nelma_fill_rect(gc, x1 - w, y1 - w, x1 + w, y1 + w); + return; + } + use_gc(gc); + + gdImageSetThickness(nelma_im, 0); + linewidth = 0; + gdImageLine(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1), pcb_to_nelma(x2), pcb_to_nelma(y2), gdBrushed); +} + +static void nelma_draw_arc(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t width, pcb_coord_t height, pcb_angle_t start_angle, pcb_angle_t delta_angle) +{ + pcb_angle_t sa, ea; + + /* + * in gdImageArc, 0 degrees is to the right and +90 degrees is down + * in pcb, 0 degrees is to the left and +90 degrees is down + */ + start_angle = 180 - start_angle; + delta_angle = -delta_angle; + if (delta_angle > 0) { + sa = start_angle; + ea = start_angle + delta_angle; + } + else { + sa = start_angle + delta_angle; + ea = start_angle; + } + + /* + * make sure we start between 0 and 360 otherwise gd does strange + * things + */ + sa = pcb_normalize_angle(sa); + ea = pcb_normalize_angle(ea); + +#if 0 + printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n", cx, cy, width, height, start_angle, delta_angle, sa, ea); + printf("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n", + (void *)im, SCALE_X(cx), SCALE_Y(cy), SCALE(width), SCALE(height), sa, ea, gc->color->c); +#endif + use_gc(gc); + gdImageSetThickness(nelma_im, 0); + linewidth = 0; + gdImageArc(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy), + pcb_to_nelma(2 * width), pcb_to_nelma(2 * height), sa, ea, gdBrushed); +} + +static void nelma_fill_circle(pcb_hid_gc_t gc, pcb_coord_t cx, pcb_coord_t cy, pcb_coord_t radius) +{ + use_gc(gc); + + gdImageSetThickness(nelma_im, 0); + linewidth = 0; + gdImageFilledEllipse(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy), + pcb_to_nelma(2 * radius), pcb_to_nelma(2 * radius), gc->color->c); + +} + +static void nelma_fill_polygon_offs(pcb_hid_gc_t gc, int n_coords, pcb_coord_t *x, pcb_coord_t *y, pcb_coord_t dx, pcb_coord_t dy) +{ + int i; + gdPoint *points; + + points = (gdPoint *) malloc(n_coords * sizeof(gdPoint)); + if (points == NULL) { + fprintf(stderr, "ERROR: nelma_fill_polygon(): malloc failed\n"); + exit(1); + } + use_gc(gc); + for (i = 0; i < n_coords; i++) { + points[i].x = pcb_to_nelma(x[i]+dx); + points[i].y = pcb_to_nelma(y[i]+dy); + } + gdImageSetThickness(nelma_im, 0); + linewidth = 0; + gdImageFilledPolygon(nelma_im, points, n_coords, gc->color->c); + free(points); +} + +static void nelma_fill_polygon(pcb_hid_gc_t gc, int n_coords, pcb_coord_t *x, pcb_coord_t *y) +{ + nelma_fill_polygon_offs(gc, n_coords, x, y, 0, 0); +} + + +static void nelma_calibrate(double xval, double yval) +{ + CRASH("nelma_calibrate"); +} + +static void nelma_set_crosshair(pcb_coord_t x, pcb_coord_t y, int a) +{ +} + +static int nelma_usage(const char *topic) +{ + fprintf(stderr, "\nnelma exporter command line arguments:\n\n"); + pcb_hid_usage(nelma_attribute_list, sizeof(nelma_attribute_list) / sizeof(nelma_attribute_list[0])); + fprintf(stderr, "\nUsage: pcb-rnd [generic_options] -x nelma [nelma options] foo.pcb\n\n"); + return 0; +} + +/* *** Miscellaneous ******************************************************* */ + +#include "dolists.h" + +int pplg_check_ver_export_nelma(int ver_needed) { return 0; } + +int pplg_uninit_export_nelma(void) +{ + pcb_hid_remove_attributes_by_cookie(nelma_cookie); + return 0; +} + +int pplg_init_export_nelma(void) +{ + PCB_API_CHK_VER; + + memset(&nelma_hid, 0, sizeof(pcb_hid_t)); + + pcb_hid_nogui_init(&nelma_hid); + pcb_dhlp_draw_helpers_init(&nelma_hid); + + nelma_hid.struct_size = sizeof(pcb_hid_t); + nelma_hid.name = "nelma"; + nelma_hid.description = "Numerical analysis package export"; + nelma_hid.exporter = 1; + + nelma_hid.get_export_options = nelma_get_export_options; + nelma_hid.do_export = nelma_do_export; + nelma_hid.parse_arguments = nelma_parse_arguments; + nelma_hid.set_layer_group = nelma_set_layer_group; + nelma_hid.make_gc = nelma_make_gc; + nelma_hid.destroy_gc = nelma_destroy_gc; + nelma_hid.set_color = nelma_set_color; + nelma_hid.set_line_cap = nelma_set_line_cap; + nelma_hid.set_line_width = nelma_set_line_width; + nelma_hid.set_draw_xor = nelma_set_draw_xor; + nelma_hid.set_draw_faded = nelma_set_draw_faded; + nelma_hid.draw_line = nelma_draw_line; + nelma_hid.draw_arc = nelma_draw_arc; + nelma_hid.draw_rect = nelma_draw_rect; + nelma_hid.fill_circle = nelma_fill_circle; + nelma_hid.fill_polygon = nelma_fill_polygon; + nelma_hid.fill_polygon_offs = nelma_fill_polygon_offs; + nelma_hid.fill_rect = nelma_fill_rect; + nelma_hid.calibrate = nelma_calibrate; + nelma_hid.set_crosshair = nelma_set_crosshair; + + nelma_hid.usage = nelma_usage; + + pcb_hid_register_hid(&nelma_hid); + return 0; +}