xref: /plan9-contrib/sys/src/cmd/postscript/tr2post/draw.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1*219b2ee8SDavid du Colombier #include <u.h>
2*219b2ee8SDavid du Colombier #include <libc.h>
3*219b2ee8SDavid du Colombier #include <bio.h>
4*219b2ee8SDavid du Colombier #include "../common/common.h"
5*219b2ee8SDavid du Colombier #include "tr2post.h"
6*219b2ee8SDavid du Colombier 
7*219b2ee8SDavid du Colombier BOOLEAN drawflag = FALSE;
8*219b2ee8SDavid du Colombier 
9*219b2ee8SDavid du Colombier void
10*219b2ee8SDavid du Colombier cover(double x, double y) {
11*219b2ee8SDavid du Colombier }
12*219b2ee8SDavid du Colombier 
13*219b2ee8SDavid du Colombier void
14*219b2ee8SDavid du Colombier drawspline(Biobufhdr *Bp, int flag) {	/* flag!=1 connect end points */
15*219b2ee8SDavid du Colombier 	int x[100], y[100];
16*219b2ee8SDavid du Colombier 	int i, N;
17*219b2ee8SDavid du Colombier /*
18*219b2ee8SDavid du Colombier  *
19*219b2ee8SDavid du Colombier  * Spline drawing routine for Postscript printers. The complicated stuff is
20*219b2ee8SDavid du Colombier  * handled by procedure Ds, which should be defined in the library file. I've
21*219b2ee8SDavid du Colombier  * seen wrong implementations of troff's spline drawing, so fo the record I'll
22*219b2ee8SDavid du Colombier  * write down the parametric equations and the necessary conversions to Bezier
23*219b2ee8SDavid du Colombier  * cubic splines (as used in Postscript).
24*219b2ee8SDavid du Colombier  *
25*219b2ee8SDavid du Colombier  *
26*219b2ee8SDavid du Colombier  * Parametric equation (x coordinate only):
27*219b2ee8SDavid du Colombier  *
28*219b2ee8SDavid du Colombier  *
29*219b2ee8SDavid du Colombier  *	    (x2 - 2 * x1 + x0)    2                    (x0 + x1)
30*219b2ee8SDavid du Colombier  *	x = ------------------ * t   + (x1 - x0) * t + ---------
31*219b2ee8SDavid du Colombier  *		    2					   2
32*219b2ee8SDavid du Colombier  *
33*219b2ee8SDavid du Colombier  *
34*219b2ee8SDavid du Colombier  * The coefficients in the Bezier cubic are,
35*219b2ee8SDavid du Colombier  *
36*219b2ee8SDavid du Colombier  *
37*219b2ee8SDavid du Colombier  *	A = 0
38*219b2ee8SDavid du Colombier  *	B = (x2 - 2 * x1 + x0) / 2
39*219b2ee8SDavid du Colombier  *	C = x1 - x0
40*219b2ee8SDavid du Colombier  *
41*219b2ee8SDavid du Colombier  *
42*219b2ee8SDavid du Colombier  * while the current point is,
43*219b2ee8SDavid du Colombier  *
44*219b2ee8SDavid du Colombier  *	current-point = (x0 + x1) / 2
45*219b2ee8SDavid du Colombier  *
46*219b2ee8SDavid du Colombier  * Using the relationships given in the Postscript manual (page 121) it's easy to
47*219b2ee8SDavid du Colombier  * see that the control points are given by,
48*219b2ee8SDavid du Colombier  *
49*219b2ee8SDavid du Colombier  *
50*219b2ee8SDavid du Colombier  *	x0' = (x0 + 5 * x1) / 6
51*219b2ee8SDavid du Colombier  *	x1' = (x2 + 5 * x1) / 6
52*219b2ee8SDavid du Colombier  *	x2' = (x1 + x2) / 2
53*219b2ee8SDavid du Colombier  *
54*219b2ee8SDavid du Colombier  *
55*219b2ee8SDavid du Colombier  * where the primed variables are the ones used by curveto. The calculations
56*219b2ee8SDavid du Colombier  * shown above are done in procedure Ds using the coordinates set up in both
57*219b2ee8SDavid du Colombier  * the x[] and y[] arrays.
58*219b2ee8SDavid du Colombier  *
59*219b2ee8SDavid du Colombier  * A simple test of whether your spline drawing is correct would be to use cip
60*219b2ee8SDavid du Colombier  * to draw a spline and some tangent lines at appropriate points and then print
61*219b2ee8SDavid du Colombier  * the file.
62*219b2ee8SDavid du Colombier  *
63*219b2ee8SDavid du Colombier  */
64*219b2ee8SDavid du Colombier 
65*219b2ee8SDavid du Colombier 	for (N=2; N<sizeof(x)/sizeof(x[0]); N++)
66*219b2ee8SDavid du Colombier 		if (Bgetfield(Bp, 'd', &x[N], 0)<=0 || Bgetfield(Bp, 'd', &y[N], 0)<=0)
67*219b2ee8SDavid du Colombier 			break;
68*219b2ee8SDavid du Colombier 
69*219b2ee8SDavid du Colombier 	x[0] = x[1] = hpos;
70*219b2ee8SDavid du Colombier 	y[0] = y[1] = vpos;
71*219b2ee8SDavid du Colombier 
72*219b2ee8SDavid du Colombier 	for (i = 1; i < N; i++) {
73*219b2ee8SDavid du Colombier 		x[i+1] += x[i];
74*219b2ee8SDavid du Colombier 		y[i+1] += y[i];
75*219b2ee8SDavid du Colombier 	}
76*219b2ee8SDavid du Colombier 
77*219b2ee8SDavid du Colombier 	x[N] = x[N-1];
78*219b2ee8SDavid du Colombier 	y[N] = y[N-1];
79*219b2ee8SDavid du Colombier 
80*219b2ee8SDavid du Colombier 	for (i = ((flag!=1)?0:1); i < ((flag!=1)?N-1:N-2); i++) {
81*219b2ee8SDavid du Colombier 		endstring();
82*219b2ee8SDavid du Colombier 		if (pageon())
83*219b2ee8SDavid du Colombier 			Bprint(Bstdout, "%d %d %d %d %d %d Ds\n", x[i], y[i], x[i+1], y[i+1], x[i+2], y[i+2]);
84*219b2ee8SDavid du Colombier /*		if (dobbox == TRUE) {		/* could be better */
85*219b2ee8SDavid du Colombier /*	    		cover((double)(x[i] + x[i+1])/2,(double)-(y[i] + y[i+1])/2);
86*219b2ee8SDavid du Colombier /*	    		cover((double)x[i+1], (double)-y[i+1]);
87*219b2ee8SDavid du Colombier /*	    		cover((double)(x[i+1] + x[i+2])/2, (double)-(y[i+1] + y[i+2])/2);
88*219b2ee8SDavid du Colombier /*		}
89*219b2ee8SDavid du Colombier  */
90*219b2ee8SDavid du Colombier 	}
91*219b2ee8SDavid du Colombier 
92*219b2ee8SDavid du Colombier 	hpos = x[N];			/* where troff expects to be */
93*219b2ee8SDavid du Colombier 	vpos = y[N];
94*219b2ee8SDavid du Colombier }
95*219b2ee8SDavid du Colombier 
96*219b2ee8SDavid du Colombier void
97*219b2ee8SDavid du Colombier draw(Biobufhdr *Bp) {
98*219b2ee8SDavid du Colombier 
99*219b2ee8SDavid du Colombier 	int r, x1, y1, x2, y2, i;
100*219b2ee8SDavid du Colombier 	int d1, d2;
101*219b2ee8SDavid du Colombier 
102*219b2ee8SDavid du Colombier 	drawflag = TRUE;
103*219b2ee8SDavid du Colombier 	r = Bgetrune(Bp);
104*219b2ee8SDavid du Colombier 	switch(r) {
105*219b2ee8SDavid du Colombier 	case 'l':
106*219b2ee8SDavid du Colombier 		if (Bgetfield(Bp, 'd', &x1, 0)<=0 || Bgetfield(Bp, 'd', &y1, 0)<=0 || Bgetfield(Bp, 'r', &i, 0)<=0)
107*219b2ee8SDavid du Colombier 			error(FATAL, "draw line function, destination coordinates not found.\n");
108*219b2ee8SDavid du Colombier 
109*219b2ee8SDavid du Colombier 		endstring();
110*219b2ee8SDavid du Colombier 		if (pageon())
111*219b2ee8SDavid du Colombier 			Bprint(Bstdout, "%d %d %d %d Dl\n", hpos, vpos, hpos+x1, vpos+y1);
112*219b2ee8SDavid du Colombier 		hpos += x1;
113*219b2ee8SDavid du Colombier 		vpos += y1;
114*219b2ee8SDavid du Colombier 		break;
115*219b2ee8SDavid du Colombier 	case 'c':
116*219b2ee8SDavid du Colombier 		if (Bgetfield(Bp, 'd', &d1, 0)<=0)
117*219b2ee8SDavid du Colombier 			error(FATAL, "draw circle function, diameter coordinates not found.\n");
118*219b2ee8SDavid du Colombier 
119*219b2ee8SDavid du Colombier 		endstring();
120*219b2ee8SDavid du Colombier 		if (pageon())
121*219b2ee8SDavid du Colombier 			Bprint(Bstdout, "%d %d %d %d De\n", hpos, vpos, d1, d1);
122*219b2ee8SDavid du Colombier 		hpos += d1;
123*219b2ee8SDavid du Colombier 		break;
124*219b2ee8SDavid du Colombier 	case 'e':
125*219b2ee8SDavid du Colombier 		if (Bgetfield(Bp, 'd', &d1, 0)<=0 || Bgetfield(Bp, 'd', &d2, 0)<=0)
126*219b2ee8SDavid du Colombier 			error(FATAL, "draw ellipse function, diameter coordinates not found.\n");
127*219b2ee8SDavid du Colombier 
128*219b2ee8SDavid du Colombier 		endstring();
129*219b2ee8SDavid du Colombier 		if (pageon())
130*219b2ee8SDavid du Colombier 			Bprint(Bstdout, "%d %d %d %d De\n", hpos, vpos, d1, d2);
131*219b2ee8SDavid du Colombier 		hpos += d1;
132*219b2ee8SDavid du Colombier 		break;
133*219b2ee8SDavid du Colombier 	case 'a':
134*219b2ee8SDavid du Colombier 		if (Bgetfield(Bp, 'd', &x1, 0)<=0 || Bgetfield(Bp, 'd', &y1, 0)<=0 || Bgetfield(Bp, 'd', &x2, 0)<=0 || Bgetfield(Bp, 'd', &y2, 0)<=0)
135*219b2ee8SDavid du Colombier 			error(FATAL, "draw arc function, coordinates not found.\n");
136*219b2ee8SDavid du Colombier 
137*219b2ee8SDavid du Colombier 		endstring();
138*219b2ee8SDavid du Colombier 		if (pageon())
139*219b2ee8SDavid du Colombier 			Bprint(Bstdout, "%d %d %d %d %d %d Da\n", hpos, vpos, x1, y1, x2, y2);
140*219b2ee8SDavid du Colombier 		hpos += x1 + x2;
141*219b2ee8SDavid du Colombier 		vpos += y1 + y2;
142*219b2ee8SDavid du Colombier 		break;
143*219b2ee8SDavid du Colombier 	case 'q':
144*219b2ee8SDavid du Colombier 		drawspline(Bp, 1);
145*219b2ee8SDavid du Colombier 		break;
146*219b2ee8SDavid du Colombier 	case '~':
147*219b2ee8SDavid du Colombier 		drawspline(Bp, 2);
148*219b2ee8SDavid du Colombier 		break;
149*219b2ee8SDavid du Colombier 	default:
150*219b2ee8SDavid du Colombier 		error(FATAL, "unknown draw function <%c>\n", r);
151*219b2ee8SDavid du Colombier 		break;
152*219b2ee8SDavid du Colombier 	}
153*219b2ee8SDavid du Colombier }
154