Add support for filling / thindrawing raw polygons to the HID interface
[geda-pcb/gde.git] / src / hid / ps / ps.c
blobd742a5f1083a5a7044f121ea833b620576d5e52b
1 /* $Id$ */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdio.h>
8 #include <stdarg.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <assert.h>
13 #include "global.h"
14 #include "data.h"
15 #include "misc.h"
16 #include "error.h"
17 #include "draw.h"
19 #include "hid.h"
20 #include "../hidint.h"
21 #include "hid/common/draw_helpers.h"
22 #include "../ps/ps.h"
23 #include "../../print.h"
25 #ifdef HAVE_LIBDMALLOC
26 #include <dmalloc.h>
27 #endif
29 RCSID ("$Id$");
31 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented PS function %s.\n", __FUNCTION__); abort()
33 typedef struct hid_gc_struct
35 HID *me_pointer;
36 EndCapStyle cap;
37 int width;
38 unsigned char r, g, b;
39 int erase;
40 int faded;
41 } hid_gc_struct;
43 static double calibration_x = 1.0, calibration_y = 1.0;
45 static FILE *f = 0;
46 static int pagecount = 0;
47 static int linewidth = -1;
48 static int lastgroup = -1;
49 static int lastcap = -1;
50 static int lastcolor = -1;
51 static int print_group[MAX_LAYER];
52 static int print_layer[MAX_LAYER];
53 static double fade_ratio = 0.4;
54 static double antifade_ratio = 0.6;
55 static int multi_file = 0;
56 static double media_width, media_height, ps_width, ps_height;
58 static const char *medias[] = {
59 "A0", "A1", "A2", "A3", "A4", "A5",
60 "A6", "A7", "A8", "A9", "A10",
61 "B0", "B1", "B2", "B3", "B4", "B5",
62 "B6", "B7", "B8", "B9", "B10",
63 "Letter", "11x17", "Ledger",
64 "Legal", "Executive",
65 "A-Size", "B-size",
66 "C-Size", "D-size", "E-size",
67 "US-Business_Card", "Intl-Business_Card",
71 typedef struct
73 char *name;
74 long int Width, Height;
75 long int MarginX, MarginY;
76 } MediaType, *MediaTypePtr;
79 * Metric ISO sizes in mm. See http://en.wikipedia.org/wiki/ISO_paper_sizes
81 * A0 841 x 1189
82 * A1 594 x 841
83 * A2 420 x 594
84 * A3 297 x 420
85 * A4 210 x 297
86 * A5 148 x 210
87 * A6 105 x 148
88 * A7 74 x 105
89 * A8 52 x 74
90 * A9 37 x 52
91 * A10 26 x 37
93 * B0 1000 x 1414
94 * B1 707 x 1000
95 * B2 500 x 707
96 * B3 353 x 500
97 * B4 250 x 353
98 * B5 176 x 250
99 * B6 125 x 176
100 * B7 88 x 125
101 * B8 62 x 88
102 * B9 44 x 62
103 * B10 31 x 44
105 * awk '{printf(" {\"%s\", %d, %d, MARGINX, MARGINY},\n", $2, $3*100000/25.4, $5*100000/25.4)}'
107 * See http://en.wikipedia.org/wiki/Paper_size#Loose_sizes for some of the other sizes. The
108 * {A,B,C,D,E}-Size here are the ANSI sizes and not the architectural sizes.
111 #define MARGINX 50000
112 #define MARGINY 50000
114 static MediaType media_data[] = {
115 {"A0", 3311023, 4681102, MARGINX, MARGINY},
116 {"A1", 2338582, 3311023, MARGINX, MARGINY},
117 {"A2", 1653543, 2338582, MARGINX, MARGINY},
118 {"A3", 1169291, 1653543, MARGINX, MARGINY},
119 {"A4", 826771, 1169291, MARGINX, MARGINY},
120 {"A5", 582677, 826771, MARGINX, MARGINY},
121 {"A6", 413385, 582677, MARGINX, MARGINY},
122 {"A7", 291338, 413385, MARGINX, MARGINY},
123 {"A8", 204724, 291338, MARGINX, MARGINY},
124 {"A9", 145669, 204724, MARGINX, MARGINY},
125 {"A10", 102362, 145669, MARGINX, MARGINY},
126 {"B0", 3937007, 5566929, MARGINX, MARGINY},
127 {"B1", 2783464, 3937007, MARGINX, MARGINY},
128 {"B2", 1968503, 2783464, MARGINX, MARGINY},
129 {"B3", 1389763, 1968503, MARGINX, MARGINY},
130 {"B4", 984251, 1389763, MARGINX, MARGINY},
131 {"B5", 692913, 984251, MARGINX, MARGINY},
132 {"B6", 492125, 692913, MARGINX, MARGINY},
133 {"B7", 346456, 492125, MARGINX, MARGINY},
134 {"B8", 244094, 346456, MARGINX, MARGINY},
135 {"B9", 173228, 244094, MARGINX, MARGINY},
136 {"B10", 122047, 173228, MARGINX, MARGINY},
137 {"Letter", 850000, 1100000, MARGINX, MARGINY},
138 {"11x17", 1100000, 1700000, MARGINX, MARGINY},
139 {"Ledger", 1700000, 1100000, MARGINX, MARGINY},
140 {"Legal", 850000, 1400000, MARGINX, MARGINY},
141 {"Executive", 750000, 1000000, MARGINX, MARGINY},
142 {"A-size", 850000, 1100000, MARGINX, MARGINY},
143 {"B-size", 1100000, 1700000, MARGINX, MARGINY},
144 {"C-size", 1700000, 2200000, MARGINX, MARGINY},
145 {"D-size", 2200000, 3400000, MARGINX, MARGINY},
146 {"E-size", 3400000, 4400000, MARGINX, MARGINY},
147 {"US-Business_Card", 350000, 200000, 0, 0},
148 {"Intl-Business_Card", 337500, 212500, 0, 0}
151 #undef MARGINX
152 #undef MARGINY
154 HID_Attribute ps_attribute_list[] = {
155 /* other HIDs expect this to be first. */
156 {"psfile", "Postscript output file",
157 HID_String, 0, 0, {0, 0, 0}, 0, 0},
158 #define HA_psfile 0
159 {"drill-helper", "Prints a centering target in large drill holes",
160 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
161 #define HA_drillhelper 1
162 {"align-marks", "Prints alignment marks on each layer",
163 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0},
164 #define HA_alignmarks 2
165 {"outline", "Prints outline on each layer",
166 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0},
167 #define HA_outline 3
168 {"mirror", "Prints mirror image of each layer",
169 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
170 #define HA_mirror 4
171 {"fill-page", "Scale board to fill page",
172 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
173 #define HA_fillpage 5
174 {"auto-mirror", "Prints mirror image of appropriate layers",
175 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0},
176 #define HA_automirror 6
177 {"ps-color", "Prints in color",
178 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
179 #define HA_color 7
180 {"ps-bloat", "Amount to add to trace/pad/pin edges (1 = 1/100 mil)",
181 HID_Integer, -10000, 10000, {0, 0, 0}, 0, 0},
182 #define HA_psbloat 8
183 {"ps-invert", "Draw images as white-on-black",
184 HID_Boolean, 0, 0, {0, 0, 0}, 0, 0},
185 #define HA_psinvert 9
186 {"media", "media type",
187 HID_Enum, 0, 0, {22, 0, 0}, medias, 0},
188 #define HA_media 10
189 {"psfade", "Fade amount for assembly drawings (0.0=missing, 1.0=solid)",
190 HID_Real, 0, 1, {0, 0, 0.40}, 0, 0},
191 #define HA_psfade 11
192 {"scale", "Scale value to compensate for printer sizing errors (1.0 = full scale)",
193 HID_Real, 0.01, 4, {0, 0, 1.00}, 0, 0},
194 #define HA_scale 12
195 {"multi-file", "Produce multiple files, one per page, instead of a single file.",
196 HID_Boolean, 0, 0, {0, 0, 0.40}, 0, 0},
197 #define HA_multifile 13
198 {"xcalib", "X-Axis calibration (paper width).",
199 HID_Real, 0, 0, {0, 0, 1.0}, 0, 0},
200 #define HA_xcalib 14
201 {"ycalib", "Y-Axis calibration (paper height).",
202 HID_Real, 0, 0, {0, 0, 1.0}, 0, 0},
203 #define HA_ycalib 15
204 {"drill-copper", "Draw drill holes in pins / vias, instead of leaving solid copper.",
205 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0},
206 #define HA_drillcopper 16
207 {"show-legend", "Print file name and scale on printout",
208 HID_Boolean, 0, 0, {1, 0, 0}, 0, 0},
209 #define HA_legend 17
212 #define NUM_OPTIONS (sizeof(ps_attribute_list)/sizeof(ps_attribute_list[0]))
214 REGISTER_ATTRIBUTES (ps_attribute_list)
216 static HID_Attr_Val ps_values[NUM_OPTIONS];
218 static HID_Attribute *
219 ps_get_export_options (int *n)
221 static char *last_made_filename = 0;
222 if (PCB)
223 derive_default_filename(PCB->Filename, &ps_attribute_list[HA_psfile], ".ps", &last_made_filename);
225 if (n)
226 *n = NUM_OPTIONS;
227 return ps_attribute_list;
230 static int
231 group_for_layer (int l)
233 if (l < max_layer + 2 && l >= 0)
234 return GetLayerGroupNumberByNumber (l);
235 /* else something unique */
236 return max_layer + 3 + l;
239 static int
240 layer_sort (const void *va, const void *vb)
242 int a = *(int *) va;
243 int b = *(int *) vb;
244 int d = group_for_layer (b) - group_for_layer (a);
245 if (d)
246 return d;
247 return b - a;
250 static char *filename;
251 static int drill_helper;
252 static int align_marks;
253 static int outline;
254 static int mirror;
255 static int fillpage;
256 static int automirror;
257 static int incolor;
258 static int doing_toc;
259 static int bloat;
260 static int invert;
261 static int media;
262 static int drillcopper;
263 static int legend;
265 static LayerTypePtr outline_layer;
267 static double fill_zoom;
268 static double scale_value;
270 void
271 ps_start_file (FILE *f)
273 fprintf (f, "%%!PS-Adobe-3.0\n\n");
276 static FILE *
277 psopen (const char *base, const char *which)
279 FILE *f;
280 char *buf, *suff, *buf2;
282 if (!multi_file)
283 return fopen (base, "w");
285 buf = malloc (strlen (base) + strlen (which) + 5);
287 suff = strrchr (base, '.');
288 if (suff)
290 strcpy (buf, base);
291 buf2 = strrchr (buf, '.');
292 sprintf(buf2, ".%s.%s", which, suff+1);
294 else
296 sprintf(buf, "%s.%s.ps", base, which);
298 printf("PS: open %s\n", buf);
299 f = fopen(buf, "w");
300 free (buf);
301 return f;
304 static BoxType region;
306 /* This is used by other HIDs that use a postscript format, like lpr
307 or eps. */
308 void
309 ps_hid_export_to_file (FILE * the_file, HID_Attr_Val * options)
311 int i;
312 static int saved_layer_stack[MAX_LAYER];
313 FlagType save_thindraw;
315 save_thindraw = PCB->Flags;
316 CLEAR_FLAG(THINDRAWFLAG, PCB);
317 CLEAR_FLAG(THINDRAWPOLYFLAG, PCB);
319 f = the_file;
320 drill_helper = options[HA_drillhelper].int_value;
321 align_marks = options[HA_alignmarks].int_value;
322 outline = options[HA_outline].int_value;
323 mirror = options[HA_mirror].int_value;
324 fillpage = options[HA_fillpage].int_value;
325 automirror = options[HA_automirror].int_value;
326 incolor = options[HA_color].int_value;
327 bloat = options[HA_psbloat].int_value;
328 invert = options[HA_psinvert].int_value;
329 fade_ratio = options[HA_psfade].real_value;
330 media = options[HA_media].int_value;
331 media_width = media_data[media].Width / 1e5;
332 media_height = media_data[media].Height / 1e5;
333 ps_width = media_width - 2.0*media_data[media].MarginX / 1e5;
334 ps_height = media_height - 2.0*media_data[media].MarginY / 1e5;
335 scale_value = options[HA_scale].real_value;
336 calibration_x = options[HA_xcalib].real_value;
337 calibration_y = options[HA_ycalib].real_value;
338 drillcopper = options[HA_drillcopper].int_value;
339 legend = options[HA_legend].int_value;
341 if (fade_ratio < 0)
342 fade_ratio = 0;
343 if (fade_ratio > 1)
344 fade_ratio = 1;
345 antifade_ratio = 1.0 - fade_ratio;
347 if (fillpage)
349 double zx, zy;
350 if (PCB->MaxWidth > PCB->MaxHeight)
352 zx = ps_height / PCB->MaxWidth;
353 zy = ps_width / PCB->MaxHeight;
355 else
357 zx = ps_height / PCB->MaxHeight;
358 zy = ps_width / PCB->MaxWidth;
360 if (zx < zy)
361 fill_zoom = zx;
362 else
363 fill_zoom = zy;
365 else
366 fill_zoom = 0.00001;
369 memset (print_group, 0, sizeof (print_group));
370 memset (print_layer, 0, sizeof (print_layer));
372 outline_layer = NULL;
374 for (i = 0; i < max_layer; i++)
376 LayerType *layer = PCB->Data->Layer + i;
377 if (layer->LineN || layer->TextN || layer->ArcN || layer->PolygonN)
378 print_group[GetLayerGroupNumberByNumber (i)] = 1;
380 if (strcmp (layer->Name, "outline") == 0
381 || strcmp (layer->Name, "route") == 0)
383 printf("see outline layer\n");
384 outline_layer = layer;
387 print_group[GetLayerGroupNumberByNumber (max_layer)] = 1;
388 print_group[GetLayerGroupNumberByNumber (max_layer + 1)] = 1;
389 for (i = 0; i < max_layer; i++)
390 if (print_group[GetLayerGroupNumberByNumber (i)])
391 print_layer[i] = 1;
393 memcpy (saved_layer_stack, LayerStack, sizeof (LayerStack));
394 qsort (LayerStack, max_layer, sizeof (LayerStack[0]), layer_sort);
396 lastgroup = -1;
397 linewidth = -1;
398 lastcap = -1;
399 lastcolor = -1;
401 region.X1 = 0;
402 region.Y1 = 0;
403 region.X2 = PCB->MaxWidth;
404 region.Y2 = PCB->MaxHeight;
406 if (! multi_file)
408 pagecount = 1;
409 fprintf (f, "%%%%Page: 1\n");
410 fprintf (f, "/Times-Roman findfont 24 scalefont setfont\n");
411 fprintf (f,
412 "/rightshow { /s exch def s stringwidth pop -1 mul 0 rmoveto s show } def\n");
413 fprintf (f,
414 "/y 72 9 mul def /toc { 100 y moveto show /y y 24 sub def } bind def\n");
415 fprintf (f, "/tocp { /y y 12 sub def 90 y moveto rightshow } bind def\n");
416 doing_toc = 1;
417 hid_expose_callback (&ps_hid, &region, 0);
420 pagecount = 1;
421 doing_toc = 0;
422 lastgroup = -1;
423 hid_expose_callback (&ps_hid, &region, 0);
425 if (f)
426 fprintf (f, "showpage\n");
428 memcpy (LayerStack, saved_layer_stack, sizeof (LayerStack));
429 PCB->Flags = save_thindraw;
432 static void
433 ps_do_export (HID_Attr_Val * options)
435 int save_ons[MAX_LAYER + 2];
436 int i;
438 if (!options)
440 ps_get_export_options (0);
441 for (i = 0; i < NUM_OPTIONS; i++)
442 ps_values[i] = ps_attribute_list[i].default_val;
443 options = ps_values;
446 filename = options[HA_psfile].str_value;
447 if (!filename)
448 filename = "pcb-out.ps";
450 multi_file = options[HA_multifile].int_value;
452 if (multi_file)
453 f = 0;
454 else
456 f = psopen (filename, "toc");
457 if (!f)
459 perror (filename);
460 return;
462 ps_start_file (f);
465 hid_save_and_show_layer_ons (save_ons);
466 ps_hid_export_to_file (f, options);
467 hid_restore_layer_ons (save_ons);
469 multi_file = 0;
470 if (f)
471 fclose (f);
474 extern void hid_parse_command_line (int *argc, char ***argv);
476 static void
477 ps_parse_arguments (int *argc, char ***argv)
479 hid_register_attributes (ps_attribute_list,
480 sizeof (ps_attribute_list) /
481 sizeof (ps_attribute_list[0]));
482 hid_parse_command_line (argc, argv);
485 static void
486 corner (int x, int y, int dx, int dy)
488 #if 0
489 int len = (PCB->MaxWidth + PCB->MaxHeight) / 10;
490 int len2 = (PCB->MaxWidth + PCB->MaxHeight) / 50;
491 #else
492 int len = 200000;
493 int len2 = 20000;
494 #endif
495 int thick = 0;
497 fprintf (f, "gsave %d setlinewidth %d %d translate %d %d scale\n",
498 thick * 2, x, y, dx, dy);
499 fprintf (f, "%d %d moveto %d %d %d 0 90 arc %d %d lineto\n",
500 len, thick, thick, thick, len2 + thick, thick, len);
501 if (dx < 0 && dy < 0)
502 fprintf (f, "%d %d moveto 0 %d rlineto\n",
503 len2 * 2 + thick, thick, -len2);
504 fprintf (f, "stroke grestore\n");
507 static int is_mask;
508 static int is_drill;
509 static int is_assy;
510 static int is_copper;
511 static int is_paste;
513 static int
514 ps_set_layer (const char *name, int group, int empty)
516 int idx = (group >= 0
517 && group <
518 max_layer) ? PCB->LayerGroups.Entries[group][0] : group;
519 if (name == 0)
520 name = PCB->Data->Layer[idx].Name;
522 if (empty)
523 return 0;
525 if (idx >= 0 && idx < max_layer && !print_layer[idx])
526 return 0;
528 if (strcmp (name, "invisible") == 0)
529 return 0;
531 is_drill = (SL_TYPE (idx) == SL_PDRILL || SL_TYPE (idx) == SL_UDRILL);
532 is_mask = (SL_TYPE (idx) == SL_MASK);
533 is_assy = (SL_TYPE (idx) == SL_ASSY);
534 is_copper = (SL_TYPE (idx) == 0);
535 is_paste = (SL_TYPE (idx) == SL_PASTE);
536 #if 0
537 printf ("Layer %s group %d drill %d mask %d\n", name, group, is_drill,
538 is_mask);
539 #endif
541 if (doing_toc)
543 if (group < 0 || group != lastgroup)
545 pagecount++;
546 lastgroup = group;
547 fprintf (f, "(%d.) tocp\n", pagecount);
549 fprintf (f, "(%s) toc\n", name);
550 return 0;
553 if (group < 0 || group != lastgroup)
555 double boffset;
556 int mirror_this = 0;
557 lastgroup = group;
559 if (f && pagecount)
561 fprintf (f, "showpage\n");
563 pagecount++;
564 if (multi_file)
566 if (f)
567 fclose (f);
568 f = psopen (filename, layer_type_to_file_name (idx));
569 if (!f)
571 perror(filename);
572 return 0;
575 ps_start_file (f);
577 fprintf (f, "%%%%Page: %d\n", pagecount);
579 if (mirror)
580 mirror_this = 1 - mirror_this;
581 if (automirror
583 ((idx >= 0 && group == GetLayerGroupNumberByNumber (max_layer))
584 || (idx < 0 && SL_SIDE (idx) == SL_BOTTOM_SIDE)))
585 mirror_this = 1 - mirror_this;
587 fprintf (f, "/Helvetica findfont 10 scalefont setfont\n");
588 if (legend)
590 fprintf (f, "30 30 moveto (%s) show\n", PCB->Filename);
591 if (PCB->Name)
592 fprintf (f, "30 41 moveto (%s, %s) show\n",
593 PCB->Name, layer_type_to_file_name (idx));
594 else
595 fprintf (f, "30 41 moveto (%s) show\n",
596 layer_type_to_file_name (idx));
597 if (mirror_this)
598 fprintf (f, "( \\(mirrored\\)) show\n");
600 if (fillpage)
601 fprintf (f, "(, not to scale) show\n");
602 else
603 fprintf (f, "(, scale = 1:%.3f) show\n", scale_value);
605 fprintf (f, "newpath\n");
607 fprintf (f, "72 72 scale %g %g translate\n", 0.5*media_width, 0.5*media_height);
609 boffset = 0.5*media_height;
610 if (PCB->MaxWidth > PCB->MaxHeight)
612 fprintf (f, "90 rotate\n");
613 boffset = 0.5*media_width;
614 fprintf (f, "%g %g scale %% calibration\n", calibration_y, calibration_x);
616 else
617 fprintf (f, "%g %g scale %% calibration\n", calibration_x, calibration_y);
619 if (mirror_this)
620 fprintf (f, "1 -1 scale\n");
622 if (SL_TYPE (idx) == SL_FAB)
623 fprintf (f, "0.00001 dup neg scale\n");
624 else
625 fprintf (f, "%g dup neg scale\n", (fill_zoom * scale_value));
626 fprintf (f, "%d %d translate\n",
627 -PCB->MaxWidth / 2, -PCB->MaxHeight / 2);
629 /* Keep the drill list from falling off the left edge of the paper,
630 * even if it means some of the board falls off the right edge.
631 * If users don't want to make smaller boards, or use fewer drill
632 * sizes, they can always ignore this sheet. */
633 if (SL_TYPE (idx) == SL_FAB) {
634 int natural = (int) ((boffset - 0.5) * 100000) - PCB->MaxHeight / 2;
635 int needed = PrintFab_overhang();
636 fprintf (f, "%% PrintFab overhang natural %d, needed %d\n", natural, needed);
637 if (needed > natural)
638 fprintf (f, "0 %d translate\n", needed - natural);
641 if (invert)
643 fprintf (f, "/gray { 1 exch sub setgray } bind def\n");
644 fprintf (f,
645 "/rgb { 1 1 3 { pop 1 exch sub 3 1 roll } for setrgbcolor } bind def\n");
647 else
649 fprintf (f, "/gray { setgray } bind def\n");
650 fprintf (f, "/rgb { setrgbcolor } bind def\n");
653 if ((outline && !outline_layer) || invert)
655 fprintf (f,
656 "0 setgray 0 setlinewidth 0 0 moveto 0 %d lineto %d %d lineto %d 0 lineto closepath %s\n",
657 PCB->MaxHeight, PCB->MaxWidth, PCB->MaxHeight, PCB->MaxWidth,
658 invert ? "fill" : "stroke");
661 if (align_marks)
663 corner (0, 0, -1, -1);
664 corner (PCB->MaxWidth, 0, 1, -1);
665 corner (PCB->MaxWidth, PCB->MaxHeight, 1, 1);
666 corner (0, PCB->MaxHeight, -1, 1);
669 linewidth = -1;
670 lastcap = -1;
671 lastcolor = -1;
673 fprintf (f, "/ts 10000 def\n");
674 fprintf (f,
675 "/ty ts neg def /tx 0 def /Helvetica findfont ts scalefont setfont\n");
676 fprintf (f, "/t { moveto lineto stroke } bind def\n");
677 fprintf (f,
678 "/r { /y2 exch def /x2 exch def /y1 exch def /x1 exch def\n");
679 fprintf (f,
680 " x1 y1 moveto x1 y2 lineto x2 y2 lineto x2 y1 lineto closepath fill } bind def\n");
681 fprintf (f, "/c { 0 360 arc fill } bind def\n");
682 fprintf (f,
683 "/a { gsave setlinewidth translate scale 0 0 1 5 3 roll arc stroke grestore} bind def\n");
684 if (drill_helper)
685 fprintf (f,
686 "/dh { gsave %d setlinewidth 0 gray %d 0 360 arc stroke grestore} bind def\n",
687 MIN_PINORVIAHOLE, MIN_PINORVIAHOLE * 3 / 2);
689 #if 0
690 /* Try to outsmart ps2pdf's heuristics for page rotation, by putting
691 * text on all pages -- even if that text is blank */
692 if (SL_TYPE (idx) != SL_FAB)
693 fprintf (f,
694 "gsave tx ty translate 1 -1 scale 0 0 moveto (Layer %s) show grestore newpath /ty ty ts sub def\n",
695 name);
696 else
697 fprintf (f, "gsave tx ty translate 1 -1 scale 0 0 moveto ( ) show grestore newpath /ty ty ts sub def\n");
698 #endif
700 /* If we're printing a copper layer other than the outline layer,
701 and we want to "print outlines", and we have an outline layer,
702 print the outline layer on this layer also. */
703 if (outline
704 && outline_layer
705 && outline_layer != PCB->Data->Layer+idx
706 && SL_TYPE (idx) == 0 /* copper */
707 && strcmp (name, "outline")
708 && strcmp (name, "route"))
710 printf("attempting to draw outlines on %s\n", name);
711 DrawLayer (outline_layer, &region);
714 return 1;
717 static hidGC
718 ps_make_gc (void)
720 hidGC rv = (hidGC) calloc (1, sizeof (hid_gc_struct));
721 rv->me_pointer = &ps_hid;
722 rv->cap = Trace_Cap;
723 return rv;
726 static void
727 ps_destroy_gc (hidGC gc)
729 free (gc);
732 static void
733 ps_use_mask (int use_it)
735 /* does nothing */
738 static void
739 ps_set_color (hidGC gc, const char *name)
741 if (strcmp (name, "erase") == 0 || strcmp (name, "drill") == 0)
743 gc->r = gc->g = gc->b = 255;
744 gc->erase = 1;
746 else if (incolor)
748 int r, g, b;
749 sscanf (name + 1, "%02x%02x%02x", &r, &g, &b);
750 gc->r = r;
751 gc->g = g;
752 gc->b = b;
753 gc->erase = 0;
755 else
757 gc->r = gc->g = gc->b = 0;
758 gc->erase = 0;
762 static void
763 ps_set_line_cap (hidGC gc, EndCapStyle style)
765 gc->cap = style;
768 static void
769 ps_set_line_width (hidGC gc, int width)
771 gc->width = width;
774 static void
775 ps_set_draw_xor (hidGC gc, int xor)
780 static void
781 ps_set_draw_faded (hidGC gc, int faded)
783 gc->faded = faded;
786 static void
787 ps_set_line_cap_angle (hidGC gc, int x1, int y1, int x2, int y2)
789 CRASH;
792 static void
793 use_gc (hidGC gc)
795 if (gc->me_pointer != &ps_hid)
797 fprintf (stderr, "Fatal: GC from another HID passed to ps HID\n");
798 abort ();
800 if (linewidth != gc->width)
802 fprintf (f, "%d setlinewidth\n",
803 gc->width + (gc->erase ? -2 : 2) * bloat);
804 linewidth = gc->width;
806 if (lastcap != gc->cap)
808 int c;
809 switch (gc->cap)
811 case Round_Cap:
812 case Trace_Cap:
813 c = 1;
814 break;
815 default:
816 case Square_Cap:
817 c = 2;
818 break;
820 fprintf (f, "%d setlinecap %d setlinejoin\n", c, c);
821 lastcap = gc->cap;
823 #define CBLEND(gc) (((gc->r)<<24)|((gc->g)<<16)|((gc->b)<<8)|(gc->faded))
824 if (lastcolor != CBLEND (gc))
826 if (is_drill || is_mask)
828 fprintf (f, "%d gray\n", gc->erase ? 0 : 1);
829 lastcolor = 0;
831 else
833 double r, g, b;
834 r = gc->r;
835 g = gc->g;
836 b = gc->b;
837 if (gc->faded)
839 r = antifade_ratio * 255 + fade_ratio * r;
840 g = antifade_ratio * 255 + fade_ratio * g;
841 b = antifade_ratio * 255 + fade_ratio * b;
843 if (gc->r == gc->g && gc->g == gc->b)
844 fprintf (f, "%g gray\n", r / 255.0);
845 else
846 fprintf (f, "%g %g %g rgb\n", r / 255.0, g / 255.0, b / 255.0);
847 lastcolor = CBLEND (gc);
852 static void
853 ps_draw_rect (hidGC gc, int x1, int y1, int x2, int y2)
855 use_gc (gc);
856 fprintf (f, "%d %d %d %d r\n", x1, y1, x2, y2);
859 static void ps_fill_rect (hidGC gc, int x1, int y1, int x2, int y2);
860 static void ps_fill_circle (hidGC gc, int cx, int cy, int radius);
862 static void
863 ps_draw_line (hidGC gc, int x1, int y1, int x2, int y2)
865 #if 0
866 /* If you're etching your own paste mask, this will reduce the
867 amount of brass you need to etch by drawing outlines for large
868 pads. See also ps_fill_rect. */
869 if (is_paste && gc->width > 2500 && gc->cap == Square_Cap
870 && (x1 == x2 || y1 == y2))
872 int t, w;
873 if (x1 > x2)
874 { t = x1; x1 = x2; x2 = t; }
875 if (y1 > y2)
876 { t = y1; y1 = y2; y2 = t; }
877 w = gc->width/2;
878 ps_fill_rect (gc, x1-w, y1-w, x2+w, y2+w);
879 return;
881 #endif
882 if (x1 == x2 && y1 == y2)
884 int w = gc->width / 2;
885 if (gc->cap == Square_Cap)
886 ps_fill_rect (gc, x1 - w, y1 - w, x1 + w, y1 + w);
887 else
888 ps_fill_circle (gc, x1, y1, w);
889 return;
891 use_gc (gc);
892 fprintf (f, "%d %d %d %d t\n", x1, y1, x2, y2);
895 static void
896 ps_draw_arc (hidGC gc, int cx, int cy, int width, int height,
897 int start_angle, int delta_angle)
899 int sa, ea;
900 if (delta_angle > 0)
902 sa = start_angle;
903 ea = start_angle + delta_angle;
905 else
907 sa = start_angle + delta_angle;
908 ea = start_angle;
910 #if 0
911 printf ("draw_arc %d,%d %dx%d %d..%d %d..%d\n",
912 cx, cy, width, height, start_angle, delta_angle, sa, ea);
913 #endif
914 use_gc (gc);
915 fprintf (f, "%d %d %d %d %d %d %g a\n",
916 sa, ea,
917 -width, height, cx, cy, (double) (linewidth + 2 * bloat) / width);
920 static void
921 ps_fill_circle (hidGC gc, int cx, int cy, int radius)
923 use_gc (gc);
924 if (!gc->erase || !is_copper || drillcopper)
926 if (gc->erase && is_copper && drill_helper
927 && radius >= PCB->minDrill/4)
928 radius = PCB->minDrill/4;
929 fprintf (f, "%d %d %d c\n", cx, cy, radius + (gc->erase ? -1 : 1) * bloat);
933 static void
934 ps_fill_polygon (hidGC gc, int n_coords, int *x, int *y)
936 int i;
937 char *op = "moveto";
938 use_gc (gc);
939 for (i = 0; i < n_coords; i++)
941 fprintf (f, "%d %d %s\n", x[i], y[i], op);
942 op = "lineto";
944 fprintf (f, "fill\n");
947 static void
948 ps_fill_rect (hidGC gc, int x1, int y1, int x2, int y2)
950 use_gc (gc);
951 if (x1 > x2)
953 int t = x1;
954 x2 = x2;
955 x2 = t;
957 if (y1 > y2)
959 int t = y1;
960 y2 = y2;
961 y2 = t;
963 #if 0
964 /* See comment in ps_draw_line. */
965 if (is_paste && (x2-x1)>2500 && (y2-y1)>2500)
967 linewidth = 1000;
968 lastcap = Round_Cap;
969 fprintf(f, "1000 setlinewidth 1 setlinecap 1 setlinejoin\n");
970 fprintf(f, "%d %d moveto %d %d lineto %d %d lineto %d %d lineto closepath stroke\n",
971 x1+500-bloat, y1+500-bloat,
972 x1+500-bloat, y2-500+bloat,
973 x2-500+bloat, y2-500+bloat,
974 x2-500+bloat, y1+500-bloat);
975 return;
977 #endif
978 fprintf (f, "%d %d %d %d r\n", x1-bloat, y1-bloat, x2+bloat, y2+bloat);
981 HID_Attribute ps_calib_attribute_list[] = {
982 {"lprcommand", "Command to print",
983 HID_String, 0, 0, {0, 0, 0}, 0, 0},
986 static const char * const calib_lines[] = {
987 "%!PS-Adobe\n",
988 "\n",
989 "72 72 scale\n",
990 "\n",
991 "0 setlinewidth\n",
992 "0.375 0.375 moveto\n",
993 "8.125 0.375 lineto\n",
994 "8.125 10.625 lineto\n",
995 "0.375 10.625 lineto\n",
996 "closepath stroke\n",
997 "\n",
998 "0.5 0.5 translate\n",
999 "0.001 setlinewidth\n",
1000 "\n",
1001 "/Times-Roman findfont 0.2 scalefont setfont\n",
1002 "\n",
1003 "/sign {\n",
1004 " 0 lt { -1 } { 1 } ifelse\n",
1005 "} def\n",
1006 "\n",
1007 "/cbar {\n",
1008 " /units exch def\n",
1009 " /x exch def\n",
1010 " /y exch def \n",
1011 "\n",
1012 " /x x sign 0.5 mul def\n",
1013 "\n",
1014 " 0 setlinewidth\n",
1015 " newpath x y 0.25 0 180 arc gsave 0.85 setgray fill grestore closepath stroke\n",
1016 " newpath x 0 0.25 180 360 arc gsave 0.85 setgray fill grestore closepath stroke\n",
1017 " 0.001 setlinewidth\n",
1018 "\n",
1019 " x 0 moveto\n",
1020 " x y lineto\n",
1021 "% -0.07 -0.2 rlineto 0.14 0 rmoveto -0.07 0.2 rlineto\n",
1022 " x y lineto\n",
1023 " -0.1 0 rlineto 0.2 0 rlineto\n",
1024 " stroke\n",
1025 " x 0 moveto\n",
1026 "% -0.07 0.2 rlineto 0.14 0 rmoveto -0.07 -0.2 rlineto\n",
1027 " x 0 moveto\n",
1028 " -0.1 0 rlineto 0.2 0 rlineto\n",
1029 " stroke\n",
1030 "\n",
1031 " x 0.1 add\n",
1032 " y 0.2 sub moveto\n",
1033 " units show\n",
1034 "} bind def\n",
1035 "\n",
1036 "/y 9 def\n",
1037 "/t {\n",
1038 " /str exch def\n",
1039 " 1.5 y moveto str show\n",
1040 " /y y 0.25 sub def\n",
1041 "} bind def\n",
1042 "\n",
1043 "(Please measure ONE of the horizontal lines, in the units indicated for)t\n",
1044 "(that line, and enter that value as X. Similarly, measure ONE of the)t\n",
1045 "(vertical lines and enter that value as Y. Measurements should be)t\n",
1046 "(between the flat faces of the semicircles.)t\n",
1047 "()t\n",
1048 "(The large box is 10.25 by 7.75 inches)t\n",
1049 "\n",
1050 "/in { } bind def\n",
1051 "/cm { 2.54 div } bind def\n",
1052 "/mm { 25.4 div } bind def\n",
1053 "\n",
1057 static int
1058 guess(double val, double close_to, double *calib)
1060 if (val >= close_to * 0.9
1061 && val <= close_to * 1.1)
1063 *calib = close_to / val;
1064 return 0;
1066 return 1;
1069 void
1070 ps_calibrate_1 (double xval, double yval, int use_command)
1072 HID_Attr_Val vals[3];
1073 FILE *f;
1074 int used_popen = 0, c;
1076 if (xval > 0 && yval > 0)
1078 if (guess (xval, 4, &calibration_x))
1079 if (guess (xval, 15, &calibration_x))
1080 if (guess (xval, 7.5, &calibration_x))
1082 if (xval < 2)
1083 ps_attribute_list[HA_xcalib].default_val.real_value =
1084 calibration_x = xval;
1085 else
1086 Message("X value of %g is too far off.\n"
1087 "Expecting it near: 1.0, 4.0, 15.0, 7.5\n", xval);
1089 if (guess (yval, 4, &calibration_y))
1090 if (guess (yval, 20, &calibration_y))
1091 if (guess (yval, 10, &calibration_y))
1093 if (yval < 2)
1094 ps_attribute_list[HA_ycalib].default_val.real_value =
1095 calibration_y = yval;
1096 else
1097 Message("Y value of %g is too far off.\n"
1098 "Expecting it near: 1.0, 4.0, 20.0, 10.0\n", yval);
1100 return;
1103 if (ps_calib_attribute_list[0].default_val.str_value == NULL)
1105 ps_calib_attribute_list[0].default_val.str_value = strdup ("lpr");
1108 if (gui->attribute_dialog (ps_calib_attribute_list, 1, vals, "Print Calibration Page", "Generates a printer calibration page"))
1109 return;
1111 if (use_command || strchr (vals[0].str_value, '|'))
1113 char *cmd = vals[0].str_value;
1114 while (*cmd == ' ' || *cmd == '|')
1115 cmd ++;
1116 f = popen (cmd, "w");
1117 used_popen = 1;
1119 else
1120 f = fopen (vals[0].str_value, "w");
1122 for (c=0; calib_lines[c]; c++)
1123 fputs(calib_lines[c], f);
1125 fprintf (f, "4 in 0.5 (Y in) cbar\n");
1126 fprintf (f, "20 cm 1.5 (Y cm) cbar\n");
1127 fprintf (f, "10 in 2.5 (Y in) cbar\n");
1128 fprintf (f, "-90 rotate\n");
1129 fprintf (f, "4 in -0.5 (X in) cbar\n");
1130 fprintf (f, "15 cm -1.5 (X cm) cbar\n");
1131 fprintf (f, "7.5 in -2.5 (X in) cbar\n");
1133 fprintf (f, "showpage\n");
1135 if (used_popen)
1136 pclose (f);
1137 else
1138 fclose (f);
1141 static void
1142 ps_calibrate (double xval, double yval)
1144 ps_calibrate_1 (xval, yval, 0);
1147 static void
1148 ps_set_crosshair (int x, int y, int action)
1152 HID ps_hid = {
1153 sizeof (HID),
1154 "ps",
1155 "Postscript export.",
1156 0, 0, 1, 1, 0, 0,
1157 ps_get_export_options,
1158 ps_do_export,
1159 ps_parse_arguments,
1160 0 /* ps_invalidate_wh */ ,
1161 0 /* ps_invalidate_lr */ ,
1162 0 /* ps_invalidate_all */ ,
1163 ps_set_layer,
1164 ps_make_gc,
1165 ps_destroy_gc,
1166 ps_use_mask,
1167 ps_set_color,
1168 ps_set_line_cap,
1169 ps_set_line_width,
1170 ps_set_draw_xor,
1171 ps_set_draw_faded,
1172 ps_set_line_cap_angle,
1173 ps_draw_line,
1174 ps_draw_arc,
1175 ps_draw_rect,
1176 ps_fill_circle,
1177 ps_fill_polygon,
1178 common_fill_pcb_polygon,
1179 0 /* ps_thindraw_pcb_polygon */,
1180 ps_fill_rect,
1181 ps_calibrate,
1182 0 /* ps_shift_is_pressed */ ,
1183 0 /* ps_control_is_pressed */ ,
1184 0 /* ps_get_coords */ ,
1185 ps_set_crosshair,
1186 0 /* ps_add_timer */ ,
1187 0 /* ps_stop_timer */ ,
1188 0 /* ps_watch_file */ ,
1189 0 /* ps_unwatch_file */ ,
1190 0 /* ps_add_block_hook */ ,
1191 0 /* ps_stop_block_hook */ ,
1192 0 /* ps_log */ ,
1193 0 /* ps_logv */ ,
1194 0 /* ps_confirm_dialog */ ,
1195 0 /* ps_close_confirm_dialog */ ,
1196 0 /* ps_report_dialog */ ,
1197 0 /* ps_prompt_for */ ,
1198 0 /* ps_fileselect */ ,
1199 0 /* ps_attribute_dialog */ ,
1200 0 /* ps_show_item */ ,
1201 0 /* ps_beep */ ,
1202 0 /* ps_progress */
1205 #include "dolists.h"
1207 void
1208 hid_ps_init ()
1210 apply_default_hid (&ps_hid, 0);
1211 hid_register_hid (&ps_hid);
1213 hid_eps_init ();
1214 #include "ps_lists.h"