Convert mask type to enum
[geda-pcb/pcjc2.git] / src / hid / nelma / nelma.c
blobfe71234c9b2dbbac94ab18e5cf2ee5f8dd5eaaf9
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 "../hidint.h"
74 #include "hid/common/hidnogui.h"
75 #include "hid/common/draw_helpers.h"
77 #include <gd.h>
79 #include "hid/common/hidinit.h"
81 #ifdef HAVE_LIBDMALLOC
82 #include <dmalloc.h>
83 #endif
85 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented PNG function %s.\n", __FUNCTION__); abort()
87 /* Needed for PNG export */
89 struct color_struct {
90 /* the descriptor used by the gd library */
91 int c;
93 /* so I can figure out what rgb value c refers to */
94 unsigned int r, g, b;
97 struct hid_gc_struct {
98 HID *me_pointer;
99 EndCapStyle cap;
100 Coord width;
101 unsigned char r, g, b;
102 int erase;
103 struct color_struct *color;
104 gdImagePtr brush;
107 static HID nelma_hid;
109 static struct color_struct *black = NULL, *white = NULL;
110 static Coord linewidth = -1;
111 static gdImagePtr lastbrush = (gdImagePtr)((void *) -1);
113 /* gd image and file for PNG export */
114 static gdImagePtr nelma_im = NULL;
115 static FILE *nelma_f = NULL;
117 static int is_mask;
118 static int is_drill;
121 * Which groups of layers to export into PNG layer masks. 1 means export, 0
122 * means do not export.
124 static int nelma_export_group[MAX_LAYER];
126 /* Group that is currently exported. */
127 static int nelma_cur_group;
129 /* Filename prefix that will be used when saving files. */
130 static const char *nelma_basename = NULL;
132 /* Horizontal DPI (grid points per inch) */
133 static int nelma_dpi = -1;
135 /* Height of the copper layers in micrometers. */
138 * The height of the copper layer is currently taken as the vertical grid
139 * step, since this is the smallest vertical feature in the layout.
141 static int nelma_copperh = -1;
142 /* Height of the substrate layers in micrometers. */
143 static int nelma_substrateh = -1;
144 /* Relative permittivity of the substrate. */
145 static double nelma_substratee = -1;
147 /* Permittivity of empty space (As/Vm) */
148 static const double nelma_air_epsilon = 8.85e-12;
150 HID_Attribute nelma_attribute_list[] = {
151 /* other HIDs expect this to be first. */
153 /* %start-doc options "nelma Options"
154 @ftable @code
155 @item -- basename <string>
156 File name prefix.
157 @end ftable
158 %end-doc
160 {"basename", "File name prefix",
161 HID_String, 0, 0, {0, 0, 0}, 0, 0},
162 #define HA_basename 0
164 /* %start-doc options "nelma Options"
165 @ftable @code
166 @item --dpi <num>
167 Horizontal scale factor (grid points/inch).
168 @end ftable
169 %end-doc
171 {"dpi", "Horizontal scale factor (grid points/inch)",
172 HID_Integer, 0, 1000, {100, 0, 0}, 0, 0},
173 #define HA_dpi 1
175 /* %start-doc options "nelma Options"
176 @ftable @code
177 @item --copper-height <num>
178 Copper layer height (um).
179 @end ftable
180 %end-doc
182 {"copper-height", "Copper layer height (um)",
183 HID_Integer, 0, 200, {100, 0, 0}, 0, 0},
184 #define HA_copperh 2
186 /* %start-doc options "nelma Options"
187 @ftable @code
188 @item --substrate-height <num>
189 Substrate layer height (um).
190 @end ftable
191 %end-doc
193 {"substrate-height", "Substrate layer height (um)",
194 HID_Integer, 0, 10000, {2000, 0, 0}, 0, 0},
195 #define HA_substrateh 3
197 /* %start-doc options "nelma Options"
198 @ftable @code
199 @item --substrate-epsilon <num>
200 Substrate relative epsilon.
201 @end ftable
202 %end-doc
204 {"substrate-epsilon", "Substrate relative epsilon",
205 HID_Real, 0, 100, {0, 0, 4.0}, 0, 0},
206 #define HA_substratee 4
209 #define NUM_OPTIONS (sizeof(nelma_attribute_list)/sizeof(nelma_attribute_list[0]))
211 REGISTER_ATTRIBUTES(nelma_attribute_list)
212 static HID_Attr_Val nelma_values[NUM_OPTIONS];
214 /* *** Utility funcions **************************************************** */
216 /* convert from default PCB units to nelma units */
217 static int pcb_to_nelma (Coord pcb)
219 return COORD_TO_INCH(pcb) * nelma_dpi;
222 static char *
223 nelma_get_png_name(const char *basename, const char *suffix)
225 char *buf;
226 int len;
228 len = strlen(basename) + strlen(suffix) + 6;
229 buf = (char *)malloc(sizeof(*buf) * len);
231 sprintf(buf, "%s.%s.png", basename, suffix);
233 return buf;
236 /* Retrieves coordinates (in default PCB units) of a pin or pad. */
237 /* Copied from netlist.c */
238 static int
239 pin_name_to_xy (LibraryEntryType * pin, Coord *x, Coord *y)
241 ConnectionType conn;
242 if (!SeekPad(pin, &conn, false))
243 return 1;
244 switch (conn.type) {
245 case PIN_TYPE:
246 *x = ((PinType *) (conn.ptr2))->X;
247 *y = ((PinType *) (conn.ptr2))->Y;
248 return 0;
249 case PAD_TYPE:
250 *x = ((PadType *) (conn.ptr2))->Point1.X;
251 *y = ((PadType *) (conn.ptr2))->Point1.Y;
252 return 0;
254 return 1;
257 /* *** Exporting netlist data and geometry to the nelma config file ******** */
259 static void
260 nelma_write_space(FILE * out)
262 double xh, zh;
264 int z;
265 int i, idx;
266 const char *ext;
268 xh = 2.54e-2 / ((double) nelma_dpi);
269 zh = nelma_copperh * 1e-6;
271 fprintf(out, "\n/* **** Space **** */\n\n");
273 fprintf(out, "space pcb {\n");
274 fprintf(out, "\tstep = { %e, %e, %e }\n", xh, xh, zh);
275 fprintf(out, "\tlayers = {\n");
277 fprintf(out, "\t\t\"air-top\",\n");
278 fprintf(out, "\t\t\"air-bottom\"");
280 z = 10;
281 for (i = 0; i < MAX_LAYER; i++)
282 if (nelma_export_group[i]) {
283 idx = (i >= 0 && i < max_group) ?
284 PCB->LayerGroups.Entries[i][0] : i;
285 ext = layer_type_to_file_name(idx, FNS_fixed);
287 if (z != 10) {
288 fprintf(out, ",\n");
289 fprintf(out, "\t\t\"substrate-%d\"", z);
290 z++;
292 fprintf(out, ",\n");
293 fprintf(out, "\t\t\"%s\"", ext);
294 z++;
296 fprintf(out, "\n\t}\n");
297 fprintf(out, "}\n");
301 static void
302 nelma_write_material(FILE * out, char *name, char *type, double e)
304 fprintf(out, "material %s {\n", name);
305 fprintf(out, "\ttype = \"%s\"\n", type);
306 fprintf(out, "\tpermittivity = %e\n", e);
307 fprintf(out, "\tconductivity = 0.0\n");
308 fprintf(out, "\tpermeability = 0.0\n");
309 fprintf(out, "}\n");
312 static void
313 nelma_write_materials(FILE * out)
315 fprintf(out, "\n/* **** Materials **** */\n\n");
317 nelma_write_material(out, "copper", "metal", nelma_air_epsilon);
318 nelma_write_material(out, "air", "dielectric", nelma_air_epsilon);
319 nelma_write_material(out, "composite", "dielectric",
320 nelma_air_epsilon * nelma_substratee);
323 static void
324 nelma_write_nets(FILE * out)
326 LibraryType netlist;
327 LibraryMenuType *net;
328 LibraryEntryType *pin;
330 int n, m, i, idx;
332 const char *ext;
334 netlist = PCB->NetlistLib;
336 fprintf(out, "\n/* **** Nets **** */\n\n");
338 for (n = 0; n < netlist.MenuN; n++) {
339 net = &netlist.Menu[n];
341 /* Weird, but correct */
342 fprintf(out, "net %s {\n", &net->Name[2]);
344 fprintf(out, "\tobjects = {\n");
346 for (m = 0; m < net->EntryN; m++) {
347 pin = &net->Entry[m];
349 /* pin_name_to_xy(pin, &x, &y); */
351 for (i = 0; i < MAX_LAYER; i++)
352 if (nelma_export_group[i]) {
353 idx = (i >= 0 && i < max_group) ?
354 PCB->LayerGroups.Entries[i][0] : i;
355 ext = layer_type_to_file_name(idx, FNS_fixed);
357 if (m != 0 || i != 0)
358 fprintf(out, ",\n");
359 fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry,
360 ext);
364 fprintf(out, "\n");
365 fprintf(out, "\t}\n");
366 fprintf(out, "}\n");
370 static void
371 nelma_write_layer(FILE * out, int z, int h,
372 const char *name, int full,
373 char *mat)
375 LibraryType netlist;
376 LibraryMenuType *net;
377 LibraryEntryType *pin;
379 int n, m;
381 fprintf(out, "layer %s {\n", name);
382 fprintf(out, "\theight = %d\n", h);
383 fprintf(out, "\tz-order = %d\n", z);
384 fprintf(out, "\tmaterial = \"%s\"\n", mat);
386 if (full) {
387 fprintf(out, "\tobjects = {\n");
388 netlist = PCB->NetlistLib;
390 for (n = 0; n < netlist.MenuN; n++) {
391 net = &netlist.Menu[n];
393 for (m = 0; m < net->EntryN; m++) {
394 pin = &net->Entry[m];
396 if (m != 0 || n != 0)
397 fprintf(out, ",\n");
398 fprintf(out, "\t\t\"%s-%s\"", pin->ListEntry,
399 name);
403 fprintf(out, "\n\t}\n");
405 fprintf(out, "}\n");
408 static void
409 nelma_write_layers(FILE * out)
411 int i, idx;
412 int z;
414 const char *ext;
415 char buf[100];
417 int subh;
419 subh = nelma_substrateh / nelma_copperh;
421 fprintf(out, "\n/* **** Layers **** */\n\n");
423 /* Air layers on top and bottom of the stack */
424 /* Their height is double substrate height. */
425 nelma_write_layer(out, 1, 2 * subh, "air-top", 0, "air");
426 nelma_write_layer(out, 1000, 2 * subh, "air-bottom", 0, "air");
428 z = 10;
429 for (i = 0; i < MAX_LAYER; i++)
430 if (nelma_export_group[i]) {
431 idx = (i >= 0 && i < max_group) ?
432 PCB->LayerGroups.Entries[i][0] : i;
433 ext = layer_type_to_file_name(idx, FNS_fixed);
435 if (z != 10) {
436 sprintf(buf, "substrate-%d", z);
437 nelma_write_layer(out,
439 subh,
440 buf,
442 "composite");
443 z++;
446 * FIXME: for layers that are not on top or bottom,
447 * the material should be "composite"
449 nelma_write_layer(out, z, 1, ext, 1, "air");
451 z++;
455 static void
456 nelma_write_object(FILE * out, LibraryEntryType *pin)
458 int i, idx;
459 Coord px = 0, py = 0;
460 int x, y;
462 char *f;
463 const char *ext;
465 pin_name_to_xy (pin, &px, &py);
467 x = pcb_to_nelma (px);
468 y = pcb_to_nelma (py);
470 for (i = 0; i < MAX_LAYER; i++)
471 if (nelma_export_group[i]) {
472 idx = (i >= 0 && i < max_group) ?
473 PCB->LayerGroups.Entries[i][0] : i;
474 ext = layer_type_to_file_name(idx, FNS_fixed);
476 fprintf(out, "object %s-%s {\n", pin->ListEntry, ext);
477 fprintf(out, "\tposition = { 0, 0 }\n");
478 fprintf(out, "\tmaterial = \"copper\"\n");
479 fprintf(out, "\ttype = \"image\"\n");
480 fprintf(out, "\trole = \"net\"\n");
482 f = nelma_get_png_name(nelma_basename, ext);
484 fprintf(out, "\tfile = \"%s\"\n", f);
486 free(f);
488 fprintf(out, "\tfile-pos = { %d, %d }\n", x, y);
489 fprintf(out, "}\n");
493 static void
494 nelma_write_objects(FILE * out)
496 LibraryType netlist;
497 LibraryMenuType *net;
498 LibraryEntryType *pin;
500 int n, m;
502 netlist = PCB->NetlistLib;
504 fprintf(out, "\n/* **** Objects **** */\n\n");
506 for (n = 0; n < netlist.MenuN; n++) {
507 net = &netlist.Menu[n];
509 for (m = 0; m < net->EntryN; m++) {
510 pin = &net->Entry[m];
512 nelma_write_object(out, pin);
517 /* *** Main export callback ************************************************ */
519 static void
520 nelma_parse_arguments(int *argc, char ***argv)
522 hid_register_attributes(nelma_attribute_list,
523 sizeof(nelma_attribute_list) /
524 sizeof(nelma_attribute_list[0]));
525 hid_parse_command_line(argc, argv);
528 static HID_Attribute *
529 nelma_get_export_options(int *n)
531 static char *last_made_filename = 0;
533 if (PCB) {
534 derive_default_filename(PCB->Filename,
535 &nelma_attribute_list[HA_basename],
536 ".nelma",
537 &last_made_filename);
539 if (n) {
540 *n = NUM_OPTIONS;
542 return nelma_attribute_list;
545 /* Populates nelma_export_group array */
546 void
547 nelma_choose_groups()
549 int n, m;
550 LayerType *layer;
552 /* Set entire array to 0 (don't export any layer groups by default */
553 memset(nelma_export_group, 0, sizeof(nelma_export_group));
555 for (n = 0; n < max_copper_layer; n++) {
556 layer = &PCB->Data->Layer[n];
558 if (layer->LineN || layer->TextN || layer->ArcN ||
559 layer->PolygonN) {
560 /* layer isn't empty */
563 * is this check necessary? It seems that special
564 * layers have negative indexes?
567 if (SL_TYPE(n) == 0) {
568 /* layer is a copper layer */
569 m = GetLayerGroupNumberByNumber(n);
571 /* the export layer */
572 nelma_export_group[m] = 1;
578 static void
579 nelma_alloc_colors()
582 * Allocate white and black -- the first color allocated becomes the
583 * background color
586 white = (struct color_struct *) malloc(sizeof(*white));
587 white->r = white->g = white->b = 255;
588 white->c = gdImageColorAllocate(nelma_im, white->r, white->g, white->b);
590 black = (struct color_struct *) malloc(sizeof(*black));
591 black->r = black->g = black->b = 0;
592 black->c = gdImageColorAllocate(nelma_im, black->r, black->g, black->b);
595 static void
596 nelma_start_png(const char *basename, const char *suffix)
598 int h, w;
599 char *buf;
601 buf = nelma_get_png_name(basename, suffix);
603 h = pcb_to_nelma(PCB->MaxHeight);
604 w = pcb_to_nelma(PCB->MaxWidth);
606 /* nelma_im = gdImageCreate (w, h); */
608 /* Nelma only works with true color images */
609 nelma_im = gdImageCreate(w, h);
610 nelma_f = fopen(buf, "wb");
612 nelma_alloc_colors();
614 free(buf);
617 static void
618 nelma_finish_png()
620 #ifdef HAVE_GDIMAGEPNG
621 gdImagePng(nelma_im, nelma_f);
622 #else
623 Message("NELMA: PNG not supported by gd. Can't write layer mask.\n");
624 #endif
625 gdImageDestroy(nelma_im);
626 fclose(nelma_f);
628 free(white);
629 free(black);
631 nelma_im = NULL;
632 nelma_f = NULL;
635 void
636 nelma_start_png_export()
638 BoxType region;
640 region.X1 = 0;
641 region.Y1 = 0;
642 region.X2 = PCB->MaxWidth;
643 region.Y2 = PCB->MaxHeight;
645 linewidth = -1;
646 lastbrush = (gdImagePtr)((void *) -1);
648 hid_expose_callback(&nelma_hid, &region, 0);
651 static void
652 nelma_do_export(HID_Attr_Val * options)
654 int save_ons[MAX_LAYER + 2];
655 int i, idx;
656 FILE *nelma_config;
657 char *buf;
658 int len;
660 time_t t;
662 if (!options) {
663 nelma_get_export_options(0);
664 for (i = 0; i < NUM_OPTIONS; i++) {
665 nelma_values[i] = nelma_attribute_list[i].default_val;
667 options = nelma_values;
669 nelma_basename = options[HA_basename].str_value;
670 if (!nelma_basename) {
671 nelma_basename = "pcb-out";
673 nelma_dpi = options[HA_dpi].int_value;
674 if (nelma_dpi < 0) {
675 fprintf(stderr, "ERROR: dpi may not be < 0\n");
676 return;
678 nelma_copperh = options[HA_copperh].int_value;
679 nelma_substrateh = options[HA_substrateh].int_value;
680 nelma_substratee = options[HA_substratee].real_value;
682 nelma_choose_groups();
684 for (i = 0; i < MAX_LAYER; i++) {
685 if (nelma_export_group[i]) {
687 nelma_cur_group = i;
689 /* magic */
690 idx = (i >= 0 && i < max_group) ?
691 PCB->LayerGroups.Entries[i][0] : i;
693 nelma_start_png(nelma_basename,
694 layer_type_to_file_name(idx, FNS_fixed));
696 hid_save_and_show_layer_ons(save_ons);
697 nelma_start_png_export();
698 hid_restore_layer_ons(save_ons);
700 nelma_finish_png();
704 len = strlen(nelma_basename) + 4;
705 buf = (char *)malloc(sizeof(*buf) * len);
707 sprintf(buf, "%s.em", nelma_basename);
708 nelma_config = fopen(buf, "w");
710 free(buf);
712 fprintf(nelma_config, "/* Made with PCB Nelma export HID */");
713 t = time(NULL);
714 fprintf(nelma_config, "/* %s */", ctime(&t));
716 nelma_write_nets(nelma_config);
717 nelma_write_objects(nelma_config);
718 nelma_write_layers(nelma_config);
719 nelma_write_materials(nelma_config);
720 nelma_write_space(nelma_config);
722 fclose(nelma_config);
725 /* *** PNG export (slightly modified code from PNG export HID) ************* */
727 static int
728 nelma_set_layer(const char *name, int group, int empty)
730 int idx = (group >= 0 && group < max_group) ?
731 PCB->LayerGroups.Entries[group][0] : group;
733 if (name == 0) {
734 name = PCB->Data->Layer[idx].Name;
736 if (strcmp(name, "invisible") == 0) {
737 return 0;
739 is_drill = (SL_TYPE(idx) == SL_PDRILL || SL_TYPE(idx) == SL_UDRILL);
740 is_mask = (SL_TYPE(idx) == SL_MASK);
742 if (is_mask) {
743 /* Don't print masks */
744 return 0;
746 if (is_drill) {
748 * Print 'holes', so that we can fill gaps in the copper
749 * layer
751 return 1;
753 if (group == nelma_cur_group) {
754 return 1;
756 return 0;
759 static hidGC
760 nelma_make_gc(void)
762 hidGC rv = (hidGC) malloc(sizeof(struct hid_gc_struct));
763 rv->me_pointer = &nelma_hid;
764 rv->cap = Trace_Cap;
765 rv->width = 1;
766 rv->color = (struct color_struct *) malloc(sizeof(*rv->color));
767 rv->color->r = rv->color->g = rv->color->b = 0;
768 rv->color->c = 0;
769 return rv;
772 static void
773 nelma_destroy_gc(hidGC gc)
775 free(gc);
778 static void
779 nelma_use_mask(enum mask_mode mode)
781 /* does nothing */
784 static void
785 nelma_set_color(hidGC gc, const char *name)
787 if (nelma_im == NULL) {
788 return;
790 if (name == NULL) {
791 name = "#ff0000";
793 if (!strcmp(name, "drill")) {
794 gc->color = black;
795 gc->erase = 0;
796 return;
798 if (!strcmp(name, "erase")) {
799 /* FIXME -- should be background, not white */
800 gc->color = white;
801 gc->erase = 1;
802 return;
804 gc->color = black;
805 gc->erase = 0;
806 return;
809 static void
810 nelma_set_line_cap(hidGC gc, EndCapStyle style)
812 gc->cap = style;
815 static void
816 nelma_set_line_width(hidGC gc, Coord width)
818 gc->width = width;
821 static void
822 nelma_set_draw_xor(hidGC gc, int xor_)
827 static void
828 nelma_set_draw_faded(hidGC gc, int faded)
832 static void
833 use_gc(hidGC gc)
835 int need_brush = 0;
837 if (gc->me_pointer != &nelma_hid) {
838 fprintf(stderr, "Fatal: GC from another HID passed to nelma HID\n");
839 abort();
841 if (linewidth != gc->width) {
842 /* Make sure the scaling doesn't erase lines completely */
844 if (SCALE (gc->width) == 0 && gc->width > 0)
845 gdImageSetThickness (im, 1);
846 else
848 gdImageSetThickness(nelma_im, pcb_to_nelma(gc->width));
849 linewidth = gc->width;
850 need_brush = 1;
852 if (lastbrush != gc->brush || need_brush) {
853 static void *bcache = 0;
854 hidval bval;
855 char name[256];
856 char type;
857 int r;
859 switch (gc->cap) {
860 case Round_Cap:
861 case Trace_Cap:
862 type = 'C';
863 r = pcb_to_nelma(gc->width / 2);
864 break;
865 default:
866 case Square_Cap:
867 r = pcb_to_nelma(gc->width);
868 type = 'S';
869 break;
871 sprintf(name, "#%.2x%.2x%.2x_%c_%d", gc->color->r, gc->color->g,
872 gc->color->b, type, r);
874 if (hid_cache_color(0, name, &bval, &bcache)) {
875 gc->brush = (gdImagePtr)bval.ptr;
876 } else {
877 int bg, fg;
878 if (type == 'C')
879 gc->brush = gdImageCreate(2 * r + 1, 2 * r + 1);
880 else
881 gc->brush = gdImageCreate(r + 1, r + 1);
882 bg = gdImageColorAllocate(gc->brush, 255, 255, 255);
883 fg =
884 gdImageColorAllocate(gc->brush, gc->color->r, gc->color->g,
885 gc->color->b);
886 gdImageColorTransparent(gc->brush, bg);
889 * if we shrunk to a radius/box width of zero, then just use
890 * a single pixel to draw with.
892 if (r == 0)
893 gdImageFilledRectangle(gc->brush, 0, 0, 0, 0, fg);
894 else {
895 if (type == 'C')
896 gdImageFilledEllipse(gc->brush, r, r, 2 * r, 2 * r, fg);
897 else
898 gdImageFilledRectangle(gc->brush, 0, 0, r, r, fg);
900 bval.ptr = gc->brush;
901 hid_cache_color(1, name, &bval, &bcache);
904 gdImageSetBrush(nelma_im, gc->brush);
905 lastbrush = gc->brush;
910 static void
911 nelma_draw_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
913 use_gc(gc);
914 gdImageRectangle(nelma_im,
915 pcb_to_nelma(x1), pcb_to_nelma(y1),
916 pcb_to_nelma(x2), pcb_to_nelma(y2), gc->color->c);
919 static void
920 nelma_fill_rect(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
922 use_gc(gc);
923 gdImageSetThickness(nelma_im, 0);
924 linewidth = 0;
925 gdImageFilledRectangle(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1),
926 pcb_to_nelma(x2), pcb_to_nelma(y2), gc->color->c);
929 static void
930 nelma_draw_line(hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
932 if (x1 == x2 && y1 == y2) {
933 Coord w = gc->width / 2;
934 nelma_fill_rect(gc, x1 - w, y1 - w, x1 + w, y1 + w);
935 return;
937 use_gc(gc);
939 gdImageSetThickness(nelma_im, 0);
940 linewidth = 0;
941 gdImageLine(nelma_im, pcb_to_nelma(x1), pcb_to_nelma(y1),
942 pcb_to_nelma(x2), pcb_to_nelma(y2), gdBrushed);
945 static void
946 nelma_draw_arc(hidGC gc, Coord cx, Coord cy, Coord width, Coord height,
947 Angle start_angle, Angle delta_angle)
949 Angle sa, ea;
952 * in gdImageArc, 0 degrees is to the right and +90 degrees is down
953 * in pcb, 0 degrees is to the left and +90 degrees is down
955 start_angle = 180 - start_angle;
956 delta_angle = -delta_angle;
957 if (delta_angle > 0) {
958 sa = start_angle;
959 ea = start_angle + delta_angle;
960 } else {
961 sa = start_angle + delta_angle;
962 ea = start_angle;
966 * make sure we start between 0 and 360 otherwise gd does strange
967 * things
969 sa = NormalizeAngle (sa);
970 ea = NormalizeAngle (ea);
972 #if 0
973 printf("draw_arc %d,%d %dx%d %d..%d %d..%d\n",
974 cx, cy, width, height, start_angle, delta_angle, sa, ea);
975 printf("gdImageArc (%p, %d, %d, %d, %d, %d, %d, %d)\n",
976 im, SCALE_X(cx), SCALE_Y(cy),
977 SCALE(width), SCALE(height), sa, ea, gc->color->c);
978 #endif
979 use_gc(gc);
980 gdImageSetThickness(nelma_im, 0);
981 linewidth = 0;
982 gdImageArc(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy),
983 pcb_to_nelma(2 * width), pcb_to_nelma(2 * height), sa, ea, gdBrushed);
986 static void
987 nelma_fill_circle(hidGC gc, Coord cx, Coord cy, Coord radius)
989 use_gc(gc);
991 gdImageSetThickness(nelma_im, 0);
992 linewidth = 0;
993 gdImageFilledEllipse(nelma_im, pcb_to_nelma(cx), pcb_to_nelma(cy),
994 pcb_to_nelma(2 * radius), pcb_to_nelma(2 * radius), gc->color->c);
998 static void
999 nelma_fill_polygon(hidGC gc, int n_coords, Coord *x, Coord *y)
1001 int i;
1002 gdPoint *points;
1004 points = (gdPoint *) malloc(n_coords * sizeof(gdPoint));
1005 if (points == NULL) {
1006 fprintf(stderr, "ERROR: nelma_fill_polygon(): malloc failed\n");
1007 exit(1);
1009 use_gc(gc);
1010 for (i = 0; i < n_coords; i++) {
1011 points[i].x = pcb_to_nelma(x[i]);
1012 points[i].y = pcb_to_nelma(y[i]);
1014 gdImageSetThickness(nelma_im, 0);
1015 linewidth = 0;
1016 gdImageFilledPolygon(nelma_im, points, n_coords, gc->color->c);
1017 free(points);
1020 static void
1021 nelma_calibrate(double xval, double yval)
1023 CRASH;
1026 static void
1027 nelma_set_crosshair(int x, int y, int a)
1031 /* *** Miscellaneous ******************************************************* */
1033 #include "dolists.h"
1035 void
1036 hid_nelma_init()
1038 memset (&nelma_hid, 0, sizeof (HID));
1040 common_nogui_init (&nelma_hid);
1041 common_draw_helpers_init (&nelma_hid);
1043 nelma_hid.struct_size = sizeof (HID);
1044 nelma_hid.name = "nelma";
1045 nelma_hid.description = "Numerical analysis package export";
1046 nelma_hid.exporter = 1;
1047 nelma_hid.poly_before = 1;
1049 nelma_hid.get_export_options = nelma_get_export_options;
1050 nelma_hid.do_export = nelma_do_export;
1051 nelma_hid.parse_arguments = nelma_parse_arguments;
1052 nelma_hid.set_layer = nelma_set_layer;
1053 nelma_hid.make_gc = nelma_make_gc;
1054 nelma_hid.destroy_gc = nelma_destroy_gc;
1055 nelma_hid.use_mask = nelma_use_mask;
1056 nelma_hid.set_color = nelma_set_color;
1057 nelma_hid.set_line_cap = nelma_set_line_cap;
1058 nelma_hid.set_line_width = nelma_set_line_width;
1059 nelma_hid.set_draw_xor = nelma_set_draw_xor;
1060 nelma_hid.set_draw_faded = nelma_set_draw_faded;
1061 nelma_hid.draw_line = nelma_draw_line;
1062 nelma_hid.draw_arc = nelma_draw_arc;
1063 nelma_hid.draw_rect = nelma_draw_rect;
1064 nelma_hid.fill_circle = nelma_fill_circle;
1065 nelma_hid.fill_polygon = nelma_fill_polygon;
1066 nelma_hid.fill_rect = nelma_fill_rect;
1067 nelma_hid.calibrate = nelma_calibrate;
1068 nelma_hid.set_crosshair = nelma_set_crosshair;
1070 hid_register_hid (&nelma_hid);
1072 #include "nelma_lists.h"