Move some fields from the HID* structure to HID_DRAW* and HID_DRAW_CLASS*
[geda-pcb/pcjc2.git] / src / hid / ps / eps.c
blob3f0afc660da5c8fb3c2cf7ef4685fe83c7c4ef6f
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
5 #include <stdio.h>
6 #include <stdarg.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <assert.h>
11 #include "global.h"
12 #include "data.h"
13 #include "misc.h"
14 #include "pcb-printf.h"
16 #include "hid.h"
17 #include "hid_draw.h"
18 #include "../hidint.h"
19 #include "hid/common/hidnogui.h"
20 #include "hid/common/draw_helpers.h"
21 #include "../ps/ps.h"
22 #include "hid/common/hidinit.h"
24 #ifdef HAVE_LIBDMALLOC
25 #include <dmalloc.h>
26 #endif
28 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented EPS function %s.\n", __FUNCTION__); abort()
30 /*----------------------------------------------------------------------------*/
31 /* Function prototypes */
32 /*----------------------------------------------------------------------------*/
33 static HID_Attribute * eps_get_export_options (int *n);
34 static void eps_do_export (HID_Attr_Val * options);
35 static void eps_parse_arguments (int *argc, char ***argv);
36 static int eps_set_layer (const char *name, int group, int empty);
37 static hidGC eps_make_gc (void);
38 static void eps_destroy_gc (hidGC gc);
39 static void eps_use_mask (enum mask_mode mode);
40 static void eps_set_color (hidGC gc, const char *name);
41 static void eps_set_line_cap (hidGC gc, EndCapStyle style);
42 static void eps_set_line_width (hidGC gc, Coord width);
43 static void eps_set_draw_xor (hidGC gc, int _xor);
44 static void eps_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2);
45 static void eps_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2);
46 static void eps_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height, Angle start_angle, Angle delta_angle);
47 static void eps_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2);
48 static void eps_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius);
49 static void eps_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y);
50 static void eps_calibrate (double xval, double yval);
51 static void eps_set_crosshair (int x, int y, int action);
52 /*----------------------------------------------------------------------------*/
54 typedef struct eps_gc_struct
56 struct hid_gc_struct hid_gc; /* Parent */
58 EndCapStyle cap;
59 Coord width;
60 int color;
61 int erase;
62 } *epsGC;
64 static HID eps_hid;
65 static HID_DRAW eps_graphics;
66 static HID_DRAW_CLASS eps_graphics_class;
68 static FILE *f = 0;
69 static Coord linewidth = -1;
70 static int lastcap = -1;
71 static int lastcolor = -1;
72 static int print_group[MAX_GROUP];
73 static int print_layer[MAX_LAYER];
74 static int fast_erase = -1;
76 static HID_Attribute eps_attribute_list[] = {
77 /* other HIDs expect this to be first. */
79 /* %start-doc options "92 Encapsulated Postscript Export"
80 @ftable @code
81 @item --eps-file <string>
82 Name of the encapsulated postscript output file. Can contain a path.
83 @end ftable
84 %end-doc
86 {"eps-file", "Encapsulated Postscript output file",
87 HID_String, 0, 0, {0, 0, 0}, 0, 0},
88 #define HA_psfile 0
90 /* %start-doc options "92 Encapsulated Postscript Export"
91 @ftable @code
92 @item --eps-scale <num>
93 Scale EPS output by the parameter @samp{num}.
94 @end ftable
95 %end-doc
97 {"eps-scale", "EPS scale",
98 HID_Real, 0, 100, {0, 0, 1.0}, 0, 0},
99 #define HA_scale 1
101 /* %start-doc options "92 Encapsulated Postscript Export"
102 @ftable @code
103 @cindex as-shown (EPS)
104 @item --as-shown
105 Export layers as shown on screen.
106 @end ftable
107 %end-doc
109 {"as-shown", "Export layers as shown on screen",
110 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
111 #define HA_as_shown 2
113 /* %start-doc options "92 Encapsulated Postscript Export"
114 @ftable @code
115 @item --monochrome
116 Convert output to monochrome.
117 @end ftable
118 %end-doc
120 {"monochrome", "Convert to monochrome",
121 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
122 #define HA_mono 3
124 /* %start-doc options "92 Encapsulated Postscript Export"
125 @ftable @code
126 @cindex only-visible
127 @item --only-visible
128 Limit the bounds of the EPS file to the visible items.
129 @end ftable
130 %end-doc
132 {"only-visible", "Limit the bounds of the EPS file to the visible items",
133 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
134 #define HA_only_visible 4
137 #define NUM_OPTIONS (sizeof(eps_attribute_list)/sizeof(eps_attribute_list[0]))
139 REGISTER_ATTRIBUTES (eps_attribute_list)
141 static HID_Attr_Val eps_values[NUM_OPTIONS];
143 static HID_Attribute *
144 eps_get_export_options (int *n)
146 static char *last_made_filename = 0;
148 if (PCB) derive_default_filename(PCB->Filename, &eps_attribute_list[HA_psfile], ".eps", &last_made_filename);
150 if (n)
151 *n = NUM_OPTIONS;
152 return eps_attribute_list;
155 static int top_group, bottom_group;
157 static int
158 layer_stack_sort (const void *va, const void *vb)
160 int a_layer = *(int *) va;
161 int b_layer = *(int *) vb;
162 int a_group = GetLayerGroupNumberByNumber (a_layer);
163 int b_group = GetLayerGroupNumberByNumber (b_layer);
164 int aside = (a_group == bottom_group ? 0 : a_group == top_group ? 2 : 1);
165 int bside = (b_group == bottom_group ? 0 : b_group == top_group ? 2 : 1);
167 if (bside != aside)
168 return bside - aside;
170 if (b_group != a_group)
171 return b_group - a_group;
173 return b_layer - a_layer;
176 static const char *filename;
177 static BoxType *bounds;
178 static int in_mono, as_shown;
180 void
181 eps_hid_export_to_file (FILE * the_file, HID_Attr_Val * options)
183 int i;
184 static int saved_layer_stack[MAX_LAYER];
185 BoxType region;
186 FlagType save_thindraw;
188 save_thindraw = PCB->Flags;
189 CLEAR_FLAG(THINDRAWFLAG, PCB);
190 CLEAR_FLAG(THINDRAWPOLYFLAG, PCB);
191 CLEAR_FLAG(CHECKPLANESFLAG, PCB);
193 f = the_file;
195 region.X1 = 0;
196 region.Y1 = 0;
197 region.X2 = PCB->MaxWidth;
198 region.Y2 = PCB->MaxHeight;
200 if (options[HA_only_visible].int_value)
201 bounds = GetDataBoundingBox (PCB->Data);
202 else
203 bounds = &region;
205 memset (print_group, 0, sizeof (print_group));
206 memset (print_layer, 0, sizeof (print_layer));
208 /* Figure out which layers actually have stuff on them. */
209 for (i = 0; i < max_copper_layer; i++)
211 LayerType *layer = PCB->Data->Layer + i;
212 if (layer->On)
213 if (layer->LineN || layer->TextN || layer->ArcN || layer->PolygonN)
214 print_group[GetLayerGroupNumberByNumber (i)] = 1;
217 /* Now, if only one layer has real stuff on it, we can use the fast
218 erase logic. Otherwise, we have to use the expensive multi-mask
219 erase. */
220 fast_erase = 0;
221 for (i = 0; i < max_group; i++)
222 if (print_group[i])
223 fast_erase ++;
225 /* If NO layers had anything on them, at least print the component
226 layer to get the pins. */
227 if (fast_erase == 0)
229 print_group[GetLayerGroupNumberBySide (TOP_SIDE)] = 1;
230 fast_erase = 1;
233 /* "fast_erase" is 1 if we can just paint white to erase. */
234 fast_erase = fast_erase == 1 ? 1 : 0;
236 /* Now, for each group we're printing, mark its layers for
237 printing. */
238 for (i = 0; i < max_copper_layer; i++)
239 if (print_group[GetLayerGroupNumberByNumber (i)])
240 print_layer[i] = 1;
242 if (fast_erase) {
243 eps_graphics.poly_before = true;
244 eps_graphics.poly_after = false;
245 } else {
246 eps_graphics.poly_before = false;
247 eps_graphics.poly_after = true;
250 memcpy (saved_layer_stack, LayerStack, sizeof (LayerStack));
251 as_shown = options[HA_as_shown].int_value;
252 if (!options[HA_as_shown].int_value)
254 top_group = GetLayerGroupNumberBySide (TOP_SIDE);
255 bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
256 qsort (LayerStack, max_copper_layer, sizeof (LayerStack[0]), layer_stack_sort);
258 fprintf (f, "%%!PS-Adobe-3.0 EPSF-3.0\n");
259 linewidth = -1;
260 lastcap = -1;
261 lastcolor = -1;
263 in_mono = options[HA_mono].int_value;
265 #define pcb2em(x) 1 + COORD_TO_INCH (x) * 72.0 * options[HA_scale].real_value
266 fprintf (f, "%%%%BoundingBox: 0 0 %lli %lli\n",
267 llrint (pcb2em (bounds->X2 - bounds->X1)),
268 llrint (pcb2em (bounds->Y2 - bounds->Y1)) );
269 fprintf (f, "%%%%HiResBoundingBox: 0.000000 0.000000 %.6f %.6f\n",
270 pcb2em (bounds->X2 - bounds->X1),
271 pcb2em (bounds->Y2 - bounds->Y1));
272 #undef pcb2em
273 fprintf (f, "%%%%Pages: 1\n");
274 fprintf (f,
275 "save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def\n");
276 fprintf (f, "%%%%EndProlog\n");
277 fprintf (f, "%%%%Page: 1 1\n");
278 fprintf (f, "%%%%BeginDocument: %s\n\n", filename);
280 fprintf (f, "72 72 scale\n");
281 fprintf (f, "1 dup neg scale\n");
282 fprintf (f, "%g dup scale\n", options[HA_scale].real_value);
283 pcb_fprintf (f, "%mi %mi translate\n", -bounds->X1, -bounds->Y2);
284 if (options[HA_as_shown].int_value && Settings.ShowBottomSide)
285 pcb_fprintf (f, "-1 1 scale %mi 0 translate\n", bounds->X1 - bounds->X2);
286 linewidth = -1;
287 lastcap = -1;
288 lastcolor = -1;
289 #define Q (Coord) MIL_TO_COORD(10)
290 pcb_fprintf (f,
291 "/nclip { %mi %mi moveto %mi %mi lineto %mi %mi lineto %mi %mi lineto %mi %mi lineto eoclip newpath } def\n",
292 bounds->X1 - Q, bounds->Y1 - Q, bounds->X1 - Q, bounds->Y2 + Q,
293 bounds->X2 + Q, bounds->Y2 + Q, bounds->X2 + Q, bounds->Y1 - Q,
294 bounds->X1 - Q, bounds->Y1 - Q);
295 #undef Q
296 fprintf (f, "/t { moveto lineto stroke } bind def\n");
297 fprintf (f, "/tc { moveto lineto strokepath nclip } bind def\n");
298 fprintf (f, "/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n");
299 fprintf (f,
300 " x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def\n");
301 fprintf (f, "/c { 0 360 arc fill } bind def\n");
302 fprintf (f, "/cc { 0 360 arc nclip } bind def\n");
303 fprintf (f,
304 "/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def\n");
306 hid_expose_callback (&eps_hid, bounds, 0);
308 fprintf (f, "showpage\n");
310 fprintf (f, "%%%%EndDocument\n");
311 fprintf (f, "%%%%Trailer\n");
312 fprintf (f, "cleartomark countdictstack exch sub { end } repeat restore\n");
313 fprintf (f, "%%%%EOF\n");
315 memcpy (LayerStack, saved_layer_stack, sizeof (LayerStack));
316 PCB->Flags = save_thindraw;
319 static void
320 eps_do_export (HID_Attr_Val * options)
322 int i;
323 int save_ons[MAX_LAYER + 2];
325 if (!options)
327 eps_get_export_options (0);
328 for (i = 0; i < NUM_OPTIONS; i++)
329 eps_values[i] = eps_attribute_list[i].default_val;
330 options = eps_values;
333 filename = options[HA_psfile].str_value;
334 if (!filename)
335 filename = "pcb-out.eps";
337 f = fopen (filename, "w");
338 if (!f)
340 perror (filename);
341 return;
344 if (!options[HA_as_shown].int_value)
345 hid_save_and_show_layer_ons (save_ons);
346 eps_hid_export_to_file (f, options);
347 if (!options[HA_as_shown].int_value)
348 hid_restore_layer_ons (save_ons);
350 fclose (f);
353 static void
354 eps_parse_arguments (int *argc, char ***argv)
356 hid_register_attributes (eps_attribute_list,
357 sizeof (eps_attribute_list) /
358 sizeof (eps_attribute_list[0]));
359 hid_parse_command_line (argc, argv);
362 static int is_mask;
363 static int is_paste;
364 static int is_drill;
366 static int
367 eps_set_layer (const char *name, int group, int empty)
369 int idx = (group >= 0
370 && group <
371 max_group) ? PCB->LayerGroups.Entries[group][0] : group;
372 if (name == 0)
373 name = PCB->Data->Layer[idx].Name;
375 if (idx >= 0 && idx < max_copper_layer && !print_layer[idx])
376 return 0;
377 if (SL_TYPE (idx) == SL_ASSY || SL_TYPE (idx) == SL_FAB)
378 return 0;
380 if (strcmp (name, "invisible") == 0)
381 return 0;
383 is_drill = (SL_TYPE (idx) == SL_PDRILL || SL_TYPE (idx) == SL_UDRILL);
384 is_mask = (SL_TYPE (idx) == SL_MASK);
385 is_paste = (SL_TYPE (idx) == SL_PASTE);
387 if (is_mask || is_paste)
388 return 0;
389 #if 0
390 printf ("Layer %s group %d drill %d mask %d\n", name, group, is_drill,
391 is_mask);
392 #endif
393 fprintf (f, "%% Layer %s group %d drill %d mask %d\n", name, group,
394 is_drill, is_mask);
396 if (as_shown)
398 switch (idx)
400 case SL (SILK, TOP):
401 case SL (SILK, BOTTOM):
402 if (SL_MYSIDE (idx))
403 return PCB->ElementOn;
404 else
405 return 0;
408 else
410 switch (idx)
412 case SL (SILK, TOP):
413 return 1;
414 case SL (SILK, BOTTOM):
415 return 0;
419 return 1;
422 static hidGC
423 eps_make_gc (void)
425 hidGC gc = (hidGC) calloc (1, sizeof (struct eps_gc_struct));
426 epsGC eps_gc = (epsGC)gc;
428 gc->hid = &eps_hid;
429 gc->hid_draw = &eps_graphics;
431 eps_gc->cap = Trace_Cap;
432 eps_gc->width = 0;
433 eps_gc->color = 0;
435 return gc;
438 static void
439 eps_destroy_gc (hidGC gc)
441 free (gc);
444 static void
445 eps_use_mask (enum mask_mode mode)
447 static int mask_pending = 0;
448 switch (mode)
450 case HID_MASK_CLEAR:
451 if (!mask_pending)
453 mask_pending = 1;
454 fprintf (f, "gsave\n");
456 break;
457 case HID_MASK_BEFORE:
458 case HID_MASK_AFTER:
459 break;
460 case HID_MASK_OFF:
461 if (mask_pending)
463 mask_pending = 0;
464 fprintf (f, "grestore\n");
465 lastcolor = -1;
467 break;
471 static void
472 eps_set_color (hidGC gc, const char *name)
474 epsGC eps_gc = (epsGC)gc;
475 static void *cache = 0;
476 hidval cval;
478 if (strcmp (name, "erase") == 0)
480 eps_gc->color = 0xffffff;
481 eps_gc->erase = fast_erase ? 0 : 1;
482 return;
484 if (strcmp (name, "drill") == 0)
486 eps_gc->color = 0xffffff;
487 eps_gc->erase = 0;
488 return;
490 eps_gc->erase = 0;
491 if (hid_cache_color (0, name, &cval, &cache))
493 eps_gc->color = cval.lval;
495 else if (in_mono)
497 eps_gc->color = 0;
499 else if (name[0] == '#')
501 unsigned int r, g, b;
502 sscanf (name + 1, "%2x%2x%2x", &r, &g, &b);
503 eps_gc->color = (r << 16) + (g << 8) + b;
505 else
506 eps_gc->color = 0;
509 static void
510 eps_set_line_cap (hidGC gc, EndCapStyle style)
512 epsGC eps_gc = (epsGC)gc;
514 eps_gc->cap = style;
517 static void
518 eps_set_line_width (hidGC gc, Coord width)
520 epsGC eps_gc = (epsGC)gc;
522 eps_gc->width = width;
525 static void
526 eps_set_draw_xor (hidGC gc, int xor_)
531 static void
532 use_gc (hidGC gc)
534 epsGC eps_gc = (epsGC)gc;
536 if (linewidth != eps_gc->width)
538 pcb_fprintf (f, "%mi setlinewidth\n", eps_gc->width);
539 linewidth = eps_gc->width;
541 if (lastcap != eps_gc->cap)
543 int c;
544 switch (eps_gc->cap)
546 case Round_Cap:
547 case Trace_Cap:
548 c = 1;
549 break;
550 default:
551 case Square_Cap:
552 c = 2;
553 break;
555 fprintf (f, "%d setlinecap\n", c);
556 lastcap = eps_gc->cap;
558 if (lastcolor != eps_gc->color)
560 int c = eps_gc->color;
561 #define CV(x,b) (((x>>b)&0xff)/255.0)
562 fprintf (f, "%g %g %g setrgbcolor\n", CV (c, 16), CV (c, 8), CV (c, 0));
563 lastcolor = eps_gc->color;
567 static void eps_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2);
568 static void eps_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius);
570 static void
571 eps_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
573 use_gc (gc);
574 pcb_fprintf (f, "%mi %mi %mi %mi r\n", x1, y1, x2, y2);
577 static void
578 eps_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
580 epsGC eps_gc = (epsGC)gc;
581 Coord w = eps_gc->width / 2;
583 if (x1 == x2 && y1 == y2)
585 if (eps_gc->cap == Square_Cap)
586 eps_fill_rect (gc, x1 - w, y1 - w, x1 + w, y1 + w);
587 else
588 eps_fill_circle (gc, x1, y1, w);
589 return;
591 use_gc (gc);
592 if (eps_gc->erase && eps_gc->cap != Square_Cap)
594 double ang = atan2 (y2 - y1, x2 - x1);
595 double dx = w * sin (ang);
596 double dy = -w * cos (ang);
597 double deg = ang * 180.0 / M_PI;
598 Coord vx1 = x1 + dx;
599 Coord vy1 = y1 + dy;
601 pcb_fprintf (f, "%mi %mi moveto ", vx1, vy1);
602 pcb_fprintf (f, "%mi %mi %mi %g %g arc\n", x2, y2, w, deg - 90, deg + 90);
603 pcb_fprintf (f, "%mi %mi %mi %g %g arc\n", x1, y1, w, deg + 90, deg + 270);
604 fprintf (f, "nclip\n");
606 return;
608 pcb_fprintf (f, "%mi %mi %mi %mi %s\n", x1, y1, x2, y2, eps_gc->erase ? "tc" : "t");
611 static void
612 eps_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height,
613 Angle start_angle, Angle delta_angle)
615 Angle sa, ea;
616 if (delta_angle > 0)
618 sa = start_angle;
619 ea = start_angle + delta_angle;
621 else
623 sa = start_angle + delta_angle;
624 ea = start_angle;
626 #if 0
627 printf ("draw_arc %d,%d %dx%d %d..%d %d..%d\n",
628 cx, cy, width, height, start_angle, delta_angle, sa, ea);
629 #endif
630 use_gc (gc);
631 pcb_fprintf (f, "%ma %ma %mi %mi %mi %mi %g a\n",
632 sa, ea, -width, height, cx, cy, (double) linewidth / width);
635 static void
636 eps_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
638 epsGC eps_gc = (epsGC)gc;
640 use_gc (gc);
641 pcb_fprintf (f, "%mi %mi %mi %s\n", cx, cy, radius, eps_gc->erase ? "cc" : "c");
644 static void
645 eps_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
647 int i;
648 char *op = "moveto";
649 use_gc (gc);
650 for (i = 0; i < n_coords; i++)
652 pcb_fprintf (f, "%mi %mi %s\n", x[i], y[i], op);
653 op = "lineto";
655 fprintf (f, "fill\n");
658 static void
659 eps_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
661 use_gc (gc);
662 pcb_fprintf (f, "%mi %mi %mi %mi r\n", x1, y1, x2, y2);
665 static void
666 eps_calibrate (double xval, double yval)
668 CRASH;
671 static void
672 eps_set_crosshair (int x, int y, int action)
676 void
677 hid_eps_init ()
679 memset (&eps_hid, 0, sizeof (HID));
680 memset (&eps_graphics, 0, sizeof (HID_DRAW));
681 memset (&eps_graphics_class, 0, sizeof (HID_DRAW_CLASS));
683 common_nogui_init (&eps_hid);
685 eps_hid.struct_size = sizeof (HID);
686 eps_hid.name = "eps";
687 eps_hid.description = "Encapsulated Postscript";
688 eps_hid.exporter = 1;
690 eps_hid.get_export_options = eps_get_export_options;
691 eps_hid.do_export = eps_do_export;
692 eps_hid.parse_arguments = eps_parse_arguments;
693 eps_hid.calibrate = eps_calibrate;
694 eps_hid.set_crosshair = eps_set_crosshair;
696 eps_hid.graphics = &eps_graphics;
698 common_draw_helpers_class_init (&eps_graphics_class);
700 eps_graphics_class.set_layer = eps_set_layer;
701 eps_graphics_class.make_gc = eps_make_gc;
702 eps_graphics_class.destroy_gc = eps_destroy_gc;
703 eps_graphics_class.use_mask = eps_use_mask;
704 eps_graphics_class.set_color = eps_set_color;
705 eps_graphics_class.set_line_cap = eps_set_line_cap;
706 eps_graphics_class.set_line_width = eps_set_line_width;
707 eps_graphics_class.set_draw_xor = eps_set_draw_xor;
708 eps_graphics_class.draw_line = eps_draw_line;
709 eps_graphics_class.draw_arc = eps_draw_arc;
710 eps_graphics_class.draw_rect = eps_draw_rect;
711 eps_graphics_class.fill_circle = eps_fill_circle;
712 eps_graphics_class.fill_polygon = eps_fill_polygon;
713 eps_graphics_class.fill_rect = eps_fill_rect;
715 eps_graphics.klass = &eps_graphics_class;
716 eps_graphics.poly_after = true;
717 common_draw_helpers_init (&eps_graphics);
719 hid_register_hid (&eps_hid);