Index: export_nelma/Makefile =================================================================== --- export_nelma/Makefile (nonexistent) +++ 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: export_nelma/Plug.tmpasm =================================================================== --- export_nelma/Plug.tmpasm (nonexistent) +++ 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: export_nelma/export_nelma.pup =================================================================== --- export_nelma/export_nelma.pup (nonexistent) +++ 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: export_nelma/nelma.c =================================================================== --- export_nelma/nelma.c (nonexistent) +++ 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; +}