|
|
1.1 root 1: /*
2: * emit PostScript.
3: *
4: */
5:
6: #include "draw_dag.h"
7: #include "dag.h"
8: #include "parsedag.h"
9: #include "paths.h"
10:
11: static double PS_scalefactor;
12: static dag_ink_t Current_PS_ink;
13:
14: static Point Page_min,Page_max;
15: static Point PS_page_size,PS_Margin;
16: static int Pages_across, Pages_up;
17: static int Page_number = 0;
18:
19: static char* escape(char *s) {
20: static char buf[BUFSIZ];
21: char *p = buf;
22: while (*s) {
23: if ((*s == '(') || (*s == ')')) *p++ = '\\';
24: *p++ = *s++;
25: }
26: *p = '\0';
27: return buf;
28: }
29:
30: void emit_ps_setink(dag_ink_t ink) {
31: char *inkstr;
32: switch(ink) {
33: case solid_ink:
34: inkstr = "[] 0"; break;
35: case dashed_ink:
36: inkstr = "[9 9 idtransform abs ceiling exch abs ceiling exch] 0"; break;
37: case dotted_ink:
38: inkstr = "[1 6 idtransform abs ceiling exch abs ceiling exch] 0"; break;
39: case invis_ink:
40: inkstr = "[0 1] 1"; break;
41: }
42: printf("%s setdash\n",inkstr);
43: Current_PS_ink = ink;
44: }
45:
46: void emit_ps_header() {
47: if (!Page_number) {
48: printf("%%! PostScript\n%%%%EndComments\n");
49: printf("/Reset_Node_Pointsize %d def\n",Reset_node.pointsize);
50: printf("/Reset_Edge_Pointsize %d def\n",Reset_edge.pointsize);
51: printf("/coordfont /Times-Roman findfont 6 scalefont def\n");
52: cat_libfile(DAGLIB_PS);
53: }
54:
55: PS_scalefactor = 1.;
56: if (User.width > 0) {
57: PS_scalefactor = min((User.width*Resolution)/Xmax,1.);
58: if (User.height <= 0) User.height = (double)Ymax/Resolution;
59: else PS_scalefactor = min((User.height*Resolution)/Ymax,PS_scalefactor);
60: }
61: if ((Page_size.x == 0) && (Page_size.y == 0) && (User.width != 0)) {
62: PS_page_size.x = round(User.width * Resolution / PS_scalefactor);
63: PS_page_size.y = round(User.height * Resolution / PS_scalefactor);
64: }
65: else {
66: if (Page_size.x) {
67: PS_page_size.x = round(Page_size.x / PS_scalefactor);
68: PS_page_size.y = round(Page_size.y / PS_scalefactor);
69: }
70: else {
71: PS_page_size.x = Xmax;
72: PS_page_size.y = Ymax;
73: }
74: }
75: PS_Margin.x = (int)(Margin.x/PS_scalefactor);
76: PS_Margin.y = (int)(Margin.x/PS_scalefactor);
77: printf("save\n");
78:
79: if (Default_node.pointsize != Reset_node.pointsize)
80: printf("/dagnodefont dagnodefont %.3f scalefont def\n",
81: Default_node.pointsize/(double)Reset_node.pointsize);
82: if (Default_edge.pointsize != Reset_edge.pointsize)
83: printf("/dagedgefont dagedgefont %.3f scalefont def\n",
84: Default_edge.pointsize/(double)Reset_edge.pointsize);
85: printf("/coordfont /Times-Roman findfont %d scalefont def\n",(int)(6/PS_scalefactor));
86: if (PS_scalefactor != 1.) printf("%.3f %.3f scale\n",PS_scalefactor,PS_scalefactor);
87: printf("/arrowlength %d def\n",Default_node.ysize/5);
88: printf("/arrowwidth arrowlength 2 div def\n");
89: unsquirrel(); // inside save region, so will not affect global defs
90: printf("%%%%EndProlog\n");
91: }
92:
93: void emit_ps_node_header() {
94: printf("dagnodefont setfont\n");
95: }
96:
97: void emit_ps_edge_header() {
98: emit_ps_setink(Default_edge.ink);
99: Current_PS_ink = Default_edge.ink;
100: printf("dagedgefont setfont\n");
101: }
102:
103: /* emit drawing code for an edge label */
104: void emit_ps_edgelabel(DAG_edge_t *e) {
105: if (!e->label.type) return; // no label
106: if (e->pointsize != Default_edge.pointsize)
107: printf("dagedgefont %.3f scalefont setfont\n",
108: PS_scalefactor * e->pointsize / Default_edge.pointsize);
109: Point midpoint = find_edge_midpoint(e);
110: printf("%d %d moveto\n",midpoint.x,midpoint.y);
111: switch (e->label.type) {
112: case DESC:
113: printf("gsave\n%s\ngrestore\n",e->label.value);
114: break;
115: case STRING:
116: printf("(%s) show\n",escape(e->label.value));
117: }
118: if (e->pointsize != Default_edge.pointsize)
119: printf("dagedgefront setfont\n");
120: }
121:
122: void emit_ps_node(int node) {
123: char *printname;
124: if (Node[node]->label.type == STRING)
125: printname = Node[node]->label.value;
126: else if (Node[node]->label.type == DESC)
127: printname = "";
128: else printname = Node[node]->name;
129: printf("%d %d moveto\n",Node[node]->pos.x,Node[node]->pos.y);
130: if (Node[node]->color)
131: printf("gsave %s setdagcolor\n",Node[node]->color);
132: if (Node[node]->pointsize != Default_node.pointsize)
133: printf("dagnodefont %.3f scalefont setfont\n",
134: (PS_scalefactor*Node[node]->pointsize)/Default_node.pointsize);
135: if (Node[node]->shape.type == STRING)
136: printf("(%s) %d %d %s\n",escape(printname),Node[node]->xsize,Node[node]->ysize,Node[node]->shape.value);
137: else printf("%s\n",Node[node]->shape.value);
138: if (Node[node]->label.type == DESC) {
139: printf("%d %d moveto\n",Node[node]->pos.x,Node[node]->pos.y);
140: printf("%s\n",Node[node]->label.value);
141: }
142: if (Node[node]->pointsize != Default_node.pointsize)
143: printf("dagnodefont setfont\n");
144: if (Node[node]->color)
145: printf("grestore\n");
146: }
147:
148: /*
149: * generate PS code to place node intersection on stack.
150: * intersection is the ray from rayorg through rayinter
151: */
152: void emit_ps_nodeport(int node,Point rayorg, Point rayinter) {
153: printf(" %d %d %d %d %d %d ",Node[node]->xsize,Node[node]->ysize,rayorg.x - Node[node]->pos.x,rayorg.y - Node[node]->pos.y,rayinter.x - Node[node]->pos.x,rayinter.y - Node[node]->pos.y);
154: printf("%s_clip\n",Node[node]->shape.type == STRING? Node[node]->shape.value : Default_node.shape.value);
155: printf("%d add exch %d add exch\n",Node[node]->pos.y,Node[node]->pos.x);
156: }
157:
158: Point find_seg_midpoint(Point p0, Point p1) {
159: Point rv;
160: rv.x = (p0.x + p1.x) / 2;
161: rv.y = (p0.y + p1.y) / 2;
162: return rv;
163: }
164:
165: void emit_ps_edge(int node, DAG_edge_t *e) {
166: if (e->ink == invis_ink) return;
167: int fromnode = node, tonode = e->node;
168: if (e->ink != Current_PS_ink) emit_ps_setink(e->ink);
169: printf("%% %s %s edge\n",Node[fromnode]->name,Node[tonode]->name);
170: if (e->color != 0) {printf("gsave %s setdagcolor\n",e->color);}
171:
172: printf("newpath ");
173: emit_ps_nodeport(fromnode,e->top,e->splinept[0]); printf("moveto\n");
174: Point mp = find_seg_midpoint(e->splinept[0],e->splinept[1]);
175: if (e->flipped)
176: printf("%d %d makearrow\n",e->top.x,e->top.y);
177: printf(" %d %d lineto\n",mp.x,mp.y);
178:
179: for (int i = 1; e->splinept[i + 1].x >= 0; i++) {
180: Point mp = find_seg_midpoint(e->splinept[i],e->splinept[i+1]);
181: printf("%d %d 2 copy %d %d curveto\n",
182: e->splinept[i].x,e->splinept[i].y,mp.x,mp.y);
183: }
184: emit_ps_nodeport(tonode,e->bottom,e->splinept[i]);
185: printf("lineto currentpoint stroke moveto\n");
186: if (!e->flipped)
187: printf("%d %d makearrow\n",e->bottom.x,e->bottom.y);
188: printf("stroke\n");
189:
190: if (e->color != 0) {printf("grestore\n");}
191: emit_ps_edgelabel(e);
192: }
193:
194: void emit_ps_trailer() {
195: printf("restore\n");
196: }
197:
198: void emit_ps_page() {
199: printf("showpage\ngrestore\n");
200: }
201:
202: int n_ps_pages() {
203: int rv;
204: Pages_across = Xmax / PS_page_size.x;
205: if (Pages_across != (double)Xmax/PS_page_size.x) Pages_across++;
206: Pages_up = Ymax / PS_page_size.y;
207: if (Pages_up != (double)Ymax/PS_page_size.y) Pages_up++;
208: rv = Pages_across * Pages_up;
209: return rv;
210: }
211:
212: void emit_ps_set_page(int page) {
213: int row = page % Pages_up;
214: int col = (page - row) / Pages_up;
215: Page_min.x = col * PS_page_size.x;
216: Page_min.y = row * PS_page_size.y;
217: Page_max.x = Page_min.x + PS_page_size.x;
218: Page_max.y = Page_min.y + PS_page_size.y;
219: printf("%%%%Page: %s %d\n",Current_file.name,++Page_number);
220: printf("%%%%BoundingBox: %d %d %d %d\n",
221: PS_Margin.x-1,PS_Margin.y-1,PS_Margin.x+PS_page_size.x+1,PS_Margin.y+PS_page_size.y+1);
222: printf("gsave\n");
223: /* page coord before clip so it can be in the margin if ever change this */
224: if ((Pages_up > 1) || (Pages_across > 1))
225: printf("coordfont setfont %d %d moveto (%d,%d) show\n",
226: PS_Margin.x,PS_Margin.y,col,row);
227: printf("%d %d moveto %d 0 rlineto 0 %d rlineto %d 0 rlineto closepath clip newpath\n",
228: PS_Margin.x-1,PS_Margin.y-1,PS_page_size.x+2,PS_page_size.y+2,-PS_page_size.x-2); // off by one pixel?
229: printf("%d %d translate\n",PS_Margin.x - Page_min.x,PS_Margin.y - Page_min.y);
230: }
231:
232: int node_in_page(int node) {
233: int halfx = Node[node]->xsize / 2;
234: int halfy = Node[node]->ysize / 2;
235: for (int xcorner = Node[node]->pos.x - halfx; xcorner <= Node[node]->pos.x + halfx; xcorner += halfx) {
236: for (int ycorner = Node[node]->pos.y - halfy; ycorner <= Node[node]->pos.y + halfy; ycorner += halfy) {
237: if ((ycorner >= Page_min.y) && (ycorner <= Page_max.y)
238: && (xcorner >= Page_min.x) && (xcorner <= Page_max.x))
239: return 1;
240: }
241: }
242: return 0;
243: }
244:
245: int edge_in_page(DAG_edge_t* e) {
246: for (int i = 0; e->splinept[i+1].x >= 0; i++) {
247: Point pt0 = e->splinept[i];
248: Point pt1 = e->splinept[i+1];
249: if (!(((pt0.x < Page_min.x) && (pt1.x < Page_min.x)) ||
250: ((pt0.x > Page_max.x) && (pt1.x > Page_max.x)) ||
251: ((pt0.y < Page_min.y) && (pt1.y < Page_min.y)) ||
252: ((pt0.y > Page_max.y) && (pt1.y > Page_max.y)))) return 1;
253: }
254: return 0;
255: }
256:
257: void emit_ps() {
258: int node;
259: DAG_edge_t *e;
260: int maxpage;
261:
262: emit_ps_header();
263: maxpage = n_ps_pages();
264: for (int page = 0; page < maxpage; page++) {
265: emit_ps_set_page(page);
266: emit_ps_node_header();
267: for (node = 0; node < N; node++)
268: if (node_in_page(node)) emit_ps_node(node);
269: emit_ps_edge_header();
270: for (node = 0; node < N; node++)
271: for (e = Edge[node]; e; e = e->nextof())
272: if (edge_in_page(e)) emit_ps_edge(node,e);
273: emit_ps_page();
274: }
275: emit_ps_trailer();
276: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.