Root/
Source at commit d76f7d19a894bcf90fe5118c8573549ebf9d56d0 created 11 years 5 months ago. By Xiangfu, debian: cleanup changelog, include debian build flags | |
---|---|
1 | /* |
2 | * postscript.c - Dump objects in Postscript |
3 | * |
4 | * Written 2009-2012 by Werner Almesberger |
5 | * Copyright 2009-2012 by Werner Almesberger |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; either version 2 of the License, or |
10 | * (at your option) any later version. |
11 | */ |
12 | |
13 | |
14 | #include <stdlib.h> |
15 | #include <stdio.h> |
16 | #include <string.h> |
17 | #include <ctype.h> |
18 | #include <errno.h> |
19 | |
20 | #include "util.h" |
21 | #include "coord.h" |
22 | #include "layer.h" |
23 | #include "obj.h" |
24 | #include "inst.h" |
25 | #include "unparse.h" |
26 | #include "gui_status.h" |
27 | #include "gui_inst.h" |
28 | #include "postscript.h" |
29 | |
30 | |
31 | /* |
32 | * A4 is 210 mm x 297 mm |
33 | * US Letter is 216 mm x 279 mm |
34 | * |
35 | * We pick the smallest dimensions minus a bit of slack and center on the |
36 | * printer page. |
37 | */ |
38 | |
39 | #define PAGE_HALF_WIDTH mm_to_units(210/2.0-10) /* A4 */ |
40 | #define PAGE_HALF_HEIGHT mm_to_units(279/2.0-15) /* US Letter */ |
41 | |
42 | /* |
43 | * Page layout: |
44 | * |
45 | * HEADER DATE |
46 | * --------------------------- HEADER_HEIGHT+DIVIDER_BORDER below top |
47 | * | |
48 | * | 2x |
49 | * 10 x |<------------- roughly at 10/12 |
50 | * | 1x |
51 | * | |
52 | * --------------------------- 50% height |
53 | * Frames in boxes |
54 | * |
55 | */ |
56 | |
57 | |
58 | #define PS_HEADER_HEIGHT mm_to_units(8) |
59 | #define PS_DIVIDER_BORDER mm_to_units(2) |
60 | #define PS_DIVIDER_WIDTH mm_to_units(0.5) |
61 | |
62 | #define PS_MISC_TEXT_HEIGHT mm_to_units(3) |
63 | |
64 | #define PS_DOT_DIST mm_to_units(0.03) |
65 | #define PS_DOT_DIAM mm_to_units(0.01) |
66 | |
67 | #define PS_HATCH mm_to_units(0.1) |
68 | #define PS_HATCH_LINE mm_to_units(0.015) |
69 | |
70 | #define PS_STRIPE mm_to_units(0.08) |
71 | |
72 | #define PS_RIM_LINE mm_to_units(0.02) |
73 | |
74 | #define PS_FONT_OUTLINE mm_to_units(0.025) |
75 | |
76 | #define PS_VEC_LINE mm_to_units(0.02) |
77 | #define PS_VEC_ARROW_LEN mm_to_units(0.3) |
78 | #define PS_VEC_ARROW_ANGLE 20 |
79 | #define PS_VEC_TEXT_HEIGHT mm_to_units(3) /* ~8.5 pt, real mm */ |
80 | #define PS_VEC_BASE_OFFSET mm_to_units(0.5) /* real mm */ |
81 | |
82 | #define PS_MEAS_LINE mm_to_units(0.1) /* real mm */ |
83 | #define PS_MEAS_ARROW_LEN mm_to_units(0.15) |
84 | #define PS_MEAS_ARROW_ANGLE 30 |
85 | #define PS_MEAS_TEXT_HEIGHT mm_to_units(3) /* ~8.5 pt, real mm */ |
86 | #define PS_MEAS_BASE_OFFSET mm_to_units(0.5) /* real mm */ |
87 | #define PS_MEAS_MIN_HEIGHT (PS_MEAS_TEXT_HEIGHT/2) |
88 | |
89 | #define PS_CROSS_WIDTH mm_to_units(0.01) |
90 | #define PS_CROSS_DASH mm_to_units(0.1) |
91 | |
92 | #define PS_KEY_X_GAP mm_to_units(8) |
93 | #define PS_KEY_Y_GAP mm_to_units(4) |
94 | #define PS_KEY_HEIGTH mm_to_units(8) |
95 | |
96 | #define TEXT_HEIGHT_FACTOR 1.5 /* height/width of typical text */ |
97 | |
98 | |
99 | struct postscript_params postscript_params = { |
100 | .zoom = 0, |
101 | .max_width = 0, |
102 | .max_height = 0, |
103 | .show_pad_names = 1, |
104 | .show_stuff = 0, |
105 | .label_vecs = 0, |
106 | .show_meas = 1, |
107 | .show_key = 0, |
108 | }; |
109 | |
110 | static const struct postscript_params minimal_params; |
111 | static struct postscript_params active_params; |
112 | static int pad_type_seen[pt_n]; |
113 | |
114 | |
115 | /* ----- Boxes ------------------------------------------------------------- */ |
116 | |
117 | |
118 | static struct box { |
119 | unit_type x, y; /* width and height */ |
120 | unit_type x0, y0; /* lower left corner */ |
121 | struct box *next; |
122 | } *boxes = NULL; |
123 | |
124 | |
125 | static void add_box(unit_type xa, unit_type ya, unit_type xb, unit_type yb) |
126 | { |
127 | struct box *box; |
128 | |
129 | box = alloc_type(struct box); |
130 | box->x = xb-xa; |
131 | box->y = yb-ya; |
132 | box->x0 = xa; |
133 | box->y0 = ya; |
134 | box->next = boxes; |
135 | boxes = box; |
136 | } |
137 | |
138 | |
139 | static void free_boxes(void) |
140 | { |
141 | struct box *next; |
142 | |
143 | while (boxes) { |
144 | next = boxes->next; |
145 | free(boxes); |
146 | boxes = next; |
147 | } |
148 | } |
149 | |
150 | |
151 | static int get_box(unit_type x, unit_type y, unit_type *xa, unit_type *ya) |
152 | { |
153 | struct box **box, **best = NULL; |
154 | struct box *b; |
155 | double size, best_size; |
156 | |
157 | for (box = &boxes; *box; box = &(*box)->next) { |
158 | if ((*box)->x < x || (*box)->y < y) |
159 | continue; |
160 | size = (double) (*box)->x*(*box)->y; |
161 | if (!best || size < best_size) { |
162 | best = box; |
163 | best_size = size; |
164 | } |
165 | } |
166 | if (!best) |
167 | return 0; |
168 | b = *best; |
169 | if (xa) |
170 | *xa = b->x0; |
171 | if (ya) |
172 | *ya = b->y0+b->y-y; |
173 | |
174 | *best = b->next; |
175 | add_box(b->x0+x, b->y0, b->x0+b->x, b->y0+b->y); |
176 | add_box(b->x0, b->y0, b->x0+x, b->y0+b->y-y); |
177 | free(b); |
178 | |
179 | return 1; |
180 | } |
181 | |
182 | |
183 | /* ----- Helper functions -------------------------------------------------- */ |
184 | |
185 | |
186 | static void ps_string(FILE *file, const char *s) |
187 | { |
188 | fputc('(', file); |
189 | while (*s) { |
190 | if (*s == '(' || *s == ')' || *s == '\\') |
191 | fputc('\\', file); |
192 | fputc(*s, file); |
193 | s++; |
194 | } |
195 | fputc(')', file); |
196 | } |
197 | |
198 | |
199 | static void ps_filled_box(FILE *file, struct coord a, struct coord b, |
200 | const char *pattern) |
201 | { |
202 | fprintf(file, "0 setgray %d setlinewidth\n", PS_HATCH_LINE); |
203 | fprintf(file, " %d %d moveto\n", a.x, a.y); |
204 | fprintf(file, " %d %d lineto\n", b.x, a.y); |
205 | fprintf(file, " %d %d lineto\n", b.x, b.y); |
206 | fprintf(file, " %d %d lineto\n", a.x, b.y); |
207 | fprintf(file, " closepath gsave %s grestore stroke\n", pattern); |
208 | } |
209 | |
210 | |
211 | static void ps_outlined_text_in_rect(FILE *file, const char *s, |
212 | struct coord a, struct coord b) |
213 | { |
214 | const char *t; |
215 | unit_type h, w; |
216 | |
217 | for (t = s; *t == ' '; t++); |
218 | if (!*t) |
219 | return; |
220 | h = a.y-b.y; |
221 | w = a.x-b.x; |
222 | if (h < 0) |
223 | h = -h; |
224 | if (w < 0) |
225 | w = -w; |
226 | fprintf(file, "0 setgray /Helvetica-Bold findfont dup\n"); |
227 | fprintf(file, " "); |
228 | ps_string(file, s); |
229 | fprintf(file, " %d %d\n", w/2, h/2); |
230 | fprintf(file, " boxfont\n"); |
231 | fprintf(file, " %d %d moveto\n", (a.x+b.x)/2, (a.y+b.y)/2); |
232 | fprintf(file, " "); |
233 | ps_string(file, s); |
234 | fprintf(file, " center %d showoutlined newpath\n", PS_FONT_OUTLINE); |
235 | } |
236 | |
237 | |
238 | /* ----- Items ------------------------------------------------------------- */ |
239 | |
240 | |
241 | static void ps_pad_name(FILE *file, const struct inst *inst) |
242 | { |
243 | ps_outlined_text_in_rect(file, inst->u.pad.name, |
244 | inst->base, inst->u.pad.other); |
245 | } |
246 | |
247 | |
248 | static const char *hatch(enum pad_type type) |
249 | { |
250 | switch (type) { |
251 | case pt_normal: |
252 | return "crosspath"; |
253 | case pt_bare: |
254 | return "hatchpath"; |
255 | case pt_paste: |
256 | return "backhatchpath"; |
257 | case pt_mask: |
258 | return "dotpath"; |
259 | case pt_trace: |
260 | return "horpath"; |
261 | default: |
262 | abort(); |
263 | } |
264 | } |
265 | |
266 | |
267 | static void ps_pad(FILE *file, const struct inst *inst, int show_name) |
268 | { |
269 | enum pad_type type = layers_to_pad_type(inst->u.pad.layers); |
270 | |
271 | pad_type_seen[type] = 1; |
272 | ps_filled_box(file, inst->base, inst->u.pad.other, hatch(type)); |
273 | |
274 | if (show_name && !inst->u.pad.hole) |
275 | ps_pad_name(file, inst); |
276 | } |
277 | |
278 | |
279 | static void ps_rounded_rect(FILE *file, struct coord a, struct coord b) |
280 | { |
281 | unit_type h, w, r; |
282 | |
283 | sort_coord(&a, &b); |
284 | h = b.y-a.y; |
285 | w = b.x-a.x; |
286 | |
287 | if (h > w) { |
288 | r = w/2; |
289 | fprintf(file, " %d %d moveto\n", b.x, b.y-r); |
290 | fprintf(file, " %d %d %d 0 180 arc\n", a.x+r, b.y-r, r); |
291 | fprintf(file, " %d %d lineto\n", a.x, a.y+r); |
292 | fprintf(file, " %d %d %d 180 360 arc\n", a.x+r, a.y+r, r); |
293 | } else { |
294 | r = h/2; |
295 | fprintf(file, " %d %d moveto\n", b.x-r, a.y); |
296 | fprintf(file, " %d %d %d -90 90 arc\n", b.x-r, a.y+r, r); |
297 | fprintf(file, " %d %d lineto\n", a.x+r, b.y); |
298 | fprintf(file, " %d %d %d 90 270 arc\n", a.x+r, a.y+r, r); |
299 | } |
300 | } |
301 | |
302 | |
303 | static void ps_rpad(FILE *file, const struct inst *inst, int show_name) |
304 | { |
305 | enum pad_type type = layers_to_pad_type(inst->u.pad.layers); |
306 | |
307 | pad_type_seen[type] = 1; |
308 | |
309 | fprintf(file, "0 setgray %d setlinewidth\n", PS_HATCH_LINE); |
310 | ps_rounded_rect(file, inst->base, inst->u.pad.other); |
311 | fprintf(file, " closepath gsave %s grestore stroke\n", hatch(type)); |
312 | |
313 | if (show_name && !inst->u.pad.hole) |
314 | ps_pad_name(file, inst); |
315 | } |
316 | |
317 | |
318 | static void ps_hole(FILE *file, const struct inst *inst, int show_name) |
319 | { |
320 | fprintf(file, "1 setgray %d setlinewidth\n", PS_RIM_LINE); |
321 | ps_rounded_rect(file, inst->base, inst->u.hole.other); |
322 | fprintf(file, " closepath gsave fill grestore\n"); |
323 | fprintf(file, " 0 setgray stroke\n"); |
324 | |
325 | if (show_name && inst->u.hole.pad) |
326 | ps_pad_name(file, inst->u.hole.pad); |
327 | } |
328 | |
329 | |
330 | static void ps_line(FILE *file, const struct inst *inst) |
331 | { |
332 | struct coord a = inst->base; |
333 | struct coord b = inst->u.rect.end; |
334 | |
335 | fprintf(file, "1 setlinecap 0.5 setgray %d setlinewidth\n", |
336 | inst->u.rect.width); |
337 | fprintf(file, " %d %d moveto %d %d lineto stroke\n", |
338 | a.x, a.y, b.x, b.y); |
339 | } |
340 | |
341 | |
342 | static void ps_rect(FILE *file, const struct inst *inst) |
343 | { |
344 | struct coord a = inst->base; |
345 | struct coord b = inst->u.rect.end; |
346 | |
347 | fprintf(file, "1 setlinecap 0.5 setgray %d setlinewidth\n", |
348 | inst->u.rect.width); |
349 | fprintf(file, " %d %d moveto\n", a.x, a.y); |
350 | fprintf(file, " %d %d lineto\n", b.x, a.y); |
351 | fprintf(file, " %d %d lineto\n", b.x, b.y); |
352 | fprintf(file, " %d %d lineto\n", a.x, b.y); |
353 | fprintf(file, " closepath stroke\n"); |
354 | } |
355 | |
356 | |
357 | static void ps_arc(FILE *file, const struct inst *inst) |
358 | { |
359 | double a1, a2; |
360 | |
361 | a1 = inst->u.arc.a1; |
362 | a2 = inst->u.arc.a2; |
363 | if (a2 <= a1) |
364 | a2 += 360; |
365 | |
366 | fprintf(file, "1 setlinecap 0.5 setgray %d setlinewidth\n", |
367 | inst->u.arc.width); |
368 | fprintf(file, " newpath %d %d %d %f %f arc stroke\n", |
369 | inst->base.x, inst->base.y, inst->u.arc.r, a1, a2); |
370 | } |
371 | |
372 | |
373 | static void ps_frame(FILE *file, const struct inst *inst) |
374 | { |
375 | } |
376 | |
377 | |
378 | static void ps_arrow(FILE *file, struct coord from, struct coord to, int len, |
379 | int angle) |
380 | { |
381 | struct coord side, p; |
382 | |
383 | if (from.x == to.x && from.y == to.y) { |
384 | side.x = 0; |
385 | side.y = -len; |
386 | } else { |
387 | side = normalize(sub_vec(to, from), len); |
388 | } |
389 | |
390 | p = add_vec(to, rotate(side, 180-angle)); |
391 | fprintf(file, " %d %d moveto\n", p.x, p.y); |
392 | fprintf(file, " %d %d lineto\n", to.x, to.y); |
393 | |
394 | p = add_vec(to, rotate(side, 180+angle)); |
395 | fprintf(file, " %d %d moveto\n", p.x, p.y); |
396 | fprintf(file, " %d %d lineto\n", to.x, to.y); |
397 | fprintf(file, " stroke\n"); |
398 | } |
399 | |
400 | |
401 | static void ps_vec(FILE *file, const struct inst *inst) |
402 | { |
403 | struct coord a, b, c, d; |
404 | char *s, *sx, *sy; |
405 | |
406 | a = inst->base; |
407 | b = inst->u.vec.end; |
408 | fprintf(file, "1 setlinecap 0 setgray %d setlinewidth\n", PS_VEC_LINE); |
409 | fprintf(file, " %d %d moveto\n", a.x, a.y); |
410 | fprintf(file, " %d %d lineto\n", b.x, b.y); |
411 | fprintf(file, " stroke\n"); |
412 | |
413 | ps_arrow(file, a, b, PS_VEC_ARROW_LEN, PS_VEC_ARROW_ANGLE); |
414 | |
415 | if (!active_params.label_vecs) |
416 | return; |
417 | |
418 | sx = unparse(inst->vec->x); |
419 | sy = unparse(inst->vec->y); |
420 | s = stralloc_printf("(%s, %s)", sx, sy); |
421 | free(sx); |
422 | free(sy); |
423 | c = add_vec(a, b); |
424 | d = sub_vec(b, a); |
425 | fprintf(file, "gsave %d %d moveto\n", c.x/2, c.y/2); |
426 | fprintf(file, " /Helvetica-Bold findfont dup\n"); |
427 | fprintf(file, " "); |
428 | ps_string(file, s); |
429 | fprintf(file, " %d %d realsize\n", |
430 | (int) (dist_point(a, b)-2*PS_VEC_ARROW_LEN), |
431 | PS_VEC_TEXT_HEIGHT); |
432 | fprintf(file, " boxfont\n"); |
433 | fprintf(file, " %f rotate\n", atan2(d.y, d.x)/M_PI*180); |
434 | fprintf(file, " "); |
435 | ps_string(file, s); |
436 | fprintf(file, " %d realsize pop 0 hcenter\n", PS_VEC_BASE_OFFSET); |
437 | fprintf(file, " show grestore\n"); |
438 | free(s); |
439 | } |
440 | |
441 | |
442 | /* ----- Measurements ------------------------------------------------------ */ |
443 | |
444 | |
445 | static unit_type guesstimate_text_height(const char *s, unit_type width, |
446 | double zoom) |
447 | { |
448 | return width/strlen(s)*TEXT_HEIGHT_FACTOR*zoom; |
449 | } |
450 | |
451 | |
452 | static void ps_meas(FILE *file, const struct inst *inst, |
453 | enum curr_unit unit, double zoom) |
454 | { |
455 | struct coord a0, b0, a1, b1; |
456 | struct coord c, d; |
457 | char *s; |
458 | unit_type height, width, offset; |
459 | |
460 | a0 = inst->base; |
461 | b0 = inst->u.meas.end; |
462 | project_meas(inst, &a1, &b1); |
463 | fprintf(file, "1 setlinecap 0 setgray %d realsize setlinewidth\n", |
464 | PS_MEAS_LINE); |
465 | fprintf(file, " %d %d moveto\n", a0.x, a0.y); |
466 | fprintf(file, " %d %d lineto\n", a1.x, a1.y); |
467 | fprintf(file, " %d %d lineto\n", b1.x, b1.y); |
468 | fprintf(file, " %d %d lineto\n", b0.x, b0.y); |
469 | fprintf(file, " stroke\n"); |
470 | |
471 | ps_arrow(file, a1, b1, PS_MEAS_ARROW_LEN, PS_MEAS_ARROW_ANGLE); |
472 | ps_arrow(file, b1, a1, PS_MEAS_ARROW_LEN, PS_MEAS_ARROW_ANGLE); |
473 | |
474 | s = format_len(inst->obj->u.meas.label ? inst->obj->u.meas.label : "", |
475 | dist_point(a1, b1), unit); |
476 | |
477 | c = add_vec(a1, b1); |
478 | d = sub_vec(b1, a1); |
479 | |
480 | /* |
481 | * First try: put text between the arrows |
482 | */ |
483 | width = dist_point(a1, b1)-1.5*PS_MEAS_ARROW_LEN; |
484 | offset = PS_MEAS_BASE_OFFSET; |
485 | height = 0; |
486 | if (guesstimate_text_height(s, width, zoom) < PS_MEAS_MIN_HEIGHT) { |
487 | #if 0 |
488 | fprintf(stderr, "%s -> width %d height %d vs. %d\n", |
489 | s, width, guesstimate_text_height(s, width, zoom), PS_MEAS_MIN_HEIGHT); |
490 | #endif |
491 | /* |
492 | * Second try: push it above the arrows |
493 | */ |
494 | width = dist_point(a1, b1); |
495 | offset += |
496 | PS_MEAS_ARROW_LEN*sin(PS_MEAS_ARROW_ANGLE*M_PI/180)*zoom; |
497 | |
498 | if (guesstimate_text_height(s, width, zoom) < |
499 | PS_MEAS_MIN_HEIGHT) { |
500 | height = PS_MEAS_MIN_HEIGHT; |
501 | width = strlen(s)*height; |
502 | } |
503 | } |
504 | |
505 | if (height) { |
506 | fprintf(file, "gsave %d %d moveto\n", c.x/2, c.y/2); |
507 | fprintf(file, " /Helvetica-Bold findfont dup\n"); |
508 | fprintf(file, " "); |
509 | ps_string(file, s); |
510 | fprintf(file, " %d realsize %d realsize\n", width, height); |
511 | fprintf(file, " boxfont\n"); |
512 | fprintf(file, " %f rotate\n", atan2(d.y, d.x)/M_PI*180); |
513 | fprintf(file, " "); |
514 | ps_string(file, s); |
515 | fprintf(file, " %d realsize hcenter\n", offset); |
516 | fprintf(file, " show grestore\n"); |
517 | } else { |
518 | fprintf(file, "gsave %d %d moveto\n", c.x/2, c.y/2); |
519 | fprintf(file, " /Helvetica-Bold findfont dup\n"); |
520 | fprintf(file, " "); |
521 | ps_string(file, s); |
522 | fprintf(file, " %d %d realsize\n", width, PS_MEAS_TEXT_HEIGHT); |
523 | fprintf(file, " boxfont\n"); |
524 | fprintf(file, " %f rotate\n", atan2(d.y, d.x)/M_PI*180); |
525 | fprintf(file, " "); |
526 | ps_string(file, s); |
527 | fprintf(file, " %d realsize hcenter\n", offset); |
528 | fprintf(file, " show grestore\n"); |
529 | } |
530 | free(s); |
531 | } |
532 | |
533 | |
534 | /* ----- Print layers ------------------------------------------------------ */ |
535 | |
536 | |
537 | static void ps_background(FILE *file, enum inst_prio prio, |
538 | const struct inst *inst) |
539 | { |
540 | switch (prio) { |
541 | case ip_line: |
542 | ps_line(file, inst); |
543 | break; |
544 | case ip_rect: |
545 | ps_rect(file, inst); |
546 | break; |
547 | case ip_circ: |
548 | case ip_arc: |
549 | ps_arc(file, inst); |
550 | break; |
551 | default: |
552 | break; |
553 | } |
554 | } |
555 | |
556 | |
557 | static void ps_foreground(FILE *file, enum inst_prio prio, |
558 | const struct inst *inst, double zoom) |
559 | { |
560 | switch (prio) { |
561 | case ip_pad_copper: |
562 | case ip_pad_special: |
563 | if (inst->obj->u.pad.rounded) |
564 | ps_rpad(file, inst, active_params.show_pad_names); |
565 | else |
566 | ps_pad(file, inst, active_params.show_pad_names); |
567 | break; |
568 | case ip_hole: |
569 | ps_hole(file, inst, active_params.show_pad_names); |
570 | break; |
571 | case ip_vec: |
572 | if (active_params.show_stuff) |
573 | ps_vec(file, inst); |
574 | break; |
575 | case ip_frame: |
576 | if (active_params.show_stuff) |
577 | ps_frame(file, inst); |
578 | break; |
579 | case ip_meas: |
580 | if (active_params.show_meas) |
581 | ps_meas(file, inst, curr_unit, zoom); |
582 | break; |
583 | default: |
584 | break; |
585 | } |
586 | } |
587 | |
588 | |
589 | /* ----- Package level ----------------------------------------------------- */ |
590 | |
591 | |
592 | static void ps_cross(FILE *file, const struct inst *inst) |
593 | { |
594 | fprintf(file, "gsave 0 setgray %d setlinewidth\n", PS_CROSS_WIDTH); |
595 | fprintf(file, " [%d] 0 setdash\n", PS_CROSS_DASH); |
596 | fprintf(file, " %d 0 moveto %d 0 lineto\n", |
597 | inst->bbox.min.x, inst->bbox.max.x); |
598 | fprintf(file, " 0 %d moveto 0 %d lineto\n", |
599 | inst->bbox.min.y, inst->bbox.max.y); |
600 | fprintf(file, " stroke grestore\n"); |
601 | } |
602 | |
603 | |
604 | static void ps_draw_package(FILE *file, const struct pkg *pkg, double zoom, |
605 | int cross) |
606 | { |
607 | enum inst_prio prio; |
608 | const struct inst *inst; |
609 | |
610 | fprintf(file, "gsave %f dup scale\n", zoom); |
611 | if (cross) |
612 | ps_cross(file, pkgs->insts[ip_frame]); |
613 | FOR_INST_PRIOS_UP(prio) { |
614 | FOR_PKG_INSTS(pkgs, prio, inst) |
615 | ps_background(file, prio, inst); |
616 | FOR_PKG_INSTS(pkg, prio, inst) |
617 | ps_background(file, prio, inst); |
618 | } |
619 | FOR_INST_PRIOS_UP(prio) { |
620 | FOR_PKG_INSTS(pkgs, prio, inst) |
621 | ps_foreground(file, prio, inst, zoom); |
622 | FOR_PKG_INSTS(pkg, prio, inst) |
623 | ps_foreground(file, prio, inst, zoom); |
624 | } |
625 | fprintf(file, "grestore\n"); |
626 | } |
627 | |
628 | |
629 | /* ----- Object frames ----------------------------------------------------- */ |
630 | |
631 | |
632 | static void ps_draw_frame(FILE *file, const struct pkg *pkg, |
633 | const struct inst *outer, double zoom) |
634 | { |
635 | enum inst_prio prio; |
636 | const struct inst *inst; |
637 | |
638 | fprintf(file, "gsave %f dup scale\n", zoom); |
639 | ps_cross(file, outer); |
640 | FOR_INST_PRIOS_UP(prio) { |
641 | FOR_PKG_INSTS(pkgs, prio, inst) |
642 | if (inst->outer == outer) |
643 | ps_background(file, prio, inst); |
644 | FOR_PKG_INSTS(pkg, prio, inst) |
645 | if (inst->outer == outer) |
646 | ps_background(file, prio, inst); |
647 | } |
648 | FOR_INST_PRIOS_UP(prio) { |
649 | FOR_PKG_INSTS(pkgs, prio, inst) |
650 | if (inst->outer == outer) |
651 | ps_foreground(file, prio, inst, zoom); |
652 | FOR_PKG_INSTS(pkg, prio, inst) |
653 | if (inst->outer == outer) |
654 | ps_foreground(file, prio, inst, zoom); |
655 | } |
656 | fprintf(file, "grestore\n"); |
657 | } |
658 | |
659 | |
660 | static int generate_frames(FILE *file, const struct pkg *pkg, |
661 | const struct frame *frame, double zoom) |
662 | { |
663 | const struct inst *inst; |
664 | unit_type x, y, xa, ya; |
665 | unit_type cx, cy, border; |
666 | int ok; |
667 | |
668 | /* |
669 | * This doesn't work yet. The whole idea of just picking the current |
670 | * instance of each object and drawing it is flawed, since we may have |
671 | * very different sizes in a frame, so one big vector may dominate all |
672 | * the finer details. |
673 | * |
674 | * Also, the amount of text can be large and force tiny fonts to make |
675 | * things fit. |
676 | * |
677 | * A better approach would be to use a more qualitative display than a |
678 | * quantitative one, emphasizing the logical structure of the drawing |
679 | * and not the actual sizes. |
680 | * |
681 | * This could be done by ranking vectors by current, average, maximum, |
682 | * etc. size, then let their size be determined by the amount of text |
683 | * that's needed and the size of subordinate vectors. One difficulty |
684 | * would be in making vectors with a fixed length ratio look correct, |
685 | * particularly 1:1. |
686 | * |
687 | * Furthermore, don't write on the vector but put the text horizontally |
688 | * on either the left or the right side. |
689 | * |
690 | * Frame references could be drawn by simply connecting a line to the |
691 | * area of the respective frame. And let's not forget that we also need |
692 | * to list the variables somewhere. |
693 | */ |
694 | return 0; |
695 | |
696 | while (frame) { |
697 | if (frame->name) |
698 | for (inst = pkg->insts[ip_frame]; inst; |
699 | inst = inst->next) |
700 | if (inst->u.frame.ref == frame) |
701 | goto found_frame; |
702 | frame = frame->next; |
703 | } |
704 | if (!frame) |
705 | return 1; |
706 | |
707 | found_frame: |
708 | border = PS_MEAS_TEXT_HEIGHT+PS_DIVIDER_WIDTH+PS_DIVIDER_BORDER/2; |
709 | x = (inst->bbox.max.x-inst->bbox.min.x)*zoom+2*border; |
710 | y = (inst->bbox.max.y-inst->bbox.min.y)*zoom+2*border; |
711 | if (!get_box(x, y, &xa, &ya)) |
712 | return 0; |
713 | |
714 | /* |
715 | * Recurse down first, so that we only draw something if we can be sure |
716 | * that all the rest can be drawn too. |
717 | */ |
718 | |
719 | ok = generate_frames(file, pkg, frame->next, zoom); |
720 | if (!ok) |
721 | return 0; |
722 | |
723 | |
724 | #if 1 |
725 | fprintf(file, "0 setlinewidth 0.8 setgray\n"); |
726 | fprintf(file, "%d %d moveto\n", xa+border, ya+border); |
727 | fprintf(file, "%d %d lineto\n", xa+x-border, ya+border); |
728 | fprintf(file, "%d %d lineto\n", xa+x-border, ya+y-border); |
729 | fprintf(file, "%d %d lineto\n", xa+border, ya+y-border); |
730 | fprintf(file, "closepath fill\n"); |
731 | #endif |
732 | cx = xa+x/2-(inst->bbox.min.x+inst->bbox.max.x)/2*zoom; |
733 | cy = ya+y/2-(inst->bbox.min.y+inst->bbox.max.y)/2*zoom; |
734 | |
735 | fprintf(file, "%% Frame %s\n", frame->name ? frame->name : "(root)"); |
736 | fprintf(file, "gsave %d %d translate\n", cx, cy); |
737 | ps_draw_frame(file, pkg, inst, zoom); |
738 | fprintf(file, "grestore\n"); |
739 | |
740 | return 1; |
741 | } |
742 | |
743 | |
744 | /* ----- Page level -------------------------------------------------------- */ |
745 | |
746 | |
747 | static void ps_hline(FILE *file, int y) |
748 | { |
749 | fprintf(file, "gsave %d setlinewidth\n", PS_DIVIDER_WIDTH); |
750 | fprintf(file, " %d %d moveto\n", -PAGE_HALF_WIDTH, y); |
751 | fprintf(file, " %d 0 rlineto stroke grestore\n", PAGE_HALF_WIDTH*2); |
752 | } |
753 | |
754 | |
755 | static void ps_header(FILE *file, const struct pkg *pkg) |
756 | { |
757 | fprintf(file, "gsave %d %d moveto\n", |
758 | -PAGE_HALF_WIDTH, PAGE_HALF_HEIGHT-PS_HEADER_HEIGHT); |
759 | fprintf(file, " /Helvetica-Bold findfont dup\n"); |
760 | fprintf(file, " "); |
761 | ps_string(file, pkg->name); |
762 | fprintf(file, " %d %d\n", PAGE_HALF_WIDTH, PS_HEADER_HEIGHT); |
763 | fprintf(file, " boxfont\n"); |
764 | fprintf(file, " "); |
765 | ps_string(file, pkg->name); |
766 | fprintf(file, " show grestore\n"); |
767 | |
768 | ps_hline(file, PAGE_HALF_HEIGHT-PS_HEADER_HEIGHT-PS_DIVIDER_BORDER); |
769 | } |
770 | |
771 | |
772 | static void ps_page(FILE *file, int page, const struct pkg *pkg) |
773 | { |
774 | fprintf(file, "%%%%Page: %d %d\n", page, page); |
775 | |
776 | fprintf(file, "%%%%BeginPageSetup\n"); |
777 | fprintf(file, |
778 | "currentpagedevice /PageSize get\n" |
779 | " aload pop\n" |
780 | " 2 div exch 2 div exch\n" |
781 | " translate\n" |
782 | " 72 %d div 1000 div dup scale\n", |
783 | (int) MIL_UNITS); |
784 | fprintf(file, "%%%%EndPageSetup\n"); |
785 | fprintf(file, "[ /Title "); |
786 | ps_string(file, pkg->name); |
787 | fprintf(file, " /OUT pdfmark\n"); |
788 | } |
789 | |
790 | |
791 | static void ps_unit(FILE *file, |
792 | unit_type x, unit_type y, unit_type w, unit_type h) |
793 | { |
794 | const char *s; |
795 | |
796 | switch (curr_unit) { |
797 | case curr_unit_mm: |
798 | s = "Dimensions in mm"; |
799 | break; |
800 | case curr_unit_mil: |
801 | s = "Dimensions in mil"; |
802 | break; |
803 | case curr_unit_auto: |
804 | return; |
805 | default: |
806 | abort(); |
807 | } |
808 | |
809 | fprintf(file, "gsave %d %d moveto\n", x, y); |
810 | fprintf(file, " /Helvetica findfont dup\n"); |
811 | fprintf(file, " "); |
812 | ps_string(file, s); |
813 | fprintf(file, " %d %d\n", w, h); |
814 | fprintf(file, " boxfont\n"); |
815 | fprintf(file, " "); |
816 | ps_string(file, s); |
817 | fprintf(file, " show grestore\n"); |
818 | } |
819 | |
820 | |
821 | static void ps_key(FILE *file, double w, double h, enum pad_type type) |
822 | { |
823 | char tmp[20]; /* @@@ plenty :) */ |
824 | double f = 32; |
825 | struct coord a, b; |
826 | unit_type key_w; |
827 | |
828 | key_w = (w-2*PS_KEY_X_GAP-PS_KEY_X_GAP*(pt_n-1))/pt_n; |
829 | a.x = b.x = (key_w+PS_KEY_X_GAP)*type-w/2+PS_KEY_X_GAP; |
830 | a.y = b.y = -h/2-PS_KEY_Y_GAP; |
831 | b.x += key_w; |
832 | b.y -= PS_KEY_HEIGTH; |
833 | |
834 | a.x /= f; |
835 | a.y /= f; |
836 | b.x /= f; |
837 | b.y /= f; |
838 | |
839 | strcpy(tmp, pad_type_name(type)); |
840 | tmp[0] = toupper(tmp[0]); |
841 | fprintf(file, "gsave %f %f scale\n", f, f); |
842 | ps_filled_box(file, a, b, hatch(type)); |
843 | ps_outlined_text_in_rect(file, tmp, a, b); |
844 | fprintf(file, "grestore\n"); |
845 | } |
846 | |
847 | |
848 | static void ps_keys(FILE *file, double w, double h) |
849 | { |
850 | enum pad_type i; |
851 | |
852 | for (i = 0; i != pt_n; i++) |
853 | if (pad_type_seen[i]) |
854 | ps_key(file, w, h, i); |
855 | } |
856 | |
857 | |
858 | static void ps_package(FILE *file, const struct pkg *pkg, int page) |
859 | { |
860 | struct bbox bbox; |
861 | unit_type x, y; |
862 | unit_type w, h; |
863 | double f; |
864 | unit_type c, d; |
865 | int done; |
866 | |
867 | ps_page(file, page, pkg); |
868 | ps_header(file, pkg); |
869 | |
870 | x = 2*PAGE_HALF_WIDTH-2*PS_DIVIDER_BORDER; |
871 | y = PAGE_HALF_HEIGHT-PS_HEADER_HEIGHT-3*PS_DIVIDER_BORDER; |
872 | |
873 | bbox = inst_get_bbox(pkg); |
874 | w = 2*(-bbox.min.x > bbox.max.x ? -bbox.min.x : bbox.max.x); |
875 | h = 2*(-bbox.min.y > bbox.max.y ? -bbox.min.y : bbox.max.y); |
876 | |
877 | /* |
878 | * Zoom such that we can fit at least one drawing |
879 | */ |
880 | |
881 | if (w > x/2 || h > y) { |
882 | f = (double) x/w; |
883 | if ((double) y/h < f) |
884 | f = (double) y/h; |
885 | if (f > 1) |
886 | f = 1; |
887 | } else { |
888 | for (f = 20; f > 1; f--) |
889 | if (x/(f+2) >= w && y/f >= h) |
890 | break; |
891 | } |
892 | |
893 | /* |
894 | * Decide if we have room for two, one, or zero smaller views |
895 | */ |
896 | |
897 | c = y/2+PS_DIVIDER_BORDER; |
898 | active_params = postscript_params; |
899 | if (x/(f+2) >= w && y/3 > h) { |
900 | /* main drawing */ |
901 | fprintf(file, "gsave %d %d translate\n", |
902 | (int) (x/(f+2)*f/2)-PAGE_HALF_WIDTH, c); |
903 | ps_draw_package(file, pkg, f, 1); |
904 | |
905 | active_params = minimal_params; |
906 | |
907 | /* divider */ |
908 | d = PAGE_HALF_WIDTH-2*x/(f+2); |
909 | fprintf(file, "grestore gsave %d setlinewidth\n", |
910 | PS_DIVIDER_WIDTH); |
911 | fprintf(file, " %d %d moveto 0 %d rlineto stroke\n", |
912 | d-PS_DIVIDER_BORDER, PS_DIVIDER_BORDER, y); |
913 | |
914 | /* x1 package */ |
915 | fprintf(file, "grestore gsave %d %d translate\n", |
916 | (d+PAGE_HALF_WIDTH)/2, y/6*5+PS_DIVIDER_BORDER); |
917 | ps_draw_package(file, pkg, 1, 1); |
918 | |
919 | /* x2 package */ |
920 | fprintf(file, "grestore gsave %d %d translate\n", |
921 | (d+PAGE_HALF_WIDTH)/2, y/3+PS_DIVIDER_BORDER); |
922 | ps_draw_package(file, pkg, 2, 1); |
923 | } else if (x/(f+1) >= w && y/2 > h) { |
924 | /* main drawing */ |
925 | fprintf(file, "gsave %d %d translate\n", |
926 | (int) (x/(f+1)*f/2)-PAGE_HALF_WIDTH, c); |
927 | ps_draw_package(file, pkg, f, 1); |
928 | |
929 | active_params = minimal_params; |
930 | |
931 | /* divider */ |
932 | d = PAGE_HALF_WIDTH-x/(f+1); |
933 | fprintf(file, "grestore gsave %d setlinewidth\n", |
934 | PS_DIVIDER_WIDTH); |
935 | fprintf(file, " %d %d moveto 0 %d rlineto stroke\n", |
936 | d-PS_DIVIDER_BORDER, PS_DIVIDER_BORDER, y); |
937 | |
938 | /* x1 package */ |
939 | fprintf(file, "grestore gsave %d %d translate\n", |
940 | (d+PAGE_HALF_WIDTH)/2, c); |
941 | ps_draw_package(file, pkg, 1, 1); |
942 | } else { |
943 | fprintf(file, "gsave 0 %d translate\n", c); |
944 | ps_draw_package(file, pkg, f, 1); |
945 | } |
946 | fprintf(file, "grestore\n"); |
947 | |
948 | ps_unit(file, -PAGE_HALF_WIDTH, PS_DIVIDER_BORDER, PAGE_HALF_WIDTH, |
949 | PS_MISC_TEXT_HEIGHT); |
950 | ps_hline(file, 0); |
951 | |
952 | /* |
953 | * Put the frames |
954 | * |
955 | * @@@ is it really a good idea to use the same zoom for all of them ? |
956 | */ |
957 | |
958 | active_params.show_stuff = 1; |
959 | active_params.label_vecs = 1; |
960 | for (f = 20; f >= 0.1; f = f > 1 ? f-1 : f-0.1) { |
961 | add_box(-PAGE_HALF_WIDTH, -PAGE_HALF_HEIGHT, PAGE_HALF_WIDTH, |
962 | -PS_DIVIDER_BORDER); |
963 | done = generate_frames(file, pkg, frames, f); |
964 | free_boxes(); |
965 | if (done) |
966 | break; |
967 | } |
968 | |
969 | fprintf(file, "showpage\n"); |
970 | } |
971 | |
972 | |
973 | /* ----- File level -------------------------------------------------------- */ |
974 | |
975 | |
976 | static void prologue(FILE *file, int pages) |
977 | { |
978 | fprintf(file, "%%!PS-Adobe-3.0\n"); |
979 | fprintf(file, "%%%%Pages: %d\n", pages); |
980 | fprintf(file, "%%%%EndComments\n"); |
981 | |
982 | fprintf(file, "%%%%BeginDefaults\n"); |
983 | fprintf(file, "%%%%PageResources: font Helvetica Helvetica-Bold\n"); |
984 | fprintf(file, "%%%%EndDefaults\n"); |
985 | |
986 | fprintf(file, "%%%%BeginProlog\n"); |
987 | |
988 | fprintf(file, |
989 | "/dotpath {\n" |
990 | " gsave flattenpath pathbbox clip newpath\n" |
991 | " 1 setlinecap %d setlinewidth\n" |
992 | " /ury exch def /urx exch def /lly exch def /llx exch def\n" |
993 | " llx %d urx {\n" |
994 | " lly %d ury {\n" |
995 | " 1 index exch moveto 0 0 rlineto stroke\n" |
996 | " } for\n" |
997 | " } for\n" |
998 | " grestore newpath } def\n", PS_DOT_DIAM, PS_DOT_DIST, PS_DOT_DIST); |
999 | |
1000 | fprintf(file, |
1001 | "/hatchpath {\n" |
1002 | " gsave flattenpath pathbbox clip newpath\n" |
1003 | " /ury exch def /urx exch def /lly exch def /llx exch def\n" |
1004 | " lly ury sub %d urx llx sub {\n" /* for -(ury-lly) to urx-llx */ |
1005 | " llx add dup lly moveto\n" |
1006 | " ury lly sub add ury lineto stroke\n" |
1007 | " } for\n" |
1008 | " grestore newpath } def\n", PS_HATCH); |
1009 | |
1010 | fprintf(file, |
1011 | "/backhatchpath {\n" |
1012 | " gsave flattenpath pathbbox clip newpath\n" |
1013 | " /ury exch def /urx exch def /lly exch def /llx exch def\n" |
1014 | " 0 %d ury lly sub urx llx sub add {\n" /* for 0 to urx-llx+ury-lly */ |
1015 | " llx add dup lly moveto\n" |
1016 | " ury lly sub sub ury lineto stroke\n" |
1017 | " } for\n" |
1018 | " grestore newpath } def\n", PS_HATCH); |
1019 | |
1020 | fprintf(file, |
1021 | "/crosspath {\n" |
1022 | " gsave hatchpath grestore backhatchpath } def\n"); |
1023 | |
1024 | fprintf(file, |
1025 | "/horpath {\n" |
1026 | " gsave flattenpath pathbbox clip newpath\n" |
1027 | " /ury exch def /urx exch def /lly exch def /llx exch def\n" |
1028 | " lly %d ury {\n" /* for lly to ury */ |
1029 | " dup llx exch moveto\n" |
1030 | " urx exch lineto stroke\n" |
1031 | " } for\n" |
1032 | " grestore newpath } def\n", PS_STRIPE); |
1033 | |
1034 | /* |
1035 | * Stack: font string width height factor -> factor |
1036 | * |
1037 | * Hack: sometimes, scalefont can't produce a suitable font and just |
1038 | * gives us something zero-sized, which trips the division. We just |
1039 | * ignore this case for now. Since maxfont is used in pairs, the |
1040 | * second one may still succeed. |
1041 | */ |
1042 | |
1043 | fprintf(file, |
1044 | "/sdiv { dup 0 eq { pop 1 } if div } def\n" |
1045 | "/maxfont {\n" |
1046 | " gsave 0 0 moveto\n" |
1047 | " /f exch def /h exch def /w exch def\n" |
1048 | " exch f scalefont setfont\n" |
1049 | " false charpath flattenpath pathbbox\n" |
1050 | " /ury exch def /urx exch def /lly exch def /llx exch def\n" |
1051 | " w urx llx sub sdiv h ury lly sub sdiv 2 copy gt { exch } if pop\n" |
1052 | " f mul grestore } def\n"); |
1053 | |
1054 | /* |
1055 | * Unrotate: - -> - |
1056 | */ |
1057 | |
1058 | fprintf(file, |
1059 | "/getscale { matrix currentmatrix dup 0 get dup mul exch 1 get dup mul\n" |
1060 | " add sqrt } def\n"); |
1061 | |
1062 | /* |
1063 | * Stack: string -> string |
1064 | */ |
1065 | |
1066 | fprintf(file, |
1067 | "/center {\n" |
1068 | " currentpoint /y exch def /x exch def\n" |
1069 | " gsave dup false charpath flattenpath pathbbox\n" |
1070 | " /ury exch def /urx exch def\n" |
1071 | " /lly exch def /llx exch def\n" |
1072 | " grestore\n" |
1073 | " x llx urx add 2 div sub y lly ury add 2 div sub rmoveto } def\n"); |
1074 | |
1075 | /* |
1076 | * Stack: string dist -> string |
1077 | */ |
1078 | |
1079 | fprintf(file, |
1080 | "/hcenter {\n" |
1081 | " /off exch def\n" |
1082 | " gsave matrix setmatrix dup false charpath flattenpath pathbbox\n" |
1083 | " /ury exch def /urx exch def /lly exch def /llx exch def\n" |
1084 | " grestore\n" |
1085 | //" /currscale getscale def\n" |
1086 | " llx urx sub 2 div\n" |
1087 | //" off lly sub rmoveto } def\n"); |
1088 | " off rmoveto } def\n"); |
1089 | |
1090 | /* |
1091 | * Stack: string outline_width -> - |
1092 | */ |
1093 | |
1094 | fprintf(file, |
1095 | "/showoutlined {\n" |
1096 | " gsave 2 mul setlinewidth 1 setgray 1 setlinejoin\n" |
1097 | " dup false charpath flattenpath stroke grestore\n" |
1098 | " show } def\n"); |
1099 | |
1100 | /* |
1101 | * Stack: string -> string |
1102 | */ |
1103 | |
1104 | fprintf(file, |
1105 | "/debugbox { gsave dup false charpath flattenpath pathbbox\n" |
1106 | " /ury exch def /urx exch def /lly exch def /llx exch def\n" |
1107 | " 0 setgray 100 setlinewidth\n" |
1108 | " llx lly urx llx sub ury lly sub rectstroke grestore } def\n"); |
1109 | |
1110 | /* |
1111 | * Stack: int -> int |
1112 | */ |
1113 | |
1114 | fprintf(file, |
1115 | "/originalsize 1 0 matrix currentmatrix idtransform pop def\n" |
1116 | "/realsize {\n" |
1117 | " 254 div 72 mul 1000 div 0 matrix currentmatrix idtransform\n" |
1118 | " dup mul exch dup mul add sqrt\n" |
1119 | " originalsize div } def\n"); |
1120 | |
1121 | /* |
1122 | * Stack: font string x-size y-size -> - |
1123 | */ |
1124 | |
1125 | fprintf(file, |
1126 | "/boxfont { 4 copy 1000 maxfont maxfont scalefont setfont } def\n"); |
1127 | |
1128 | /* |
1129 | * Ignore pdfmark. From |
1130 | * http://www.adobe.com/devnet/acrobat/pdfs/pdfmark_reference.pdf |
1131 | * Page 10, Example 1.1. |
1132 | */ |
1133 | |
1134 | fprintf(file, |
1135 | "/pdfmark where { pop }\n" |
1136 | " { /globaldict where { pop globaldict } { userdict } ifelse" |
1137 | " /pdfmark /cleartomark load put } ifelse\n"); |
1138 | |
1139 | fprintf(file, "%%%%EndProlog\n"); |
1140 | } |
1141 | |
1142 | |
1143 | static void epilogue(FILE *file) |
1144 | { |
1145 | fprintf(file, "%%%%EOF\n"); |
1146 | } |
1147 | |
1148 | |
1149 | static int ps_for_all_pkg(FILE *file, |
1150 | void (*fn)(FILE *file, const struct pkg *pkg, int page), |
1151 | const char *one) |
1152 | { |
1153 | struct pkg *pkg; |
1154 | int pages = 0; |
1155 | |
1156 | for (pkg = pkgs; pkg; pkg = pkg->next) |
1157 | if (pkg->name) |
1158 | if (!one || !strcmp(pkg->name, one)) |
1159 | pages++; |
1160 | if (one && !pages) { |
1161 | fprintf(stderr, "no package \"%s\" to select\n", one); |
1162 | errno = ENOENT; |
1163 | return 0; |
1164 | } |
1165 | prologue(file, pages); |
1166 | pages = 0; |
1167 | for (pkg = pkgs; pkg; pkg = pkg->next) |
1168 | if (pkg->name) |
1169 | if (!one || !strcmp(pkg->name, one)) |
1170 | fn(file, pkg, ++pages); |
1171 | epilogue(file); |
1172 | |
1173 | fflush(file); |
1174 | return !ferror(file); |
1175 | } |
1176 | |
1177 | |
1178 | int postscript(FILE *file, const char *one) |
1179 | { |
1180 | return ps_for_all_pkg(file, ps_package, one); |
1181 | } |
1182 | |
1183 | |
1184 | /* |
1185 | * Experimental. Doesn't work properly. |
1186 | */ |
1187 | |
1188 | static void ps_package_fullpage(FILE *file, const struct pkg *pkg, int page) |
1189 | { |
1190 | unit_type cx, cy; |
1191 | struct bbox bbox; |
1192 | double fx, fy, f; |
1193 | double w = 2.0*PAGE_HALF_WIDTH; |
1194 | double h = 2.0*PAGE_HALF_HEIGHT; |
1195 | int yoff = 0; |
1196 | |
1197 | ps_page(file, page, pkg); |
1198 | active_params = postscript_params; |
1199 | bbox = inst_get_bbox(pkg); |
1200 | cx = (bbox.min.x+bbox.max.x)/2; |
1201 | cy = (bbox.min.y+bbox.max.y)/2; |
1202 | if (active_params.zoom) { |
1203 | f = active_params.zoom; |
1204 | } else { |
1205 | if (active_params.max_width) |
1206 | w = active_params.max_width; |
1207 | fx = w/(bbox.max.x-bbox.min.x); |
1208 | if (active_params.max_height) |
1209 | h = active_params.max_height; |
1210 | if (active_params.show_key) { |
1211 | yoff = PS_KEY_HEIGTH+PS_KEY_Y_GAP; |
1212 | h -= yoff; |
1213 | } |
1214 | fy = h/(bbox.max.y-bbox.min.y); |
1215 | f = fx < fy ? fx : fy; |
1216 | } |
1217 | fprintf(file, "gsave\n"); |
1218 | fprintf(file, "%d %d translate\n", (int) (-cx*f), (int) (-cy*f)+yoff); |
1219 | memset(pad_type_seen, 0, sizeof(pad_type_seen)); |
1220 | ps_draw_package(file, pkg, f, 0); |
1221 | fprintf(file, "grestore\n"); |
1222 | if (active_params.show_key) { |
1223 | fprintf(file, "gsave 0 %d translate\n", yoff); |
1224 | ps_keys(file, w, h); |
1225 | fprintf(file, "grestore\n"); |
1226 | } |
1227 | fprintf(file, "showpage\n"); |
1228 | } |
1229 | |
1230 | |
1231 | int postscript_fullpage(FILE *file, const char *one) |
1232 | { |
1233 | return ps_for_all_pkg(file, ps_package_fullpage, one); |
1234 | } |
1235 |
Branches:
master