1 /***************************************************************************
2 JSPICE3 adaptation of Spice3e2 - Copyright (c) Stephen R. Whiteley 1992
3 Copyright 1990 Regents of the University of California.  All rights reserved.
4 Authors: 1988 Jeffrey M. Hsu
5          1992 Stephen R. Whiteley
6 ****************************************************************************/
7 
8 /*
9  * Postscript driver
10  */
11 
12 #include "spice.h"
13 #include "plotdev.h"
14 
15 static FILE *plotfile;
16 
17 #define SOLID 0
18 static char *linestyle[] = {
19                 "[]",           /* solid */
20                 "[1 2]",        /* dotted */
21                 "[7 7]",        /* longdashed */
22                 "[3 3]",        /* shortdashed */
23                 "[3 5 1 5]" };  /* dotdashed */
24 
25 typedef struct {
26     int lastlinestyle;      /* initial invalid value */
27     int strokecnt;          /* count line elements, avoid overflow */
28 } PSdevdep;
29 
30 #define DEVDEP(g) (*((PSdevdep *) (g)->devdep))
31 
32 static int Xoff, Yoff;
33 
34 /* line memory */
35 static int lastx ,lasty;
36 
37 
38 int
PS_Init()39 PS_Init()
40 {
41     dispdev->numlinestyles = 4;
42     dispdev->numcolors = 2;
43 
44     /* 8" X 10.5" drawable area */
45     dispdev->width = 576;       /* 8 * 72 */
46     dispdev->height = 756;      /* 10.5 * 72 */
47 
48     return (0);
49 }
50 
51 
52 int
PS_NewViewport(graph)53 PS_NewViewport(graph)
54 
55 /* devdep initially contains name of output file */
56 GRAPH *graph;
57 {
58 
59     plotfile = fopen((char*)graph->devdep, "w");
60 
61     if (!plotfile) {
62         perror(graph->devdep);
63         graph->devdep = (char *) NULL;
64         return (1);
65     }
66 
67     switch (graph->graphtype) {
68         default:
69         case GR_PLOT:
70         case GR_GRAF:
71         case GR_MPLT:
72             /* square plotting area */
73             graph->absolute.width = dispdev->width;
74             graph->absolute.height = dispdev->width;
75             Xoff = 18;
76             Yoff = 108;
77             break;
78         case GR_SCED:
79             /* full page plot */
80             graph->absolute.width = dispdev->width;
81             graph->absolute.height = dispdev->height;
82             Xoff = 18;
83             Yoff = 18;
84             break;
85     }
86 
87     /* start file off with a % */
88     fprintf(plotfile, "%%! nutmeg plot\n");
89 
90     /* reasonable values, used in gr_ for placement */
91     graph->fontwidth = 5;
92     graph->fontheight = 10;
93 
94     /* set up a reasonable font */
95     fprintf(plotfile, "/Helvetica findfont 10 scalefont setfont\n");
96 
97     graph->devdep = tmalloc(sizeof(PSdevdep));
98     DEVDEP(graph).lastlinestyle = -1;
99     DEVDEP(graph).strokecnt = 0;
100     graph->linestyle = -1;
101     lastx = -1;
102     lasty = -1;
103 
104     return (0);
105 }
106 
107 
108 int
PS_Close()109 PS_Close()
110 
111 {
112     return (0);
113 }
114 
115 
116 int
PS_Halt()117 PS_Halt()
118 {
119 
120     if (plotfile) {
121         if (DEVDEP(currentgraph).lastlinestyle != -1) {
122             /* haven't stroked last path */
123             fprintf(plotfile, "stroke\n");
124         }
125         fprintf(plotfile, "showpage\n");
126         fclose(plotfile);
127     }
128     return (0);
129 }
130 
131 
132 /* ARGSUSED */
133 int
PS_Pixel(x,y)134 PS_Pixel(x, y)
135 
136 int x, y;
137 {
138     int savedlstyle;
139 
140     savedlstyle = currentgraph->linestyle;
141     PS_SetLinestyle(SOLID);
142     if (DEVDEP(currentgraph).strokecnt > 499) {
143         if (DEVDEP(currentgraph).lastlinestyle == -1)
144             fprintf(plotfile, "newpath\n");
145         else
146             fprintf(plotfile, "stroke\n");
147         DEVDEP(currentgraph).strokecnt = 0;
148     }
149     fprintf(plotfile, "%d %d moveto\n", x+Xoff, y+Yoff);
150     fprintf(plotfile, "%d %d lineto\n", x+Xoff, y+Yoff+1);
151     (DEVDEP(currentgraph).strokecnt)++;
152     PS_SetLinestyle(savedlstyle);
153     return (0);
154 }
155 
156 
157 int
PS_Line(x1,y1,x2,y2)158 PS_Line(x1, y1, x2, y2)
159 
160 int x1, y1, x2, y2;
161 {
162     /* clip out unchanged points */
163     if (x1 == x2 && y1 == y2 && x1 == lastx && y1 == lasty)
164         return (0);
165 
166     if (currentgraph->linestyle == -1)
167         PS_SetLinestyle(SOLID);
168     if (DEVDEP(currentgraph).lastlinestyle != currentgraph->linestyle ||
169             DEVDEP(currentgraph).strokecnt > 499) {
170         if (DEVDEP(currentgraph).lastlinestyle == -1)
171             fprintf(plotfile, "newpath\n");
172         else
173             fprintf(plotfile, "stroke\n");
174         DEVDEP(currentgraph).strokecnt = 0;
175     }
176     if ((x1 != lastx) || (y1 != lasty) || !DEVDEP(currentgraph).strokecnt)
177         fprintf(plotfile, "%d %d moveto\n", x1+Xoff, y1+Yoff);
178     if ((x2 != x1) || (y2 != y1))
179         fprintf(plotfile, "%d %d lineto\n", x2+Xoff, y2+Yoff);
180 
181     /* validate cache */
182     lastx = x2;
183     lasty = y2;
184     DEVDEP(currentgraph).lastlinestyle = currentgraph->linestyle;
185     (DEVDEP(currentgraph).strokecnt)++;
186     return (0);
187 }
188 
189 
190 int
PS_Box(x1,y1,x2,y2)191 PS_Box(x1, y1, x2, y2)
192 int x1, y1, x2, y2;
193 {
194     PS_Line(x1,y1,x1,y2);
195     PS_Line(x1,y2,x2,y2);
196     PS_Line(x2,y2,x2,y1);
197     PS_Line(x2,y1,x1,y1);
198     return (0);
199 }
200 
201 
202 /* ARGSUSED */
203 int
PS_Arc(x0,y0,radius,theta1,theta2)204 PS_Arc(x0, y0, radius, theta1, theta2)
205 
206 int x0, y0, radius;
207 double theta1, theta2;
208 {
209     int a1, a2;
210 
211     if (theta1 >= theta2)
212         theta2 = 2 * M_PI + theta2;
213 
214     a1 = (180.0 / M_PI) * theta1;
215     a2 = (180.0 / M_PI) * theta2;
216 
217     if (currentgraph->linestyle == -1)
218         PS_SetLinestyle(SOLID);
219     if (DEVDEP(currentgraph).strokecnt) {
220         fprintf(plotfile, "stroke\n");
221         DEVDEP(currentgraph).strokecnt = 0;
222     }
223     else if (DEVDEP(currentgraph).lastlinestyle == -1) {
224         fprintf(plotfile, "newpath\n");
225         DEVDEP(currentgraph).lastlinestyle = currentgraph->linestyle;
226     }
227 
228     fprintf(plotfile, "%d %d %d %d %d arc\n",
229         x0+Xoff,y0+Yoff,radius,a1,a2);
230     fprintf(plotfile, "stroke\n");
231     lastx = -1;
232     lasty = -1;
233     return (0);
234 }
235 
236 
237 int
PS_Polygon(p)238 PS_Polygon(p)
239 POLYGON *p;
240 {
241     /* This is currently used only to print dots for sced.  The
242      * polygon code below looks bad and causes errors if the dots
243      * are too small, thus we use the specialized routine below.
244      */
245 
246     int *xy, x, y, savedlstyle;
247 
248     xy = (int*)p->xy;
249     if (xy[0] == xy[8]) {
250         x = xy[0];
251         y = xy[5];
252     }
253     else {
254         x = xy[4];
255         y = xy[1];
256     }
257     if (DEVDEP(currentgraph).strokecnt) {
258         fprintf(plotfile, "stroke\n");
259         DEVDEP(currentgraph).strokecnt = 0;
260     }
261     savedlstyle = currentgraph->linestyle;
262     PS_SetLinestyle(SOLID);
263     fprintf(plotfile,"%d %d moveto\n",x+1+Xoff,y+Yoff);
264     fprintf(plotfile,"%d %d 3 0 359 arc closepath fill\n",x+Xoff,y+Yoff);
265     PS_SetLinestyle(savedlstyle);
266     lastx = -1;
267     lasty = -1;
268     return (0);
269 
270 
271 /*
272     int *xy, nvert, savedlstyle;
273 
274     xy = (int*)p->xy;
275     nvert = p->nvertices;
276     savedlstyle = currentgraph->linestyle;
277     PS_SetLinestyle(SOLID);
278 
279     fprintf(plotfile, "%d %d moveto ", *xy+Xoff, *(xy+1)+Yoff);
280     xy += 2;
281     nvert--;
282     while (nvert--) {
283         fprintf(plotfile, "%d %d lineto\n", *xy+Xoff, *(xy+1)+Yoff);
284         xy += 2;
285     }
286     fprintf(plotfile,"closepath\nfill\n");
287     PS_SetLinestyle(savedlstyle);
288     return (0);
289 */
290 }
291 
292 
293 int
PS_Text(text,x,y)294 PS_Text(text, x, y)
295 
296 char *text;
297 int x, y;
298 {
299 
300     int savedlstyle;
301     char tbuf[BSIZE_SP], *s;
302 
303     if (text == NULL)
304         return (0);
305 
306     s = tbuf;
307     while (*text) {
308         if (*text == '(' || *text == ')' || *text == '\\')
309             *s++ = '\\';
310         *s++ = *text++;
311     }
312     *s = '\0';
313 
314     if (DEVDEP(currentgraph).strokecnt) {
315         fprintf(plotfile, "stroke\n");
316         DEVDEP(currentgraph).strokecnt = 0;
317     }
318     /* set linestyle to solid
319      * or may get funny color text on some plotters
320      */
321     savedlstyle = currentgraph->linestyle;
322     PS_SetLinestyle(SOLID);
323 
324     /* move to (x, y) */
325     fprintf(plotfile, "%d %d moveto\n", x+Xoff, y+Yoff);
326     fprintf(plotfile, "(%s) show\n", tbuf);
327 
328     /* restore old linestyle */
329     PS_SetLinestyle(savedlstyle);
330     lastx = -1;
331     lasty = -1;
332     return (0);
333 }
334 
335 
336 int
PS_SetLinestyle(linestyleid)337 PS_SetLinestyle(linestyleid)
338 
339 int linestyleid;
340 {
341 
342     /* special case
343         get it when PS_Text restores a -1 linestyle */
344     if (linestyleid == -1) {
345         currentgraph->linestyle = -1;
346         return (0);
347     }
348 
349     if (linestyleid < 0) {
350         internalerror("bad linestyleid");
351         return (0);
352     }
353 
354     if (linestyleid > dispdev->numlinestyles)
355         linestyleid = (linestyleid % dispdev->numlinestyles) + 1;
356 
357     if (currentgraph->linestyle != linestyleid) {
358         if (DEVDEP(currentgraph).strokecnt) {
359             fprintf(plotfile, "stroke\n");
360             DEVDEP(currentgraph).strokecnt = 0;
361             lastx = -1;
362             lasty = -1;
363         }
364         fprintf(plotfile, "%s 0 setdash\n", linestyle[linestyleid]);
365         currentgraph->linestyle = linestyleid;
366     }
367     return (0);
368 }
369 
370 
371 /* ARGSUSED */
372 int
PS_SetColor(colorid)373 PS_SetColor(colorid)
374 {
375     /* do nothing */
376     return (0);
377 }
378 
379 
380 int
PS_Update()381 PS_Update()
382 
383 {
384     fflush(plotfile);
385     return (0);
386 }
387 
388 
389 /* transformed text for sced hardcopy */
390 
391 int
PS_ScaledText(text,x,y,Xform)392 PS_ScaledText(text,x,y,Xform)
393 
394 char *text;
395 int x, y, Xform;
396 {
397     /* Xform code:
398      * 0x8: mirror x
399      * 0x4: mirror y
400      * 0x3: 0-no rotation, 1-90, 2-180, 3-270
401      */
402     int savedlstyle, deg;
403     char tbuf[BSIZE_SP], *s;
404 
405     if (text == NULL)
406         return (0);
407 
408     if (Xform == (char)0) {
409         PS_Text(text,x,y);
410         return (0);
411     }
412 
413     s = tbuf;
414     while (*text) {
415         if (*text == '(' || *text == ')' || *text == '\\')
416             *s++ = '\\';
417         *s++ = *text++;
418     }
419     *s = '\0';
420 
421     if (DEVDEP(currentgraph).strokecnt) {
422         fprintf(plotfile, "stroke\n");
423         DEVDEP(currentgraph).strokecnt = 0;
424     }
425 
426     /* set linestyle to solid
427      * or may get funny color text on some plotters
428      */
429     savedlstyle = currentgraph->linestyle;
430     PS_SetLinestyle(SOLID);
431 
432     fprintf(plotfile,"gsave\n");
433     fprintf(plotfile,"%d %d translate\n",x+Xoff,y+Yoff);
434     if (Xform & 12)
435         fprintf(plotfile,"%d %d scale\n",
436             (Xform & 8) ? -1 : 1, (Xform & 4) ? -1 : 1);
437     deg = (Xform & 3) * 90;
438     if (deg)
439         fprintf(plotfile,"%d rotate\n",deg);
440     fprintf(plotfile,"0 0 moveto\n");
441     fprintf(plotfile,"(%s) show\n",tbuf);
442     fprintf(plotfile,"grestore\n");
443 
444     /* restore old linestyle */
445     PS_SetLinestyle(savedlstyle);
446     lastx = -1;
447     lasty = -1;
448     return (0);
449 }
450