Add support for filling / thindrawing raw polygons to the HID interface
[geda-pcb/gde.git] / src / hid / nelma / nelma.c
blobd06193caf1dc8bbe263622587e72f591e816ee32
1 /*
2 * COPYRIGHT
4 * PCB, interactive printed circuit board design
6 * NELMA (Numerical capacitance calculator) export HID
7 * Copyright (C) 2006 Tomaz Solc (tomaz.solc@tablix.org)
9 * PNG export code is based on the PNG export HID
10 * Copyright (C) 2006 Dan McMahill
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 * This HID exports a PCB layout into: o One layer mask file (PNG format) per
30 * copper layer. o Nelma configuration file that contains netlist and pin
31 * information.
35 * FIXME:
37 * If you have a section of a net that does not contain any pins then that
38 * section will be missing from the Nelma's copper geometry.
40 * For example:
42 * this section will be ignored by Nelma | |
44 * || ||=======|| || component layer ||
45 * || || || ||=============|| ||============||
46 * solder layer
48 * pin1 via via pin2
50 * Single layer layouts are always exported correctly.
54 #ifdef HAVE_CONFIG_H
55 #include "config.h"
56 #endif
58 #include <stdio.h>
59 #include <stdarg.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <assert.h>
64 #include <time.h>
66 #include "global.h"
67 #include "data.h"
68 #include "misc.h"
69 #include "rats.h"
71 #include "hid.h"
72 #include "../hidint.h"
73 #include "hid/common/draw_helpers.h"
74 #include "nelma.h"
76 #include <gd.h>
78 #ifdef HAVE_LIBDMALLOC
79 #include <dmalloc.h>
80 #endif
82 RCSID("$Id$");
84 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented PNG function %s.\n", __FUNCTION__); abort()
86 /* Needed for PNG export */
88 struct color_struct {
89 /* the descriptor used by the gd library */
90 int c;
92 /* so I can figure out what rgb value c refers to */
93 unsigned int r, g, b;
96 struct hid_gc_struct {
97 HID *me_pointer;
98 EndCapStyle cap;
99 int width;
100 unsigned char r, g, b;
101 int erase;
102 int faded;
103 struct color_struct *color;
104 gdImagePtr brush;
107 static struct color_struct *black = NULL, *white = NULL;
108 static int linewidth = -1;
109 static int lastgroup = -1;
110 static gdImagePtr lastbrush = (void *) -1;
111 static int lastcap = -1;
112 static int lastcolor = -1;
114 /* gd image and file for PNG export */
115 static gdImagePtr nelma_im = NULL;
116 static FILE *nelma_f = NULL;
118 static int is_mask;
119 static int is_drill;
122 * Which groups of layers to export into PNG layer masks. 1 means export, 0
123 * means do not export.
125 static int nelma_export_group[MAX_LAYER];
127 /* Group that is currently exported. */
128 static int nelma_cur_group;
130 /* Filename prefix that will be used when saving files. */
131 static char *nelma_basename = NULL;
133 /* Horizontal DPI (grid points per inch) */
134 static int nelma_dpi = -1;
136 /* Height of the copper layers in micrometers. */
139 * The height of the copper layer is currently taken as the vertical grid
140 * step, since this is the smallest vertical feature in the layout.
142 static int nelma_copperh = -1;
143 /* Height of the substrate layers in micrometers. */
144 static int nelma_substrateh = -1;
145 /* Relative permittivity of the substrate. */
146 static double nelma_substratee = -1;
148 /* Permittivity of empty space (As/Vm) */
149 static const double nelma_air_epsilon = 8.85e-12;
151 HID_Attribute nelma_attribute_list[] = {
152 /* other HIDs expect this to be first. */
153 {"basename", "File name prefix",
154 HID_String, 0, 0, {0, 0, 0}, 0, 0},
155 #define HA_basename 0
157 {"dpi", "Horizontal scale factor (grid points/inch).",
158 HID_Integer, 0, 1000, {100, 0, 0}, 0, 0},
159 #define HA_dpi 1
161 {"copper-height", "Copper layer height (um).",
162 HID_Integer, 0, 200, {100, 0, 0}, 0, 0},
163 #define HA_copperh 2
165 {"substrate-height", "Substrate layer height (um).",
166 HID_Integer, 0, 10000, {2000, 0, 0}, 0, 0},
167 #define HA_substrateh 3
169 {"substrate-epsilon", "Substrate relative epsilon.",
170 HID_Real, 0, 100, {0, 0, 4.0}, 0, 0},
171 #define HA_substratee 4
174 #define NUM_OPTIONS (sizeof(nelma_attribute_list)/sizeof(nelma_attribute_list[0]))
176 REGISTER_ATTRIBUTES(nelma_attribute_list)
177 static HID_Attr_Val nelma_values[NUM_OPTIONS];
179 /* *** Utility funcions **************************************************** */
181 /* convert from default PCB units (1/100 mil) to nelma units */
182 static int pcb_to_nelma(int pcb)
184 int nelma;
186 nelma = (pcb * nelma_dpi) / 100000;
188 return nelma;
191 static char *
192 nelma_get_png_name(const char *basename, const char *suffix)
194 char *buf;
195 int len;
197 len = strlen(basename) + strlen(suffix) + 6;
198 buf = malloc(sizeof(*buf) * len);
200 sprintf(buf, "%s.%s.png", basename, suffix);
202 return buf;
205 /* Retrieves coordinates (in default PCB units) of a pin or pad. */
206 /* Copied from netlist.c */
207 static int
208 pin_name_to_xy(LibraryEntryType * pin, int *x, int *y)
210 ConnectionType conn;
211 if (!SeekPad(pin, &conn, False))
212 return 1;
213 switch (conn.type) {
214 case PIN_TYPE:
215 *x = ((PinType *) (conn.ptr2))->X;
216 *y = ((PinType *) (conn.ptr2))->Y;
217 return 0;
218 case PAD_TYPE:
219 *x = ((PadType *) (conn.ptr2))->Point1.X;
220 *y = ((PadType *) (conn.ptr2))->Point1.Y;
221 return 0;
223 return 1;
226 /* *** Exporting netlist data and geometry to the nelma config file ******** */
228 static void
229 nelma_write_space(FILE * out)
231 double xh, zh;
233 int z;
234 int i, idx;
235 const char *ext;
237 xh = 2.54e-2 / ((double) nelma_dpi);
238 zh = nelma_copperh * 1e-6;
240 fprintf(out, "\n/* **** Space **** */\n\n");
242 fprintf(out, "space pcb {\n");
243 fprintf(out, "\tstep = { %e, %e, %e }\n", xh, xh, zh);
244 fprintf(out, "\tlayers = {\n");
246 fprintf(out, "\t\t\"air-top\",\n");
247 fprintf(out, "\t\t\"air-bottom\"");
249 z = 10;
250 for (i = 0; i < MAX_LAYER; i++)
251 if (nelma_export_group[i]) {
252 idx = (i >= 0 && i < max_layer) ?
253 PCB->LayerGroups.Entries[i][0] : i;
254 ext = layer_type_to_file_name(idx);
256 if (z != 10) {
257 fprintf(out, ",\n");
258 fprintf(out, "\t\t\"substrate-%d\"", z);
259 z++;
261 fprintf(out, ",\n");
262 fprintf(out, "\t\t\"%s\"", ext);
263 z++;
265 fprintf(out, "\n\t}\n");
266 fprintf(out, "}\n");
270 static void
271 nelma_write_material(FILE * out, char *name, char *type, double e)
273 fprintf(out, "material %s {\n", name);
274 fprintf(out, "\ttype = \"%s\"\n", type);
275 fprintf(out, "\tpermittivity = %e\n", e);
276 fprintf(out, "\tconductivity = 0.0\n");
277 fprintf(out, "\tpermeability = 0.0\n");
278 fprintf(out, "}\n");
281 static void
282 nelma_write_materials(FILE * out)
284 fprintf(out, "\n/* **** Materials **** */\n\n");
286 nelma_write_material(out, "copper", "metal", nelma_air_epsilon);
287 nelma_write_material(out, "air", "dielectric", nelma_air_epsilon);
288 nelma_write_material(out, "composite", "dielectric",
289 nelma_air_epsilon * nelma_substratee);
292 static void
293 nelma_write_nets(FILE * out)
295 LibraryType netlist;
296 LibraryMenuTypePtr net;
297 LibraryEntryTypePtr pin;
299 int n, m, i, idx;
301 const char *ext;
303 netlist = PCB->NetlistLib;
305 fprintf(out, "\n/* **** Nets **** */\n\n");
307 for (n = 0; n < netlist.MenuN; n++) {
308 net = &netlist.Menu[n];
310 /* Weird, but correct */
311 fprintf(out, "net %s {\n", &net->Name[2]);
313 fprintf(out, "\tobjects = {\n");
315 for (m = 0; m < net->EntryN; m++) {
316 pin = &net->Entry[m];
318 /* pin_name_to_xy(pin, &x, &y); */
320 for (i = 0; i < MAX_LAYER; i++)
321 if (nelma_export_group[i]) {
322 idx = (i >= 0 && i < max_layer) ?
323 PCB->LayerGroups.Entries[i][0] : i;
324 ext = layer_type_to_file_name(idx);
326 if (m != 0 || i != 0)
327 fprintf(out, ",\n");
328 fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry,
329 ext);
333 fprintf(out, "\n");
334 fprintf(out, "\t}\n");
335 fprintf(out, "}\n");
339 static void
340 nelma_write_layer(FILE * out, int z, int h,
341 const char *name, int full,
342 char *mat)
344 LibraryType netlist;
345 LibraryMenuTypePtr net;
346 LibraryEntryTypePtr pin;
348 int n, m;
350 fprintf(out, "layer %s {\n", name);
351 fprintf(out, "\theight = %d\n", h);
352 fprintf(out, "\tz-order = %d\n", z);
353 fprintf(out, "\tmaterial = \"%s\"\n", mat);
355 if (full) {
356 fprintf(out, "\tobjects = {\n");
357 netlist = PCB->NetlistLib;
359 for (n = 0; n < netlist.MenuN; n++) {
360 net = &netlist.Menu[n];
362 for (m = 0; m < net->EntryN; m++) {
363 pin = &net->Entry[m];
365 if (m != 0 || n != 0)
366 fprintf(out, ",\n");
367 fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry,
368 name);
372 fprintf(out, "\n\t}\n");
374 fprintf(out, "}\n");
377 static void
378 nelma_write_layers(FILE * out)
380 int i, idx;
381 int z;
383 const char *ext;
384 char buf[100];
386 int subh;
388 subh = nelma_substrateh / nelma_copperh;
390 fprintf(out, "\n/* **** Layers **** */\n\n");
392 /* Air layers on top and bottom of the stack */
393 /* Their height is double substrate height. */
394 nelma_write_layer(out, 1, 2 * subh, "air-top", 0, "air");
395 nelma_write_layer(out, 1000, 2 * subh, "air-bottom", 0, "air");
397 z = 10;
398 for (i = 0; i < MAX_LAYER; i++)
399 if (nelma_export_group[i]) {
400 idx = (i >= 0 && i < max_layer) ?
401 PCB->LayerGroups.Entries[i][0] : i;
402 ext = layer_type_to_file_name(idx);
404 if (z != 10) {
405 sprintf(buf, "substrate-%d", z);
406 nelma_write_layer(out,
408 subh,
409 buf,
411 "composite");
412 z++;
415 * FIXME: for layers that are not on top or bottom,
416 * the material should be "composite"
418 nelma_write_layer(out, z, 1, ext, 1, "air");
420 z++;
424 static void
425 nelma_write_object(FILE * out, LibraryEntryTypePtr pin)
427 int i, idx;
428 int x = 0, y = 0;
430 char *f;
431 const char *ext;
433 pin_name_to_xy(pin, &x, &y);
435 x = pcb_to_nelma(x);
436 y = pcb_to_nelma(y);
438 for (i = 0; i < MAX_LAYER; i++)
439 if (nelma_export_group[i]) {
440 idx = (i >= 0 && i < max_layer) ?
441 PCB->LayerGroups.Entries[i][0] : i;
442 ext = layer_type_to_file_name(idx);
444 fprintf(out, "object %s-%s {\n", pin->ListEntry, ext);
445 fprintf(out, "\tposition = { 0, 0 }\n");
446 fprintf(out, "\tmaterial = \"copper\"\n");
447 fprintf(out, "\ttype = \"image\"\n");
448 fprintf(out, "\trole = \"net\"\n");
450 f = nelma_get_png_name(nelma_basename, ext);
452 fprintf(out, "\tfile = \"%s\"\n", f);
454 free(f);
456 fprintf(out, "\tfile-pos = { %d, %d }\n", x, y);
457 fprintf(out, "}\n");
461 static void
462 nelma_write_objects(FILE * out)
464 LibraryType netlist;
465 LibraryMenuTypePtr net;
466 LibraryEntryTypePtr pin;
468 int n, m;
470 netlist = PCB->NetlistLib;
472 fprintf(out, "\n/* **** Objects **** */\n\n");
474 for (n = 0; n < netlist.MenuN; n++) {
475 net = &netlist.Menu[n];
477 for (m = 0; m < net->EntryN; m++) {
478 pin = &net->Entry[m];
480 nelma_write_object(out, pin);
485 /* *** Main export callback ************************************************ */
487 extern void hid_parse_command_line(int *argc, char ***argv);
489 static void
490 nelma_parse_arguments(int *argc, char ***argv)
492 hid_register_attributes(nelma_attribute_list,
493 sizeof(nelma_attribute_list) /
494 sizeof(nelma_attribute_list[0]));
495 hid_parse_command_line(argc, argv);
498 static HID_Attribute *
499 nelma_get_export_options(int *n)
501 static char *last_made_filename = 0;
503 if (PCB) {
504 derive_default_filename(PCB->Filename,
505 &nelma_attribute_list[HA_basename],
506 ".nelma",
507 &last_made_filename);
509 if (n) {
510 *n = NUM_OPTIONS;
512 return nelma_attribute_list;
515 /* Populates nelma_export_group array */
516 void
517 nelma_choose_groups()
519 int n, m;
520 LayerType *layer;
522 /* Set entire array to 0 (don't export any layer groups by default */
523 memset(nelma_export_group, 0, sizeof(nelma_export_group));
525 for (n = 0; n < max_layer; n++) {
526 layer = &PCB->Data->Layer[n];
528 if (layer->LineN || layer->TextN || layer->ArcN ||
529 layer->PolygonN) {
530 /* layer isn't empty */
533 * is this check necessary? It seems that special
534 * layers have negative indexes?
537 if (SL_TYPE(n) == 0) {
538 /* layer is a copper layer */
539 m = GetLayerGroupNumberByNumber(n);
541 /* the export layer */
542 nelma_export_group[m] = 1;
548 static void
549 nelma_alloc_colors()
552 * Allocate white and black -- the first color allocated becomes the
553 * background color
556 white = (struct color_struct *) malloc(sizeof(*white));
557 white->r = white->g = white->b = 255;
558 white->c = gdImageColorAllocate(nelma_im, white->r, white->g, white->b);
560 black = (struct color_struct *) malloc(sizeof(*black));
561 black->r = black->g = black->b = 0;
562 black->c = gdImageColorAllocate(nelma_im, black->r, black->g, black->b);
565 static void
566 nelma_start_png(const char *basename, const char *suffix)
568 int h, w;
569 char *buf;
571 buf = nelma_get_png_name(basename, suffix);
573 h = pcb_to_nelma(PCB->MaxHeight);
574 w = pcb_to_nelma(PCB->MaxWidth);
576 /* nelma_im = gdImageCreate (w, h); */
578 /* Nelma only works with true color images */
579 nelma_im = gdImageCreate(w, h);
580 nelma_f = fopen(buf, "wb");
582 nelma_alloc_colors();
584 free(buf);
587 static void
588 nelma_finish_png()
590 #ifdef HAVE_GDIMAGEPNG
591 gdImagePng(nelma_im, nelma_f);
592 #else
593 Message("NELMA: PNG not supported by gd. Can't write layer mask.\n");
594 #endif
595 gdImageDestroy(nelma_im);
596 fclose(nelma_f);
598 free(white);
599 free(black);
601 nelma_im = NULL;
602 nelma_f = NULL;
605 void
606 nelma_start_png_export()
608 BoxType region;
610 region.X1 = 0;
611 region.Y1 = 0;
612 region.X2 = PCB->MaxWidth;
613 region.Y2 = PCB->MaxHeight;
615 linewidth = -1;
616 lastbrush = (void *) -1;
617 lastcap = -1;
618 lastgroup = -1;
619 lastcolor = -1;
620 lastgroup = -1;
622 hid_expose_callback(&nelma_hid, &region, 0);
625 static void
626 nelma_do_export(HID_Attr_Val * options)
628 int save_ons[MAX_LAYER + 2];
629 int i, idx;
630 FILE *nelma_config;
631 char *buf;
632 int len;
634 time_t t;
636 if (!options) {
637 nelma_get_export_options(0);
638 for (i = 0; i < NUM_OPTIONS; i++) {
639 nelma_values[i] = nelma_attribute_list[i].default_val;
641 options = nelma_values;
643 nelma_basename = options[HA_basename].str_value;
644 if (!nelma_basename) {
645 nelma_basename = "pcb-out";
647 nelma_dpi = options[HA_dpi].int_value;
648 if (nelma_dpi < 0) {
649 fprintf(stderr, "ERROR: dpi may not be < 0\n");
650 return;
652 nelma_copperh = options[HA_copperh].int_value;
653 nelma_substrateh = options[HA_substrateh].int_value;
654 nelma_substratee = options[HA_substratee].real_value;
656 nelma_choose_groups();
658 for (i = 0; i < MAX_LAYER; i++) {
659 if (nelma_export_group[i]) {
661 nelma_cur_group = i;
663 /* magic */
664 idx = (i >= 0 && i < max_layer) ?
665 PCB->LayerGroups.Entries[i][0] : i;
667 nelma_start_png(nelma_basename,
668 layer_type_to_file_name(idx));
670 hid_save_and_show_layer_ons(save_ons);
671 nelma_start_png_export();
672 hid_restore_layer_ons(save_ons);
674 nelma_finish_png();
678 len = strlen(nelma_basename) + 4;
679 buf = malloc(sizeof(*buf) * len);
681 sprintf(buf, "%s.em", nelma_basename);
682 nelma_config = fopen(buf, "w");
684 free(buf);
686 fprintf(nelma_config, "/* Made with PCB Nelma export HID */");
687 t = time(NULL);
688 fprintf(nelma_config, "/* %s */", ctime(&t));
690 nelma_write_nets(nelma_config);
691 nelma_write_objects(nelma_config);
692 nelma_write_layers(nelma_config);
693 nelma_write_materials(nelma_config);
694 nelma_write_space(nelma_config);
696 fclose(nelma_config);
699 /* *** PNG export (slightly modified code from PNG export HID) ************* */
701 static int
702 nelma_set_layer(const char *name, int group, int empty)
704 int idx = (group >= 0 && group < max_layer) ?
705 PCB->LayerGroups.Entries[group][0] : group;
707 if (name == 0) {
708 name = PCB->Data->Layer[idx].Name;
710 if (strcmp(name, "invisible") == 0) {
711 return 0;
713 is_drill = (SL_TYPE(idx) == SL_PDRILL || SL_TYPE(idx) == SL_UDRILL);
714 is_mask = (SL_TYPE(idx) == SL_MASK);
716 if (is_mask) {
717 /* Don't print masks */
718 return 0;
720 if (is_drill) {
722 * Print 'holes', so that we can fill gaps in the copper
723 * layer
725 return 1;
727 if (group == nelma_cur_group) {
728 return 1;
730 return 0;
733 static hidGC
734 nelma_make_gc(void)
736 hidGC rv = (hidGC) malloc(sizeof(struct hid_gc_struct));
737 rv->me_pointer = &nelma_hid;
738 rv->cap = Trace_Cap;
739 rv->width = 1;
740 rv->color = (struct color_struct *) malloc(sizeof(*rv->color));
741 rv->color->r = rv->color->g = rv->color->b = 0;
742 rv->color->c = 0;
743 return rv;
746 static void
747 nelma_destroy_gc(hidGC gc)
749 free(gc);
752 static void
753 nelma_use_mask(int use_it)
755 /* does nothing */
758 static void
759 nelma_set_color(hidGC gc, const char *name)
761 if (nelma_im == NULL) {
762 return;
764 if (name == NULL) {
765 name = "#ff0000";
767 if (!strcmp(name, "drill")) {
768 gc->color = black;
769 gc->erase = 0;
770 return;
772 if (!strcmp(name, "erase")) {
773 /* FIXME -- should be background, not white */
774 gc->color = white;
775 gc->erase = 1;
776 return;
778 gc->color = black;
779 gc->erase = 0;
780 return;
783 static void
784 nelma_set_line_cap(hidGC gc, EndCapStyle style)
786 gc->cap = style;
789 static void
790 nelma_set_line_width(hidGC gc, int width)
792 gc->width = width;
795 static void
796 nelma_set_draw_xor(hidGC gc, int xor)
801 static void
802 nelma_set_draw_faded(hidGC gc, int faded)
804 gc->faded = faded;
807 static void
808 nelma_set_line_cap_angle(hidGC gc, int x1, int y1, int x2, int y2)
810 CRASH;
813 static void
814 use_gc(hidGC gc)
816 int need_brush = 0;
818 if (gc->me_pointer != &nelma_hid) {
819 fprintf(stderr, "Fatal: GC from another HID passed to nelma HID\n");
820 abort();
822 if (linewidth != gc->width) {
823 /* Make sure the scaling doesn't erase lines completely */
825 if (SCALE (gc->width) == 0 && gc->width > 0)
826 gdImageSetThickness (im, 1);
827 else
829 gdImageSetThickness(nelma_im, pcb_to_nelma(gc->width));
830 linewidth = gc->width;
831 need_brush = 1;
833 if (lastbrush != gc->brush || need_brush) {
834 static void *bcache = 0;
835 hidval bval;
836 char name[256];
837 char type;
838 int r;
840 switch (gc->cap) {
841 case Round_Cap:
842 case Trace_Cap:
843 type = 'C';
844 r = pcb_to_nelma(gc->width / 2);
845 break;
846 default:
847 case Square_Cap:
848 r = pcb_to_nelma(gc->width);
849 type = 'S';
850 break;
852 sprintf(name, "#%.2x%.2x%.2x_%c_%d", gc->color->r, gc->color->g,
853 gc->color->b, type, r);
855 if (hid_cache_color(0, name, &bval, &bcache)) {
856 gc->brush = bval.ptr;
857 } else {
858 int bg, fg;
859 if (type == 'C')
860 gc->brush = gdImageCreate(2 * r + 1, 2 * r + 1);
861 else
862 gc->brush = gdImageCreate(r + 1, r + 1);
863 bg = gdImageColorAllocate(gc->brush, 255, 255, 255);
864 fg =
865 gdImageColorAllocate(gc->brush, gc->color->r, gc->color->g,
866 gc->color->b);
867 gdImageColorTransparent(gc->brush, bg);
870 * if we shrunk to a radius/box width of zero, then just use
871 * a single pixel to draw with.
873 if (r == 0)
874 gdImageFilledRectangle(gc->brush, 0, 0, 0, 0, fg);
875 else {
876 if (type == 'C')
877 gdImageFilledEllipse(gc->brush, r, r, 2 * r, 2 * r, fg);
878 else
879 gdImageFilledRectangle(gc->brush, 0, 0, r, r, fg);
881 bval.ptr = gc->brush;
882 hid_cache_color(1, name, &bval, &bcache);
885 gdImageSetBrush(nelma_im, gc->brush);
886 lastbrush = gc->brush;
889 #define CBLEND(gc) (((gc->r)<<24)|((gc->g)<<16)|((gc->b)<<8)|(gc->faded))
890 if (lastcolor != CBLEND(gc)) {
891 if (is_drill || is_mask) {
892 #ifdef FIXME
893 fprintf(f, "%d gray\n", gc->erase ? 0 : 1);
894 #endif
895 lastcolor = 0;
896 } else {
897 double r, g, b;
898 r = gc->r;
899 g = gc->g;
900 b = gc->b;
901 if (gc->faded) {
902 r = 0.8 * 255 + 0.2 * r;
903 g = 0.8 * 255 + 0.2 * g;
904 b = 0.8 * 255 + 0.2 * b;
906 #ifdef FIXME
907 if (gc->r == gc->g && gc->g == gc->b)
908 fprintf(f, "%g gray\n", r / 255.0);
909 else
910 fprintf(f, "%g %g %g rgb\n", r / 255.0, g / 255.0, b / 255.0);
911 #endif
912 lastcolor = CBLEND(gc);
917 static void
918 nelma_draw_rect(hidGC gc, int x1, int y1, int x2, int y2)
920 use_gc(gc);
921 gdImageRectangle(nelma_im,
922 pcb_to_nelma(x1), pcb_to_nelma(y1),
923 pcb_to_nelma(x2), pcb_to_nelma(y2), gc->color->c);
926 static void
927 nelma_fill_rect(hidGC gc, int x1, int y1, int x2, int y2)
929 use_gc(gc);
930 gdImageSetThickness(nelma_im, 0);
931 linewidth = 0;
932 gdImageFilledRectangle(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1),
933 pcb_to_nelma(x2), pcb_to_nelma(y2), gc->color->c);
936 static void
937 nelma_draw_line(hidGC gc, int x1, int y1, int x2, int y2)
939 if (x1 == x2 && y1 == y2) {
940 int w = gc->width / 2;
941 nelma_fill_rect(gc, x1 - w, y1 - w, x1 + w, y1 + w);
942 return;
944 use_gc(gc);
946 gdImageSetThickness(nelma_im, 0);
947 linewidth = 0;
948 gdImageLine(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1),
949 pcb_to_nelma(x2), pcb_to_nelma(y2), gdBrushed);
952 static void
953 nelma_draw_arc(hidGC gc, int cx, int cy, int width, int height,
954 int start_angle, int delta_angle)
956 int sa, ea;
959 * in gdImageArc, 0 degrees is to the right and +90 degrees is down
960 * in pcb, 0 degrees is to the left and +90 degrees is down
962 start_angle = 180 - start_angle;
963 delta_angle = -delta_angle;
964 if (delta_angle > 0) {
965 sa = start_angle;
966 ea = start_angle + delta_angle;
967 } else {
968 sa = start_angle + delta_angle;
969 ea = start_angle;
973 * make sure we start between 0 and 360 otherwise gd does strange
974 * things
976 while (sa < 0) {
977 sa += 360;
978 ea += 360;
980 while (sa >= 360) {
981 sa -= 360;
982 ea -= 360;
985 #if 0
986 printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n",
987 cx, cy, width, height, start_angle, delta_angle, sa, ea);
988 printf("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n",
989 im, SCALE_X(cx), SCALE_Y(cy),
990 SCALE(width), SCALE(height), sa, ea, gc->color->c);
991 #endif
992 use_gc(gc);
993 gdImageSetThickness(nelma_im, 0);
994 linewidth = 0;
995 gdImageArc(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy),
996 pcb_to_nelma(2 * width), pcb_to_nelma(2 * height), sa, ea, gdBrushed);
999 static void
1000 nelma_fill_circle(hidGC gc, int cx, int cy, int radius)
1002 use_gc(gc);
1004 gdImageSetThickness(nelma_im, 0);
1005 linewidth = 0;
1006 gdImageFilledEllipse(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy),
1007 pcb_to_nelma(2 * radius), pcb_to_nelma(2 * radius), gc->color->c);
1011 static void
1012 nelma_fill_polygon(hidGC gc, int n_coords, int *x, int *y)
1014 int i;
1015 gdPoint *points;
1017 points = (gdPoint *) malloc(n_coords * sizeof(gdPoint));
1018 if (points == NULL) {
1019 fprintf(stderr, "ERROR: nelma_fill_polygon(): malloc failed\n");
1020 exit(1);
1022 use_gc(gc);
1023 for (i = 0; i < n_coords; i++) {
1024 points[i].x = pcb_to_nelma(x[i]);
1025 points[i].y = pcb_to_nelma(y[i]);
1027 gdImageSetThickness(nelma_im, 0);
1028 linewidth = 0;
1029 gdImageFilledPolygon(nelma_im, points, n_coords, gc->color->c);
1030 free(points);
1033 static void
1034 nelma_calibrate(double xval, double yval)
1036 CRASH;
1039 static void
1040 nelma_set_crosshair(int x, int y, int a)
1044 /* *** Miscellaneous ******************************************************* */
1046 HID nelma_hid = {
1047 sizeof(HID),
1048 "nelma",
1049 "Numerical analysis package export.",
1050 0, /* gui */
1051 0, /* printer */
1052 1, /* exporter */
1053 1, /* poly before */
1054 0, /* poly after */
1055 0, /* poly dicer */
1056 nelma_get_export_options,
1057 nelma_do_export,
1058 nelma_parse_arguments,
1059 0 /* nelma_invalidate_wh */ ,
1060 0 /* nelma_invalidate_lr */ ,
1061 0 /* nelma_invalidate_all */ ,
1062 nelma_set_layer,
1063 nelma_make_gc,
1064 nelma_destroy_gc,
1065 nelma_use_mask,
1066 nelma_set_color,
1067 nelma_set_line_cap,
1068 nelma_set_line_width,
1069 nelma_set_draw_xor,
1070 nelma_set_draw_faded,
1071 nelma_set_line_cap_angle,
1072 nelma_draw_line,
1073 nelma_draw_arc,
1074 nelma_draw_rect,
1075 nelma_fill_circle,
1076 nelma_fill_polygon,
1077 common_fill_pcb_polygon,
1078 0 /* nelma_thindraw_pcb_polygon */ ,
1079 nelma_fill_rect,
1080 nelma_calibrate,
1081 0 /* nelma_shift_is_pressed */ ,
1082 0 /* nelma_control_is_pressed */ ,
1083 0 /* nelma_get_coords */ ,
1084 nelma_set_crosshair,
1085 0 /* nelma_add_timer */ ,
1086 0 /* nelma_stop_timer */ ,
1087 0 /* nelma_watch_file */ ,
1088 0 /* nelma_unwatch_file */ ,
1089 0 /* nelma_add_block_hook */ ,
1090 0 /* nelma_stop_block_hook */ ,
1091 0 /* nelma_log */ ,
1092 0 /* nelma_logv */ ,
1093 0 /* nelma_confirm_dialog */ ,
1094 0 /* nelma_close_confirm_dialog */ ,
1095 0 /* nelma_report_dialog */ ,
1096 0 /* nelma_prompt_for */ ,
1097 0 /* nelma_fileselect */ ,
1098 0 /* nelma_attribute_dialog */ ,
1099 0 /* nelma_show_item */ ,
1100 0 /* nelma_beep */ ,
1101 0 /* nelma_progress */
1104 #include "dolists.h"
1106 void
1107 hid_nelma_init()
1109 apply_default_hid(&nelma_hid, 0);
1110 hid_register_hid(&nelma_hid);
1112 #include "nelma_lists.h"