Move some fields from the HID* structure to HID_DRAW* and HID_DRAW_CLASS*
[geda-pcb/pcjc2.git] / src / hid / nelma / nelma.c
blobdff74b0890673d5a1a86f21a8aec8a8246e0a7f0
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 "error.h" /* Message() */
68 #include "data.h"
69 #include "misc.h"
70 #include "rats.h"
72 #include "hid.h"
73 #include "hid_draw.h"
74 #include "../hidint.h"
75 #include "hid/common/hidnogui.h"
76 #include "hid/common/draw_helpers.h"
78 #include <gd.h>
80 #include "hid/common/hidinit.h"
82 #ifdef HAVE_LIBDMALLOC
83 #include <dmalloc.h>
84 #endif
86 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented PNG function %s.\n", __FUNCTION__); abort()
88 /* Needed for PNG export */
90 struct color_struct {
91 /* the descriptor used by the gd library */
92 int c;
94 /* so I can figure out what rgb value c refers to */
95 unsigned int r, g, b;
98 typedef struct nelma_gc_struct {
99 struct hid_gc_struct hid_gc; /* Parent */
101 EndCapStyle cap;
102 Coord width;
103 unsigned char r, g, b;
104 int erase;
105 struct color_struct *color;
106 gdImagePtr brush;
107 } *nelmaGC;
109 static HID nelma_hid;
110 static HID_DRAW nelma_graphics;
111 static HID_DRAW_CLASS nelma_graphics_class;
113 static struct color_struct *black = NULL, *white = NULL;
114 static Coord linewidth = -1;
115 static gdImagePtr lastbrush = (gdImagePtr)((void *) -1);
117 /* gd image and file for PNG export */
118 static gdImagePtr nelma_im = NULL;
119 static FILE *nelma_f = NULL;
121 static int is_mask;
122 static int is_drill;
125 * Which groups of layers to export into PNG layer masks. 1 means export, 0
126 * means do not export.
128 static int nelma_export_group[MAX_GROUP];
130 /* Group that is currently exported. */
131 static int nelma_cur_group;
133 /* Filename prefix that will be used when saving files. */
134 static const char *nelma_basename = NULL;
136 /* Horizontal DPI (grid points per inch) */
137 static int nelma_dpi = -1;
139 /* Height of the copper layers in micrometers. */
142 * The height of the copper layer is currently taken as the vertical grid
143 * step, since this is the smallest vertical feature in the layout.
145 static int nelma_copperh = -1;
146 /* Height of the substrate layers in micrometers. */
147 static int nelma_substrateh = -1;
148 /* Relative permittivity of the substrate. */
149 static double nelma_substratee = -1;
151 /* Permittivity of empty space (As/Vm) */
152 static const double nelma_air_epsilon = 8.85e-12;
154 HID_Attribute nelma_attribute_list[] = {
155 /* other HIDs expect this to be first. */
157 /* %start-doc options "nelma Options"
158 @ftable @code
159 @item -- basename <string>
160 File name prefix.
161 @end ftable
162 %end-doc
164 {"basename", "File name prefix",
165 HID_String, 0, 0, {0, 0, 0}, 0, 0},
166 #define HA_basename 0
168 /* %start-doc options "nelma Options"
169 @ftable @code
170 @item --dpi <num>
171 Horizontal scale factor (grid points/inch).
172 @end ftable
173 %end-doc
175 {"dpi", "Horizontal scale factor (grid points/inch)",
176 HID_Integer, 0, 1000, {100, 0, 0}, 0, 0},
177 #define HA_dpi 1
179 /* %start-doc options "nelma Options"
180 @ftable @code
181 @item --copper-height <num>
182 Copper layer height (um).
183 @end ftable
184 %end-doc
186 {"copper-height", "Copper layer height (um)",
187 HID_Integer, 0, 200, {100, 0, 0}, 0, 0},
188 #define HA_copperh 2
190 /* %start-doc options "nelma Options"
191 @ftable @code
192 @item --substrate-height <num>
193 Substrate layer height (um).
194 @end ftable
195 %end-doc
197 {"substrate-height", "Substrate layer height (um)",
198 HID_Integer, 0, 10000, {2000, 0, 0}, 0, 0},
199 #define HA_substrateh 3
201 /* %start-doc options "nelma Options"
202 @ftable @code
203 @item --substrate-epsilon <num>
204 Substrate relative epsilon.
205 @end ftable
206 %end-doc
208 {"substrate-epsilon", "Substrate relative epsilon",
209 HID_Real, 0, 100, {0, 0, 4.0}, 0, 0},
210 #define HA_substratee 4
213 #define NUM_OPTIONS (sizeof(nelma_attribute_list)/sizeof(nelma_attribute_list[0]))
215 REGISTER_ATTRIBUTES(nelma_attribute_list)
216 static HID_Attr_Val nelma_values[NUM_OPTIONS];
218 /* *** Utility funcions **************************************************** */
220 /* convert from default PCB units to nelma units */
221 static int pcb_to_nelma (Coord pcb)
223 return COORD_TO_INCH(pcb) * nelma_dpi;
226 static char *
227 nelma_get_png_name(const char *basename, const char *suffix)
229 char *buf;
230 int len;
232 len = strlen(basename) + strlen(suffix) + 6;
233 buf = (char *)malloc(sizeof(*buf) * len);
235 sprintf(buf, "%s.%s.png", basename, suffix);
237 return buf;
240 /* Retrieves coordinates (in default PCB units) of a pin or pad. */
241 /* Copied from netlist.c */
242 static int
243 pin_name_to_xy (LibraryEntryType * pin, Coord *x, Coord *y)
245 ConnectionType conn;
246 if (!SeekPad(pin, &conn, false))
247 return 1;
248 switch (conn.type) {
249 case PIN_TYPE:
250 *x = ((PinType *) (conn.ptr2))->X;
251 *y = ((PinType *) (conn.ptr2))->Y;
252 return 0;
253 case PAD_TYPE:
254 *x = ((PadType *) (conn.ptr2))->Point1.X;
255 *y = ((PadType *) (conn.ptr2))->Point1.Y;
256 return 0;
258 return 1;
261 /* *** Exporting netlist data and geometry to the nelma config file ******** */
263 static void
264 nelma_write_space(FILE * out)
266 double xh, zh;
268 int z;
269 int i, idx;
270 const char *ext;
272 xh = 2.54e-2 / ((double) nelma_dpi);
273 zh = nelma_copperh * 1e-6;
275 fprintf(out, "\n/* **** Space **** */\n\n");
277 fprintf(out, "space pcb {\n");
278 fprintf(out, "\tstep = { %e, %e, %e }\n", xh, xh, zh);
279 fprintf(out, "\tlayers = {\n");
281 fprintf(out, "\t\t\"air-top\",\n");
282 fprintf(out, "\t\t\"air-bottom\"");
284 z = 10;
285 for (i = 0; i < MAX_GROUP; i++)
286 if (nelma_export_group[i]) {
287 idx = (i >= 0 && i < max_group) ?
288 PCB->LayerGroups.Entries[i][0] : i;
289 ext = layer_type_to_file_name(idx, FNS_fixed);
291 if (z != 10) {
292 fprintf(out, ",\n");
293 fprintf(out, "\t\t\"substrate-%d\"", z);
294 z++;
296 fprintf(out, ",\n");
297 fprintf(out, "\t\t\"%s\"", ext);
298 z++;
300 fprintf(out, "\n\t}\n");
301 fprintf(out, "}\n");
305 static void
306 nelma_write_material(FILE * out, char *name, char *type, double e)
308 fprintf(out, "material %s {\n", name);
309 fprintf(out, "\ttype = \"%s\"\n", type);
310 fprintf(out, "\tpermittivity = %e\n", e);
311 fprintf(out, "\tconductivity = 0.0\n");
312 fprintf(out, "\tpermeability = 0.0\n");
313 fprintf(out, "}\n");
316 static void
317 nelma_write_materials(FILE * out)
319 fprintf(out, "\n/* **** Materials **** */\n\n");
321 nelma_write_material(out, "copper", "metal", nelma_air_epsilon);
322 nelma_write_material(out, "air", "dielectric", nelma_air_epsilon);
323 nelma_write_material(out, "composite", "dielectric",
324 nelma_air_epsilon * nelma_substratee);
327 static void
328 nelma_write_nets(FILE * out)
330 LibraryType netlist;
331 LibraryMenuType *net;
332 LibraryEntryType *pin;
334 int n, m, i, idx;
336 const char *ext;
338 netlist = PCB->NetlistLib;
340 fprintf(out, "\n/* **** Nets **** */\n\n");
342 for (n = 0; n < netlist.MenuN; n++) {
343 net = &netlist.Menu[n];
345 /* Weird, but correct */
346 fprintf(out, "net %s {\n", &net->Name[2]);
348 fprintf(out, "\tobjects = {\n");
350 for (m = 0; m < net->EntryN; m++) {
351 pin = &net->Entry[m];
353 /* pin_name_to_xy(pin, &x, &y); */
355 for (i = 0; i < MAX_GROUP; i++)
356 if (nelma_export_group[i]) {
357 idx = (i >= 0 && i < max_group) ?
358 PCB->LayerGroups.Entries[i][0] : i;
359 ext = layer_type_to_file_name(idx, FNS_fixed);
361 if (m != 0 || i != 0)
362 fprintf(out, ",\n");
363 fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry,
364 ext);
368 fprintf(out, "\n");
369 fprintf(out, "\t}\n");
370 fprintf(out, "}\n");
374 static void
375 nelma_write_layer(FILE * out, int z, int h,
376 const char *name, int full,
377 char *mat)
379 LibraryType netlist;
380 LibraryMenuType *net;
381 LibraryEntryType *pin;
383 int n, m;
385 fprintf(out, "layer %s {\n", name);
386 fprintf(out, "\theight = %d\n", h);
387 fprintf(out, "\tz-order = %d\n", z);
388 fprintf(out, "\tmaterial = \"%s\"\n", mat);
390 if (full) {
391 fprintf(out, "\tobjects = {\n");
392 netlist = PCB->NetlistLib;
394 for (n = 0; n < netlist.MenuN; n++) {
395 net = &netlist.Menu[n];
397 for (m = 0; m < net->EntryN; m++) {
398 pin = &net->Entry[m];
400 if (m != 0 || n != 0)
401 fprintf(out, ",\n");
402 fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry,
403 name);
407 fprintf(out, "\n\t}\n");
409 fprintf(out, "}\n");
412 static void
413 nelma_write_layers(FILE * out)
415 int i, idx;
416 int z;
418 const char *ext;
419 char buf[100];
421 int subh;
423 subh = nelma_substrateh / nelma_copperh;
425 fprintf(out, "\n/* **** Layers **** */\n\n");
427 /* Air layers on top and bottom of the stack */
428 /* Their height is double substrate height. */
429 nelma_write_layer(out, 1, 2 * subh, "air-top", 0, "air");
430 nelma_write_layer(out, 1000, 2 * subh, "air-bottom", 0, "air");
432 z = 10;
433 for (i = 0; i < MAX_GROUP; i++)
434 if (nelma_export_group[i]) {
435 idx = (i >= 0 && i < max_group) ?
436 PCB->LayerGroups.Entries[i][0] : i;
437 ext = layer_type_to_file_name(idx, FNS_fixed);
439 if (z != 10) {
440 sprintf(buf, "substrate-%d", z);
441 nelma_write_layer(out,
443 subh,
444 buf,
446 "composite");
447 z++;
450 * FIXME: for layers that are not on top or bottom,
451 * the material should be "composite"
453 nelma_write_layer(out, z, 1, ext, 1, "air");
455 z++;
459 static void
460 nelma_write_object(FILE * out, LibraryEntryType *pin)
462 int i, idx;
463 Coord px = 0, py = 0;
464 int x, y;
466 char *f;
467 const char *ext;
469 pin_name_to_xy (pin, &px, &py);
471 x = pcb_to_nelma (px);
472 y = pcb_to_nelma (py);
474 for (i = 0; i < MAX_GROUP; i++)
475 if (nelma_export_group[i]) {
476 idx = (i >= 0 && i < max_group) ?
477 PCB->LayerGroups.Entries[i][0] : i;
478 ext = layer_type_to_file_name(idx, FNS_fixed);
480 fprintf(out, "object %s-%s {\n", pin->ListEntry, ext);
481 fprintf(out, "\tposition = { 0, 0 }\n");
482 fprintf(out, "\tmaterial = \"copper\"\n");
483 fprintf(out, "\ttype = \"image\"\n");
484 fprintf(out, "\trole = \"net\"\n");
486 f = nelma_get_png_name(nelma_basename, ext);
488 fprintf(out, "\tfile = \"%s\"\n", f);
490 free(f);
492 fprintf(out, "\tfile-pos = { %d, %d }\n", x, y);
493 fprintf(out, "}\n");
497 static void
498 nelma_write_objects(FILE * out)
500 LibraryType netlist;
501 LibraryMenuType *net;
502 LibraryEntryType *pin;
504 int n, m;
506 netlist = PCB->NetlistLib;
508 fprintf(out, "\n/* **** Objects **** */\n\n");
510 for (n = 0; n < netlist.MenuN; n++) {
511 net = &netlist.Menu[n];
513 for (m = 0; m < net->EntryN; m++) {
514 pin = &net->Entry[m];
516 nelma_write_object(out, pin);
521 /* *** Main export callback ************************************************ */
523 static void
524 nelma_parse_arguments(int *argc, char ***argv)
526 hid_register_attributes(nelma_attribute_list,
527 sizeof(nelma_attribute_list) /
528 sizeof(nelma_attribute_list[0]));
529 hid_parse_command_line(argc, argv);
532 static HID_Attribute *
533 nelma_get_export_options(int *n)
535 static char *last_made_filename = 0;
537 if (PCB) {
538 derive_default_filename(PCB->Filename,
539 &nelma_attribute_list[HA_basename],
540 ".nelma",
541 &last_made_filename);
543 if (n) {
544 *n = NUM_OPTIONS;
546 return nelma_attribute_list;
549 /* Populates nelma_export_group array */
550 void
551 nelma_choose_groups()
553 int n, m;
554 LayerType *layer;
556 /* Set entire array to 0 (don't export any layer groups by default */
557 memset(nelma_export_group, 0, sizeof(nelma_export_group));
559 for (n = 0; n < max_copper_layer; n++) {
560 layer = &PCB->Data->Layer[n];
562 if (layer->LineN || layer->TextN || layer->ArcN ||
563 layer->PolygonN) {
564 /* layer isn't empty */
567 * is this check necessary? It seems that special
568 * layers have negative indexes?
571 if (SL_TYPE(n) == 0) {
572 /* layer is a copper layer */
573 m = GetLayerGroupNumberByNumber(n);
575 /* the export layer */
576 nelma_export_group[m] = 1;
582 static void
583 nelma_alloc_colors()
586 * Allocate white and black -- the first color allocated becomes the
587 * background color
590 white = (struct color_struct *) malloc(sizeof(*white));
591 white->r = white->g = white->b = 255;
592 white->c = gdImageColorAllocate(nelma_im, white->r, white->g, white->b);
594 black = (struct color_struct *) malloc(sizeof(*black));
595 black->r = black->g = black->b = 0;
596 black->c = gdImageColorAllocate(nelma_im, black->r, black->g, black->b);
599 static void
600 nelma_start_png(const char *basename, const char *suffix)
602 int h, w;
603 char *buf;
605 buf = nelma_get_png_name(basename, suffix);
607 h = pcb_to_nelma(PCB->MaxHeight);
608 w = pcb_to_nelma(PCB->MaxWidth);
610 /* nelma_im = gdImageCreate (w, h); */
612 /* Nelma only works with true color images */
613 nelma_im = gdImageCreate(w, h);
614 nelma_f = fopen(buf, "wb");
616 nelma_alloc_colors();
618 free(buf);
621 static void
622 nelma_finish_png()
624 #ifdef HAVE_GDIMAGEPNG
625 gdImagePng(nelma_im, nelma_f);
626 #else
627 Message("NELMA: PNG not supported by gd. Can't write layer mask.\n");
628 #endif
629 gdImageDestroy(nelma_im);
630 fclose(nelma_f);
632 free(white);
633 free(black);
635 nelma_im = NULL;
636 nelma_f = NULL;
639 void
640 nelma_start_png_export()
642 BoxType region;
644 region.X1 = 0;
645 region.Y1 = 0;
646 region.X2 = PCB->MaxWidth;
647 region.Y2 = PCB->MaxHeight;
649 linewidth = -1;
650 lastbrush = (gdImagePtr)((void *) -1);
652 hid_expose_callback(&nelma_hid, &region, 0);
655 static void
656 nelma_do_export(HID_Attr_Val * options)
658 int save_ons[MAX_LAYER + 2];
659 int i, idx;
660 FILE *nelma_config;
661 char *buf;
662 int len;
664 time_t t;
666 if (!options) {
667 nelma_get_export_options(0);
668 for (i = 0; i < NUM_OPTIONS; i++) {
669 nelma_values[i] = nelma_attribute_list[i].default_val;
671 options = nelma_values;
673 nelma_basename = options[HA_basename].str_value;
674 if (!nelma_basename) {
675 nelma_basename = "pcb-out";
677 nelma_dpi = options[HA_dpi].int_value;
678 if (nelma_dpi < 0) {
679 fprintf(stderr, "ERROR: dpi may not be < 0\n");
680 return;
682 nelma_copperh = options[HA_copperh].int_value;
683 nelma_substrateh = options[HA_substrateh].int_value;
684 nelma_substratee = options[HA_substratee].real_value;
686 nelma_choose_groups();
688 for (i = 0; i < MAX_GROUP; i++) {
689 if (nelma_export_group[i]) {
691 nelma_cur_group = i;
693 /* magic */
694 idx = (i >= 0 && i < max_group) ?
695 PCB->LayerGroups.Entries[i][0] : i;
697 nelma_start_png(nelma_basename,
698 layer_type_to_file_name(idx, FNS_fixed));
700 hid_save_and_show_layer_ons(save_ons);
701 nelma_start_png_export();
702 hid_restore_layer_ons(save_ons);
704 nelma_finish_png();
708 len = strlen(nelma_basename) + 4;
709 buf = (char *)malloc(sizeof(*buf) * len);
711 sprintf(buf, "%s.em", nelma_basename);
712 nelma_config = fopen(buf, "w");
714 free(buf);
716 fprintf(nelma_config, "/* Made with PCB Nelma export HID */");
717 t = time(NULL);
718 fprintf(nelma_config, "/* %s */", ctime(&t));
720 nelma_write_nets(nelma_config);
721 nelma_write_objects(nelma_config);
722 nelma_write_layers(nelma_config);
723 nelma_write_materials(nelma_config);
724 nelma_write_space(nelma_config);
726 fclose(nelma_config);
729 /* *** PNG export (slightly modified code from PNG export HID) ************* */
731 static int
732 nelma_set_layer(const char *name, int group, int empty)
734 int idx = (group >= 0 && group < max_group) ?
735 PCB->LayerGroups.Entries[group][0] : group;
737 if (name == 0) {
738 name = PCB->Data->Layer[idx].Name;
740 if (strcmp(name, "invisible") == 0) {
741 return 0;
743 is_drill = (SL_TYPE(idx) == SL_PDRILL || SL_TYPE(idx) == SL_UDRILL);
744 is_mask = (SL_TYPE(idx) == SL_MASK);
746 if (is_mask) {
747 /* Don't print masks */
748 return 0;
750 if (is_drill) {
752 * Print 'holes', so that we can fill gaps in the copper
753 * layer
755 return 1;
757 if (group == nelma_cur_group) {
758 return 1;
760 return 0;
763 static hidGC
764 nelma_make_gc(void)
766 hidGC gc = (hidGC) calloc (1, sizeof(struct hid_gc_struct));
767 nelmaGC nelma_gc = (nelmaGC)gc;
769 gc->hid = &nelma_hid;
770 gc->hid_draw = &nelma_graphics;
772 nelma_gc->cap = Trace_Cap;
773 nelma_gc->width = 1;
774 nelma_gc->color = (struct color_struct *) malloc(sizeof(*nelma_gc->color));
775 nelma_gc->color->r = nelma_gc->color->g = nelma_gc->color->b = 0;
776 nelma_gc->color->c = 0;
778 return gc;
781 static void
782 nelma_destroy_gc(hidGC gc)
784 free(gc);
787 static void
788 nelma_use_mask(enum mask_mode mode)
790 /* does nothing */
793 static void
794 nelma_set_color(hidGC gc, const char *name)
796 nelmaGC nelma_gc = (nelmaGC)gc;
798 if (nelma_im == NULL) {
799 return;
801 if (name == NULL) {
802 name = "#ff0000";
804 if (!strcmp(name, "drill")) {
805 nelma_gc->color = black;
806 nelma_gc->erase = 0;
807 return;
809 if (!strcmp(name, "erase")) {
810 /* FIXME -- should be background, not white */
811 nelma_gc->color = white;
812 nelma_gc->erase = 1;
813 return;
815 nelma_gc->color = black;
816 nelma_gc->erase = 0;
817 return;
820 static void
821 nelma_set_line_cap(hidGC gc, EndCapStyle style)
823 nelmaGC nelma_gc = (nelmaGC)gc;
825 nelma_gc->cap = style;
828 static void
829 nelma_set_line_width(hidGC gc, Coord width)
831 nelmaGC nelma_gc = (nelmaGC)gc;
833 nelma_gc->width = width;
836 static void
837 nelma_set_draw_xor(hidGC gc, int xor_)
842 static void
843 nelma_set_draw_faded(hidGC gc, int faded)
847 static void
848 use_gc(hidGC gc)
850 nelmaGC nelma_gc = (nelmaGC)gc;
851 int need_brush = 0;
853 if (gc->hid != &nelma_hid) {
854 fprintf(stderr, "Fatal: GC from another HID passed to nelma HID\n");
855 abort();
857 if (linewidth != nelma_gc->width) {
858 /* Make sure the scaling doesn't erase lines completely */
860 if (SCALE (nelma_gc->width) == 0 && nelma_gc->width > 0)
861 gdImageSetThickness (im, 1);
862 else
864 gdImageSetThickness(nelma_im, pcb_to_nelma(nelma_gc->width));
865 linewidth = nelma_gc->width;
866 need_brush = 1;
868 if (lastbrush != nelma_gc->brush || need_brush) {
869 static void *bcache = 0;
870 hidval bval;
871 char name[256];
872 char type;
873 int r;
875 switch (nelma_gc->cap) {
876 case Round_Cap:
877 case Trace_Cap:
878 type = 'C';
879 r = pcb_to_nelma(nelma_gc->width / 2);
880 break;
881 default:
882 case Square_Cap:
883 r = pcb_to_nelma(nelma_gc->width);
884 type = 'S';
885 break;
887 sprintf(name, "#%.2x%.2x%.2x_%c_%d", nelma_gc->color->r, nelma_gc->color->g,
888 nelma_gc->color->b, type, r);
890 if (hid_cache_color(0, name, &bval, &bcache)) {
891 nelma_gc->brush = (gdImagePtr)bval.ptr;
892 } else {
893 int bg, fg;
894 if (type == 'C')
895 nelma_gc->brush = gdImageCreate(2 * r + 1, 2 * r + 1);
896 else
897 nelma_gc->brush = gdImageCreate(r + 1, r + 1);
898 bg = gdImageColorAllocate(nelma_gc->brush, 255, 255, 255);
899 fg =
900 gdImageColorAllocate(nelma_gc->brush, nelma_gc->color->r, nelma_gc->color->g,
901 nelma_gc->color->b);
902 gdImageColorTransparent(nelma_gc->brush, bg);
905 * if we shrunk to a radius/box width of zero, then just use
906 * a single pixel to draw with.
908 if (r == 0)
909 gdImageFilledRectangle(nelma_gc->brush, 0, 0, 0, 0, fg);
910 else {
911 if (type == 'C')
912 gdImageFilledEllipse(nelma_gc->brush, r, r, 2 * r, 2 * r, fg);
913 else
914 gdImageFilledRectangle(nelma_gc->brush, 0, 0, r, r, fg);
916 bval.ptr = nelma_gc->brush;
917 hid_cache_color(1, name, &bval, &bcache);
920 gdImageSetBrush(nelma_im, nelma_gc->brush);
921 lastbrush = nelma_gc->brush;
926 static void
927 nelma_draw_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
929 nelmaGC nelma_gc = (nelmaGC)gc;
931 use_gc(gc);
932 gdImageRectangle(nelma_im,
933 pcb_to_nelma(x1), pcb_to_nelma(y1),
934 pcb_to_nelma(x2), pcb_to_nelma(y2), nelma_gc->color->c);
937 static void
938 nelma_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
940 nelmaGC nelma_gc = (nelmaGC)gc;
942 use_gc(gc);
943 gdImageSetThickness(nelma_im, 0);
944 linewidth = 0;
945 gdImageFilledRectangle(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1),
946 pcb_to_nelma(x2), pcb_to_nelma(y2), nelma_gc->color->c);
949 static void
950 nelma_draw_line(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
952 nelmaGC nelma_gc = (nelmaGC)gc;
954 if (x1 == x2 && y1 == y2) {
955 Coord w = nelma_gc->width / 2;
956 nelma_fill_rect(gc, x1 - w, y1 - w, x1 + w, y1 + w);
957 return;
959 use_gc(gc);
961 gdImageSetThickness(nelma_im, 0);
962 linewidth = 0;
963 gdImageLine(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1),
964 pcb_to_nelma(x2), pcb_to_nelma(y2), gdBrushed);
967 static void
968 nelma_draw_arc(hidGC gc, Coord cx, Coord cy, Coord width, Coord height,
969 Angle start_angle, Angle delta_angle)
971 Angle sa, ea;
974 * in gdImageArc, 0 degrees is to the right and +90 degrees is down
975 * in pcb, 0 degrees is to the left and +90 degrees is down
977 start_angle = 180 - start_angle;
978 delta_angle = -delta_angle;
979 if (delta_angle > 0) {
980 sa = start_angle;
981 ea = start_angle + delta_angle;
982 } else {
983 sa = start_angle + delta_angle;
984 ea = start_angle;
988 * make sure we start between 0 and 360 otherwise gd does strange
989 * things
991 sa = NormalizeAngle (sa);
992 ea = NormalizeAngle (ea);
994 #if 0
995 printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n",
996 cx, cy, width, height, start_angle, delta_angle, sa, ea);
997 printf("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n",
998 im, SCALE_X(cx), SCALE_Y(cy),
999 SCALE(width), SCALE(height), sa, ea, nelma_gc->color->c);
1000 #endif
1001 use_gc(gc);
1002 gdImageSetThickness(nelma_im, 0);
1003 linewidth = 0;
1004 gdImageArc(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy),
1005 pcb_to_nelma(2 * width), pcb_to_nelma(2 * height), sa, ea, gdBrushed);
1008 static void
1009 nelma_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius)
1011 nelmaGC nelma_gc = (nelmaGC)gc;
1013 use_gc(gc);
1015 gdImageSetThickness(nelma_im, 0);
1016 linewidth = 0;
1017 gdImageFilledEllipse(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy),
1018 pcb_to_nelma(2 * radius), pcb_to_nelma(2 * radius), nelma_gc->color->c);
1022 static void
1023 nelma_fill_polygon(hidGC gc, int n_coords, Coord *x, Coord *y)
1025 nelmaGC nelma_gc = (nelmaGC)gc;
1026 int i;
1027 gdPoint *points;
1029 points = (gdPoint *) malloc(n_coords * sizeof(gdPoint));
1030 if (points == NULL) {
1031 fprintf(stderr, "ERROR: nelma_fill_polygon(): malloc failed\n");
1032 exit(1);
1034 use_gc(gc);
1035 for (i = 0; i < n_coords; i++) {
1036 points[i].x = pcb_to_nelma(x[i]);
1037 points[i].y = pcb_to_nelma(y[i]);
1039 gdImageSetThickness(nelma_im, 0);
1040 linewidth = 0;
1041 gdImageFilledPolygon(nelma_im, points, n_coords, nelma_gc->color->c);
1042 free(points);
1045 static void
1046 nelma_calibrate(double xval, double yval)
1048 CRASH;
1051 static void
1052 nelma_set_crosshair(int x, int y, int a)
1056 /* *** Miscellaneous ******************************************************* */
1058 #include "dolists.h"
1060 void
1061 hid_nelma_init()
1063 memset (&nelma_hid, 0, sizeof (HID));
1064 memset (&nelma_graphics, 0, sizeof (HID_DRAW));
1065 memset (&nelma_graphics_class, 0, sizeof (HID_DRAW_CLASS));
1067 common_nogui_init (&nelma_hid);
1069 nelma_hid.struct_size = sizeof (HID);
1070 nelma_hid.name = "nelma";
1071 nelma_hid.description = "Numerical analysis package export";
1072 nelma_hid.exporter = 1;
1074 nelma_hid.get_export_options = nelma_get_export_options;
1075 nelma_hid.do_export = nelma_do_export;
1076 nelma_hid.parse_arguments = nelma_parse_arguments;
1077 nelma_hid.calibrate = nelma_calibrate;
1078 nelma_hid.set_crosshair = nelma_set_crosshair;
1080 nelma_hid.graphics = &nelma_graphics;
1082 common_draw_helpers_class_init (&nelma_graphics_class);
1084 nelma_graphics_class.set_layer = nelma_set_layer;
1085 nelma_graphics_class.make_gc = nelma_make_gc;
1086 nelma_graphics_class.destroy_gc = nelma_destroy_gc;
1087 nelma_graphics_class.use_mask = nelma_use_mask;
1088 nelma_graphics_class.set_color = nelma_set_color;
1089 nelma_graphics_class.set_line_cap = nelma_set_line_cap;
1090 nelma_graphics_class.set_line_width = nelma_set_line_width;
1091 nelma_graphics_class.set_draw_xor = nelma_set_draw_xor;
1092 nelma_graphics_class.set_draw_faded = nelma_set_draw_faded;
1093 nelma_graphics_class.draw_line = nelma_draw_line;
1094 nelma_graphics_class.draw_arc = nelma_draw_arc;
1095 nelma_graphics_class.draw_rect = nelma_draw_rect;
1096 nelma_graphics_class.fill_circle = nelma_fill_circle;
1097 nelma_graphics_class.fill_polygon = nelma_fill_polygon;
1098 nelma_graphics_class.fill_rect = nelma_fill_rect;
1100 nelma_graphics.klass = &nelma_graphics_class;
1101 nelma_graphics.poly_before = true;
1102 common_draw_helpers_init (&nelma_graphics);
1104 hid_register_hid (&nelma_hid);
1106 #include "nelma_lists.h"