xref: /plan9/sys/src/cmd/pic/print.c (revision 14f51593fd82e19ba95969a8c07ff71131015979)
13e12c5d1SDavid du Colombier #include <stdio.h>
23e12c5d1SDavid du Colombier #include <math.h>
33e12c5d1SDavid du Colombier #include "pic.h"
43e12c5d1SDavid du Colombier #include "y.tab.h"
53e12c5d1SDavid du Colombier 
63e12c5d1SDavid du Colombier void dotext(obj *);
73e12c5d1SDavid du Colombier void dotline(double, double, double, double, int, double);
83e12c5d1SDavid du Colombier void dotbox(double, double, double, double, int, double);
93e12c5d1SDavid du Colombier void ellipse(double, double, double, double);
103e12c5d1SDavid du Colombier void circle(double, double, double);
113e12c5d1SDavid du Colombier void arc(double, double, double, double, double, double);
123e12c5d1SDavid du Colombier void arrow(double, double, double, double, double, double, double, int);
133e12c5d1SDavid du Colombier void line(double, double, double, double);
143e12c5d1SDavid du Colombier void box(double, double, double, double);
153e12c5d1SDavid du Colombier void spline(double x, double y, double n, ofloat *p, int dashed, double ddval);
163e12c5d1SDavid du Colombier void move(double, double);
173e12c5d1SDavid du Colombier void troff(char *);
183e12c5d1SDavid du Colombier void dot(void);
197dd7cddfSDavid du Colombier void fillstart(double), fillend(int vis, int noedge);
203e12c5d1SDavid du Colombier 
print(void)213e12c5d1SDavid du Colombier void print(void)
223e12c5d1SDavid du Colombier {
233e12c5d1SDavid du Colombier 	obj *p;
243e12c5d1SDavid du Colombier 	int i, j, k, m;
257dd7cddfSDavid du Colombier 	int fill, vis, invis;
263e12c5d1SDavid du Colombier 	double x0, y0, x1, y1, ox, oy, dx, dy, ndx, ndy;
273e12c5d1SDavid du Colombier 
283e12c5d1SDavid du Colombier 	for (i = 0; i < nobj; i++) {
293e12c5d1SDavid du Colombier 		p = objlist[i];
303e12c5d1SDavid du Colombier 		ox = p->o_x;
313e12c5d1SDavid du Colombier 		oy = p->o_y;
323e12c5d1SDavid du Colombier 		if (p->o_count >= 1)
333e12c5d1SDavid du Colombier 			x1 = p->o_val[0];
343e12c5d1SDavid du Colombier 		if (p->o_count >= 2)
353e12c5d1SDavid du Colombier 			y1 = p->o_val[1];
363e12c5d1SDavid du Colombier 		m = p->o_mode;
377dd7cddfSDavid du Colombier 		fill = p->o_attr & FILLBIT;
387dd7cddfSDavid du Colombier 		invis = p->o_attr & INVIS;
397dd7cddfSDavid du Colombier 		vis = !invis;
403e12c5d1SDavid du Colombier 		switch (p->o_type) {
413e12c5d1SDavid du Colombier 		case TROFF:
423e12c5d1SDavid du Colombier 			troff(text[p->o_nt1].t_val);
433e12c5d1SDavid du Colombier 			break;
443e12c5d1SDavid du Colombier 		case BOX:
453e12c5d1SDavid du Colombier 		case BLOCK:
463e12c5d1SDavid du Colombier 			x0 = ox - x1 / 2;
473e12c5d1SDavid du Colombier 			y0 = oy - y1 / 2;
483e12c5d1SDavid du Colombier 			x1 = ox + x1 / 2;
493e12c5d1SDavid du Colombier 			y1 = oy + y1 / 2;
507dd7cddfSDavid du Colombier 			if (fill) {
513e12c5d1SDavid du Colombier 				move(x0, y0);
523e12c5d1SDavid du Colombier 				fillstart(p->o_fillval);
533e12c5d1SDavid du Colombier 			}
54*14f51593SDavid du Colombier 			if (p->o_type == BLOCK){
557dd7cddfSDavid du Colombier 				;	/* nothing at all */
56*14f51593SDavid du Colombier 			}else if (invis && !fill){
573e12c5d1SDavid du Colombier 				;	/* nothing at all */
58*14f51593SDavid du Colombier 			}else if (p->o_attr & (DOTBIT|DASHBIT))
593e12c5d1SDavid du Colombier 				dotbox(x0, y0, x1, y1, p->o_attr, p->o_ddval);
603e12c5d1SDavid du Colombier 			else
613e12c5d1SDavid du Colombier 				box(x0, y0, x1, y1);
627dd7cddfSDavid du Colombier 			if (fill)
637dd7cddfSDavid du Colombier 				fillend(vis, fill);
643e12c5d1SDavid du Colombier 			move(ox, oy);
653e12c5d1SDavid du Colombier 			dotext(p);	/* if there are any text strings */
663e12c5d1SDavid du Colombier 			if (ishor(m))
673e12c5d1SDavid du Colombier 				move(isright(m) ? x1 : x0, oy);	/* right side */
683e12c5d1SDavid du Colombier 			else
693e12c5d1SDavid du Colombier 				move(ox, isdown(m) ? y0 : y1);	/* bottom */
703e12c5d1SDavid du Colombier 			break;
713e12c5d1SDavid du Colombier 		case BLOCKEND:
723e12c5d1SDavid du Colombier 			break;
733e12c5d1SDavid du Colombier 		case CIRCLE:
747dd7cddfSDavid du Colombier 			if (fill)
753e12c5d1SDavid du Colombier 				fillstart(p->o_fillval);
767dd7cddfSDavid du Colombier 			if (vis || fill)
773e12c5d1SDavid du Colombier 				circle(ox, oy, x1);
787dd7cddfSDavid du Colombier 			if (fill)
797dd7cddfSDavid du Colombier 				fillend(vis, fill);
803e12c5d1SDavid du Colombier 			move(ox, oy);
813e12c5d1SDavid du Colombier 			dotext(p);
823e12c5d1SDavid du Colombier 			if (ishor(m))
833e12c5d1SDavid du Colombier 				move(ox + isright(m) ? x1 : -x1, oy);
843e12c5d1SDavid du Colombier 			else
853e12c5d1SDavid du Colombier 				move(ox, oy + isup(m) ? x1 : -x1);
863e12c5d1SDavid du Colombier 			break;
873e12c5d1SDavid du Colombier 		case ELLIPSE:
887dd7cddfSDavid du Colombier 			if (fill)
893e12c5d1SDavid du Colombier 				fillstart(p->o_fillval);
907dd7cddfSDavid du Colombier 			if (vis || fill)
913e12c5d1SDavid du Colombier 				ellipse(ox, oy, x1, y1);
927dd7cddfSDavid du Colombier 			if (fill)
937dd7cddfSDavid du Colombier 				fillend(vis, fill);
943e12c5d1SDavid du Colombier 			move(ox, oy);
953e12c5d1SDavid du Colombier 			dotext(p);
963e12c5d1SDavid du Colombier 			if (ishor(m))
973e12c5d1SDavid du Colombier 				move(ox + isright(m) ? x1 : -x1, oy);
983e12c5d1SDavid du Colombier 			else
993e12c5d1SDavid du Colombier 				move(ox, oy - isdown(m) ? y1 : -y1);
1003e12c5d1SDavid du Colombier 			break;
1013e12c5d1SDavid du Colombier 		case ARC:
1027dd7cddfSDavid du Colombier 			if (fill) {
1033e12c5d1SDavid du Colombier 				move(ox, oy);
1047dd7cddfSDavid du Colombier 				fillstart(p->o_fillval);
1057dd7cddfSDavid du Colombier 			}
1063e12c5d1SDavid du Colombier 			if (p->o_attr & HEAD1)
1073e12c5d1SDavid du Colombier 				arrow(x1 - (y1 - oy), y1 + (x1 - ox),
1083e12c5d1SDavid du Colombier 				      x1, y1, p->o_val[4], p->o_val[5], p->o_val[5]/p->o_val[6]/2, p->o_nhead);
1097dd7cddfSDavid du Colombier                         if (invis && !fill)
1103e12c5d1SDavid du Colombier                                 /* probably wrong when it's cw */
1113e12c5d1SDavid du Colombier                                 move(x1, y1);
1123e12c5d1SDavid du Colombier                         else
1133e12c5d1SDavid du Colombier 				arc(ox, oy, x1, y1, p->o_val[2], p->o_val[3]);
1143e12c5d1SDavid du Colombier 			if (p->o_attr & HEAD2)
1153e12c5d1SDavid du Colombier 				arrow(p->o_val[2] + p->o_val[3] - oy, p->o_val[3] - (p->o_val[2] - ox),
1163e12c5d1SDavid du Colombier 				      p->o_val[2], p->o_val[3], p->o_val[4], p->o_val[5], -p->o_val[5]/p->o_val[6]/2, p->o_nhead);
1177dd7cddfSDavid du Colombier 			if (fill)
1187dd7cddfSDavid du Colombier 				fillend(vis, fill);
1193e12c5d1SDavid du Colombier 			if (p->o_attr & CW_ARC)
1203e12c5d1SDavid du Colombier 				move(x1, y1);	/* because drawn backwards */
1217dd7cddfSDavid du Colombier 			move(ox, oy);
1227dd7cddfSDavid du Colombier 			dotext(p);
1233e12c5d1SDavid du Colombier 			break;
1243e12c5d1SDavid du Colombier 		case LINE:
1253e12c5d1SDavid du Colombier 		case ARROW:
1263e12c5d1SDavid du Colombier 		case SPLINE:
1277dd7cddfSDavid du Colombier 			if (fill) {
1287dd7cddfSDavid du Colombier 				move(ox, oy);
1297dd7cddfSDavid du Colombier 				fillstart(p->o_fillval);
1307dd7cddfSDavid du Colombier 			}
1317dd7cddfSDavid du Colombier 			if (vis && p->o_attr & HEAD1)
1323e12c5d1SDavid du Colombier 				arrow(ox + p->o_val[5], oy + p->o_val[6], ox, oy, p->o_val[2], p->o_val[3], 0.0, p->o_nhead);
1337dd7cddfSDavid du Colombier                         if (invis && !fill)
1343e12c5d1SDavid du Colombier                                 move(x1, y1);
1353e12c5d1SDavid du Colombier 			else if (p->o_type == SPLINE)
1363e12c5d1SDavid du Colombier 				spline(ox, oy, p->o_val[4], &p->o_val[5], p->o_attr & (DOTBIT|DASHBIT), p->o_ddval);
1373e12c5d1SDavid du Colombier 			else {
1383e12c5d1SDavid du Colombier 				dx = ox;
1393e12c5d1SDavid du Colombier 				dy = oy;
1403e12c5d1SDavid du Colombier 				for (k=0, j=5; k < p->o_val[4]; k++, j += 2) {
1413e12c5d1SDavid du Colombier 					ndx = dx + p->o_val[j];
1423e12c5d1SDavid du Colombier 					ndy = dy + p->o_val[j+1];
1433e12c5d1SDavid du Colombier 					if (p->o_attr & (DOTBIT|DASHBIT))
1443e12c5d1SDavid du Colombier 						dotline(dx, dy, ndx, ndy, p->o_attr, p->o_ddval);
1453e12c5d1SDavid du Colombier 					else
1463e12c5d1SDavid du Colombier 						line(dx, dy, ndx, ndy);
1473e12c5d1SDavid du Colombier 					dx = ndx;
1483e12c5d1SDavid du Colombier 					dy = ndy;
1493e12c5d1SDavid du Colombier 				}
1503e12c5d1SDavid du Colombier 			}
1517dd7cddfSDavid du Colombier 			if (vis && p->o_attr & HEAD2) {
1523e12c5d1SDavid du Colombier 				dx = ox;
1533e12c5d1SDavid du Colombier 				dy = oy;
1543e12c5d1SDavid du Colombier 				for (k = 0, j = 5; k < p->o_val[4] - 1; k++, j += 2) {
1553e12c5d1SDavid du Colombier 					dx += p->o_val[j];
1563e12c5d1SDavid du Colombier 					dy += p->o_val[j+1];
1573e12c5d1SDavid du Colombier 				}
1583e12c5d1SDavid du Colombier 				arrow(dx, dy, x1, y1, p->o_val[2], p->o_val[3], 0.0, p->o_nhead);
1593e12c5d1SDavid du Colombier 			}
1607dd7cddfSDavid du Colombier 			if (fill)
1617dd7cddfSDavid du Colombier 				fillend(vis, fill);
1627dd7cddfSDavid du Colombier 			move((ox + x1)/2, (oy + y1)/2);	/* center */
1637dd7cddfSDavid du Colombier 			dotext(p);
1643e12c5d1SDavid du Colombier 			break;
1653e12c5d1SDavid du Colombier 		case MOVE:
1667dd7cddfSDavid du Colombier 			move(ox, oy);
1677dd7cddfSDavid du Colombier 			break;
1683e12c5d1SDavid du Colombier 		case TEXT:
1693e12c5d1SDavid du Colombier 			move(ox, oy);
1707dd7cddfSDavid du Colombier                         if (vis)
1713e12c5d1SDavid du Colombier 				dotext(p);
1723e12c5d1SDavid du Colombier 			break;
1733e12c5d1SDavid du Colombier 		}
1743e12c5d1SDavid du Colombier 	}
1753e12c5d1SDavid du Colombier }
1763e12c5d1SDavid du Colombier 
dotline(double x0,double y0,double x1,double y1,int ddtype,double ddval)1773e12c5d1SDavid du Colombier void dotline(double x0, double y0, double x1, double y1, int ddtype, double ddval) /* dotted line */
1783e12c5d1SDavid du Colombier {
1793e12c5d1SDavid du Colombier 	static double prevval = 0.05;	/* 20 per inch by default */
1803e12c5d1SDavid du Colombier 	int i, numdots;
1813e12c5d1SDavid du Colombier 	double a, b, dx, dy;
1823e12c5d1SDavid du Colombier 
1833e12c5d1SDavid du Colombier 	if (ddval == 0)
1843e12c5d1SDavid du Colombier 		ddval = prevval;
1853e12c5d1SDavid du Colombier 	prevval = ddval;
1863e12c5d1SDavid du Colombier 	/* don't save dot/dash value */
1873e12c5d1SDavid du Colombier 	dx = x1 - x0;
1883e12c5d1SDavid du Colombier 	dy = y1 - y0;
1893e12c5d1SDavid du Colombier 	if (ddtype & DOTBIT) {
1903e12c5d1SDavid du Colombier 		numdots = sqrt(dx*dx + dy*dy) / prevval + 0.5;
1913e12c5d1SDavid du Colombier 		if (numdots > 0)
1923e12c5d1SDavid du Colombier 			for (i = 0; i <= numdots; i++) {
1933e12c5d1SDavid du Colombier 				a = (double) i / (double) numdots;
1943e12c5d1SDavid du Colombier 				move(x0 + (a * dx), y0 + (a * dy));
1953e12c5d1SDavid du Colombier 				dot();
1963e12c5d1SDavid du Colombier 			}
1973e12c5d1SDavid du Colombier 	} else if (ddtype & DASHBIT) {
1983e12c5d1SDavid du Colombier 		double d, dashsize, spacesize;
1993e12c5d1SDavid du Colombier 		d = sqrt(dx*dx + dy*dy);
2003e12c5d1SDavid du Colombier 		if (d <= 2 * prevval) {
2013e12c5d1SDavid du Colombier 			line(x0, y0, x1, y1);
2023e12c5d1SDavid du Colombier 			return;
2033e12c5d1SDavid du Colombier 		}
2043e12c5d1SDavid du Colombier 		numdots = d / (2 * prevval) + 1;	/* ceiling */
2053e12c5d1SDavid du Colombier 		dashsize = prevval;
2063e12c5d1SDavid du Colombier 		spacesize = (d - numdots * dashsize) / (numdots - 1);
2073e12c5d1SDavid du Colombier 		for (i = 0; i < numdots-1; i++) {
2083e12c5d1SDavid du Colombier 			a = i * (dashsize + spacesize) / d;
2093e12c5d1SDavid du Colombier 			b = a + dashsize / d;
2103e12c5d1SDavid du Colombier 			line(x0 + (a*dx), y0 + (a*dy), x0 + (b*dx), y0 + (b*dy));
2113e12c5d1SDavid du Colombier 			a = b;
2123e12c5d1SDavid du Colombier 			b = a + spacesize / d;
2133e12c5d1SDavid du Colombier 			move(x0 + (a*dx), y0 + (a*dy));
2143e12c5d1SDavid du Colombier 		}
2153e12c5d1SDavid du Colombier 		line(x0 + (b * dx), y0 + (b * dy), x1, y1);
2163e12c5d1SDavid du Colombier 	}
2173e12c5d1SDavid du Colombier 	prevval = 0.05;
2183e12c5d1SDavid du Colombier }
2193e12c5d1SDavid du Colombier 
dotbox(double x0,double y0,double x1,double y1,int ddtype,double ddval)2203e12c5d1SDavid du Colombier void dotbox(double x0, double y0, double x1, double y1, int ddtype, double ddval)	/* dotted or dashed box */
2213e12c5d1SDavid du Colombier {
2223e12c5d1SDavid du Colombier 	dotline(x0, y0, x1, y0, ddtype, ddval);
2233e12c5d1SDavid du Colombier 	dotline(x1, y0, x1, y1, ddtype, ddval);
2243e12c5d1SDavid du Colombier 	dotline(x1, y1, x0, y1, ddtype, ddval);
2253e12c5d1SDavid du Colombier 	dotline(x0, y1, x0, y0, ddtype, ddval);
2263e12c5d1SDavid du Colombier }
2273e12c5d1SDavid du Colombier 
dotext(obj * p)2283e12c5d1SDavid du Colombier void dotext(obj *p)	/* print text strings of p in proper vertical spacing */
2293e12c5d1SDavid du Colombier {
2303e12c5d1SDavid du Colombier 	int i, nhalf;
2313e12c5d1SDavid du Colombier 	void label(char *, int, int);
2323e12c5d1SDavid du Colombier 
2333e12c5d1SDavid du Colombier 	nhalf = p->o_nt2 - p->o_nt1 - 1;
2343e12c5d1SDavid du Colombier 	for (i = p->o_nt1; i < p->o_nt2; i++) {
2353e12c5d1SDavid du Colombier 		label(text[i].t_val, text[i].t_type, nhalf);
2363e12c5d1SDavid du Colombier 		nhalf -= 2;
2373e12c5d1SDavid du Colombier 	}
2383e12c5d1SDavid du Colombier }
239