xref: /plan9/sys/src/cmd/pic/pltroff.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 #include <stdio.h>
2 #include <math.h>
3 #include <string.h>
4 #include "pic.h"
5 extern int dbg;
6 
7 #define	abs(n)	(n >= 0 ? n : -(n))
8 #define	max(x,y)	((x)>(y) ? (x) : (y))
9 
10 char	*textshift = "\\v'.2m'";	/* move text this far down */
11 
12 /* scaling stuff defined by s command as X0,Y0 to X1,Y1 */
13 /* output dimensions set by -l,-w options to 0,0 to hmax, vmax */
14 /* default output is 6x6 inches */
15 
16 
17 double	xscale;
18 double	yscale;
19 
20 double	hpos	= 0;	/* current horizontal position in output coordinate system */
21 double	vpos	= 0;	/* current vertical position; 0 is top of page */
22 
23 double	htrue	= 0;	/* where we really are */
24 double	vtrue	= 0;
25 
26 double	X0, Y0;		/* left bottom of input */
27 double	X1, Y1;		/* right top of input */
28 
29 double	hmax;		/* right end of output */
30 double	vmax;		/* top of output (down is positive) */
31 
32 extern	double	deltx;
33 extern	double	delty;
34 extern	double	xmin, ymin, xmax, ymax;
35 
36 double	xconv(double), yconv(double), xsc(double), ysc(double);
37 void	space(double, double, double, double);
38 void	hgoto(double), vgoto(double), hmot(double), vmot(double);
39 void	move(double, double), movehv(double, double);
40 void	cont(double, double);
41 
openpl(char * s)42 void openpl(char *s)	/* initialize device; s is residue of .PS invocation line */
43 {
44 	double maxw, maxh, ratio = 1;
45 	double odeltx = deltx, odelty = delty;
46 
47 	hpos = vpos = 0;
48 	maxw = getfval("maxpswid");
49 	maxh = getfval("maxpsht");
50 	if (deltx > maxw) {	/* shrink horizontal */
51 		ratio = maxw / deltx;
52 		deltx *= ratio;
53 		delty *= ratio;
54 	}
55 	if (delty > maxh) {	/* shrink vertical */
56 		ratio = maxh / delty;
57 		deltx *= ratio;
58 		delty *= ratio;
59 	}
60 	if (ratio != 1) {
61 		fprintf(stderr, "pic: %g X %g picture shrunk to", odeltx, odelty);
62 		fprintf(stderr, " %g X %g\n", deltx, delty);
63 	}
64 	space(xmin, ymin, xmax, ymax);
65 	printf("... %g %g %g %g\n", xmin, ymin, xmax, ymax);
66 	printf("... %.3fi %.3fi %.3fi %.3fi\n",
67 		xconv(xmin), yconv(ymin), xconv(xmax), yconv(ymax));
68 	printf(".nr 00 \\n(.u\n");
69 	printf(".nf\n");
70 	printf(".PS %.3fi %.3fi %s", yconv(ymin), xconv(xmax), s);
71 		/* assumes \n comes as part of s */
72 }
73 
space(double x0,double y0,double x1,double y1)74 void space(double x0, double y0, double x1, double y1)	/* set limits of page */
75 {
76 	X0 = x0;
77 	Y0 = y0;
78 	X1 = x1;
79 	Y1 = y1;
80 	xscale = deltx == 0.0 ? 1.0 : deltx / (X1-X0);
81 	yscale = delty == 0.0 ? 1.0 : delty / (Y1-Y0);
82 }
83 
xconv(double x)84 double xconv(double x)	/* convert x from external to internal form */
85 {
86 	return (x-X0) * xscale;
87 }
88 
xsc(double x)89 double xsc(double x)	/* convert x from external to internal form, scaling only */
90 {
91 
92 	return (x) * xscale;
93 }
94 
yconv(double y)95 double yconv(double y)	/* convert y from external to internal form */
96 {
97 	return (Y1-y) * yscale;
98 }
99 
ysc(double y)100 double ysc(double y)	/* convert y from external to internal form, scaling only */
101 {
102 	return (y) * yscale;
103 }
104 
closepl(char * PEline)105 void closepl(char *PEline)	/* clean up after finished */
106 {
107 	movehv(0.0, 0.0);	/* get back to where we started */
108 	if (strchr(PEline, 'F') == NULL) {
109 		printf(".sp 1+%.3fi\n", yconv(ymin));
110 	}
111 	printf("%s\n", PEline);
112 	printf(".if \\n(00 .fi\n");
113 }
114 
move(double x,double y)115 void move(double x, double y)	/* go to position x, y in external coords */
116 {
117 	hgoto(xconv(x));
118 	vgoto(yconv(y));
119 }
120 
movehv(double h,double v)121 void movehv(double h, double v)	/* go to internal position h, v */
122 {
123 	hgoto(h);
124 	vgoto(v);
125 }
126 
hmot(double n)127 void hmot(double n)	/* generate n units of horizontal motion */
128 {
129 	hpos += n;
130 }
131 
vmot(double n)132 void vmot(double n)	/* generate n units of vertical motion */
133 {
134 	vpos += n;
135 }
136 
hgoto(double n)137 void hgoto(double n)
138 {
139 	hpos = n;
140 }
141 
vgoto(double n)142 void vgoto(double n)
143 {
144 	vpos = n;
145 }
146 
fabs(double x)147 double fabs(double x)
148 {
149 	return x < 0 ? -x : x;
150 }
151 
hvflush(void)152 void hvflush(void)	/* get to proper point for output */
153 {
154 	if (fabs(hpos-htrue) >= 0.0005) {
155 		printf("\\h'%.3fi'", hpos - htrue);
156 		htrue = hpos;
157 	}
158 	if (fabs(vpos-vtrue) >= 0.0005) {
159 		printf("\\v'%.3fi'", vpos - vtrue);
160 		vtrue = vpos;
161 	}
162 }
163 
flyback(void)164 void flyback(void)	/* return to upper left corner (entry point) */
165 {
166 	printf(".sp -1\n");
167 	htrue = vtrue = 0;
168 }
169 
printlf(int n,char * f)170 void printlf(int n, char *f)
171 {
172 	if (f)
173 		printf(".lf %d %s\n", n, f);
174 	else
175 		printf(".lf %d\n", n);
176 }
177 
troff(char * s)178 void troff(char *s)	/* output troff right here */
179 {
180 	printf("%s\n", s);
181 }
182 
label(char * s,int t,int nh)183 void label(char *s, int t, int nh)	/* text s of type t nh half-lines up */
184 {
185 	int q;
186 	char *p;
187 
188 	if (!s)
189 		return;
190 	hvflush();
191 	dprintf("label: %s %o %d\n", s, t, nh);
192 	printf("%s", textshift);	/* shift down and left */
193 	if (t & ABOVE)
194 		nh++;
195 	else if (t & BELOW)
196 		nh--;
197 	if (nh)
198 		printf("\\v'%du*\\n(.vu/2u'", -nh);
199 	/* just in case the text contains a quote: */
200 	q = 0;
201 	for (p = s; *p; p++)
202 		if (*p == '\'') {
203 			q = 1;
204 			break;
205 		}
206 	t &= ~(ABOVE|BELOW);
207 	if (t & LJUST) {
208 		printf("%s", s);
209 	} else if (t & RJUST) {
210 		if (q)
211 			printf("\\h\\(ts-\\w\\(ts%s\\(tsu\\(ts%s", s, s);
212 		else
213 			printf("\\h'-\\w'%s'u'%s", s, s);
214 	} else {	/* CENTER */
215 		if (q)
216 			printf("\\h\\(ts-\\w\\(ts%s\\(tsu/2u\\(ts%s", s, s);
217 		else
218 			printf("\\h'-\\w'%s'u/2u'%s", s, s);
219 	}
220 	printf("\n");
221 	flyback();
222 }
223 
line(double x0,double y0,double x1,double y1)224 void line(double x0, double y0, double x1, double y1)	/* draw line from x0,y0 to x1,y1 */
225 {
226 	move(x0, y0);
227 	cont(x1, y1);
228 }
229 
arrow(double x0,double y0,double x1,double y1,double w,double h,double ang,int nhead)230 void arrow(double x0, double y0, double x1, double y1, double w, double h,
231 	 double ang, int nhead) 	/* draw arrow (without shaft) */
232 {
233 	double alpha, rot, drot, hyp;
234 	double dx, dy;
235 	int i;
236 
237 	rot = atan2(w / 2, h);
238 	hyp = sqrt(w/2 * w/2 + h * h);
239 	alpha = atan2(y1-y0, x1-x0) + ang;
240 	if (nhead < 2)
241 		nhead = 2;
242 	dprintf("rot=%g, hyp=%g, alpha=%g\n", rot, hyp, alpha);
243 	for (i = nhead-1; i >= 0; i--) {
244 		drot = 2 * rot / (double) (nhead-1) * (double) i;
245 		dx = hyp * cos(alpha + PI - rot + drot);
246 		dy = hyp * sin(alpha + PI - rot + drot);
247 		dprintf("dx,dy = %g,%g\n", dx, dy);
248 		line(x1+dx, y1+dy, x1, y1);
249 	}
250 }
251 
252 double lastgray = 0;
253 
fillstart(double v)254 void fillstart(double v)	/* this works only for postscript, obviously. */
255 {				/* uses drechsler's dpost conventions... */
256 	hvflush();
257 	printf("\\X'BeginObject %g setgray'\n", v);
258 	lastgray = v;
259 	flyback();
260 }
261 
fillend(int vis,int fill)262 void fillend(int vis, int fill)
263 {
264 	hvflush();
265 	printf("\\X'EndObject gsave eofill grestore %g setgray %s'\n",
266 		!vis ? lastgray : 0.0,
267 		vis ? "stroke" : "");
268 	/* for dashed: [50] 0 setdash just before stroke. */
269 	lastgray = 0;
270 	flyback();
271 }
272 
box(double x0,double y0,double x1,double y1)273 void box(double x0, double y0, double x1, double y1)
274 {
275 	move(x0, y0);
276 	cont(x0, y1);
277 	cont(x1, y1);
278 	cont(x1, y0);
279 	cont(x0, y0);
280 }
281 
cont(double x,double y)282 void cont(double x, double y)	/* continue line from here to x,y */
283 {
284 	double h1, v1;
285 	double dh, dv;
286 
287 	h1 = xconv(x);
288 	v1 = yconv(y);
289 	dh = h1 - hpos;
290 	dv = v1 - vpos;
291 	hvflush();
292 	printf("\\D'l%.3fi %.3fi'\n", dh, dv);
293 	flyback();	/* expensive */
294 	hpos = h1;
295 	vpos = v1;
296 }
297 
circle(double x,double y,double r)298 void circle(double x, double y, double r)
299 {
300 	move(x-r, y);
301 	hvflush();
302 	printf("\\D'c%.3fi'\n", xsc(2 * r));
303 	flyback();
304 }
305 
spline(double x,double y,double n,ofloat * p,int dashed,double ddval)306 void spline(double x, double y, double n, ofloat *p, int dashed, double ddval)
307 {
308 	int i;
309 	double dx, dy;
310 	double xerr, yerr;
311 
312 	move(x, y);
313 	hvflush();
314 	xerr = yerr = 0.0;
315 	printf("\\D'~");
316 	for (i = 0; i < 2 * n; i += 2) {
317 		dx = xsc(xerr += p[i]);
318 		xerr -= dx/xscale;
319 		dy = ysc(yerr += p[i+1]);
320 		yerr -= dy/yscale;
321 		printf(" %.3fi %.3fi", dx, -dy);	/* WATCH SIGN */
322 	}
323 	printf("'\n");
324 	flyback();
325 }
326 
ellipse(double x,double y,double r1,double r2)327 void ellipse(double x, double y, double r1, double r2)
328 {
329 	double ir1, ir2;
330 
331 	move(x-r1, y);
332 	hvflush();
333 	ir1 = xsc(r1);
334 	ir2 = ysc(r2);
335 	printf("\\D'e%.3fi %.3fi'\n", 2 * ir1, 2 * abs(ir2));
336 	flyback();
337 }
338 
arc(double x,double y,double x0,double y0,double x1,double y1)339 void arc(double x, double y, double x0, double y0, double x1, double y1)	/* draw arc with center x,y */
340 {
341 
342 	move(x0, y0);
343 	hvflush();
344 	printf("\\D'a%.3fi %.3fi %.3fi %.3fi'\n",
345 		xsc(x-x0), -ysc(y-y0), xsc(x1-x), -ysc(y1-y));	/* WATCH SIGNS */
346 	flyback();
347 }
348 
dot(void)349 void dot(void) {
350 	hvflush();
351 	/* what character to draw here depends on what's available. */
352 	/* on the 202, l. is good but small. */
353 	/* in general, use a smaller, shifted period and hope */
354 
355 	printf("\\&\\f1\\h'-.1m'\\v'.03m'\\s-3.\\s+3\\fP\n");
356 	flyback();
357 }
358