#include <stdio.h>
#include <math.h>
extern int cflag;

#define	abs(n)	(n >= 0 ? n : -(n))
#define	max(x,y)	((x)>(y) ? (x) : (y))
#define	PI	3.141592654
#define	PI2	PI/2

extern	int	res;

#define	DEV202	1
#define	DEVAPS	2
#define	DEVCAT	3
#define DEVCAN	4
extern	int	devtype;
int	minline	= 245;	/* draw lines shorter than this with dots on 202 */
		/* ought to be point-size dependent, but what's that? */
		/* this is big enough to handle 202 up to 36 points */

int	useDline	= 1;	/* if set, produce \D for all lines */
extern	float	hshift;	/* how much to move left by for text */
extern	float	vshift;	/* how much down */

/* scaling stuff, specific to typesetter */
/* defined by s command as X0,Y0 to X1,Y1 */
/* output dimensions set by -l,-w options to 0,0 to hmax, vmax */
/* default output is 6x6 inches */


float	xscale;
float	yscale;

int	hpos	= 0;	/* current horizontal position in output coordinate system */
int	vpos	= 0;	/* current vertical position; 0 is top of page */

int	htrue	= 0;	/* where we really are */
int	vtrue	= 0;

float	X0, Y0;		/* left bottom of input */
float	X1, Y1;		/* right top of input */

int	hmax;		/* right end of output */
int	vmax;		/* top of output (down is positive) */

extern	float	deltx;
extern	float	delty;
extern	int	xmin, ymin, xmax, ymax, sxmin, symin, sxmax, symax;
extern	int	psize;

openpl()	/* initialize device */
{
	float maxdelt;

	hpos = vpos = 0;
	hmax = vmax = 6 * res;	/* default = 6 x 6 */
	maxdelt = max(deltx, delty);
	if (maxdelt > 8) {	/* 8 inches */
		fprintf(stderr, "pltroff: %g X %g picture shrunk to", deltx, delty);
		deltx *= 8/maxdelt;
		delty *= 8/maxdelt;
		fprintf(stderr, " %g X %g\n", deltx, delty);
	}
	if (deltx > 0 && delty > 0) {	/* have to change default size */
		hmax = res * deltx;
		vmax = res * delty;
	}

	if (xconv(xmax) >= 8192 || yconv(ymax) >= 8192) {
		/* internal troff limit: 13 bits for motion */
		fprintf(stderr, "pltroff: picture too high or wide");
		exit(1);
	}

	if (xmax == xmin)
		space(xmin, ymin, xmin + ymax-ymin, ymax);
	else	/* assumes 1:1 aspect ratio */
		space(xmin, ymin, xmax, ymin + xmax-xmin);

	/* debug rubbish, troff'd better ignore this */
	printf("... %d %d %d %d %d %d %d %d\n",
		xmin, ymin, xmax, ymax, sxmin, symin, sxmax, symax);
	printf("... %du %du %du %du %du %du %du %du\n",
		xconv(xmin), yconv(ymin), xconv(xmax), yconv(ymax),
		xconv(sxmin), yconv(symin), xconv(sxmax), yconv(symax));

	/* troff preamble */
	if(psize) printf(".ps %d\n",psize);
	printf(".if t .sp .3\n");
	if(cflag) printf(".in (\\n(.lu-%du)/2u\n",xconv(xmax));
	printf(".ne %du\n",yconv(ymin));
	printf(".br\n");
}

closepl()	/* clean up after finished */
{
	movehv(0, 0);	/* get back to where we started */
	printf(".sp 1+%du\n", yconv(ymin));
	if(cflag) printf(".in\n");
	printf(".if t .sp .6v\n");
	if(psize) printf(".ps\n");	/* God help anyone messing with ps */
}

move(x, y)	/* go to position x, y in external coords */
	int x, y;
{
	hgoto(xconv(x));
	vgoto(yconv(y));
}

movehv(h, v)	/* go to internal position h, v */
	int h, v;
{
	hgoto(h);
	vgoto(v);
}

hgoto(n)
{
	hpos = n;
}

vgoto(n)
{
	vpos = n;
}

hvflush()	/* get to proper point for output */
{
	if (hpos != htrue) {
		printf("\\h'%du'", hpos - htrue);
		htrue = hpos;
	}
	if (vpos != vtrue) {
		printf("\\v'%du'", vpos - vtrue);
		vtrue = vpos;
	}
}

flyback()	/* return to upper left corner (entry point) */
{
	printf(".sp -1\n");
	htrue = vtrue = 0;
}

label(s, t)	/* text s of type t */
	char *s;
	int t;
{
	int q, nh = 0;
	char *p;

	hvflush();
	if(hshift != 0.0) printf("\\h'-%.1fm'",hshift);	/* shift left */
	if(vshift != 0.0) printf("\\v'%.1fm'",vshift);	/* shift down */

	if (t == 'A')
		nh++;
	else if (t == 'B')
		nh--;
	if (nh)
		printf("\\v'%du*\\n(.vu/2u'", -nh);

	/* just in case the text contains a quote: */
	q = 0;
	for (p = s; *p; p++)
		if (*p == '\'') {
			q = 1;
			break;
		}
	switch (t) {
	case 'L':
	default:
		printf("%s", s);
		break;
	case 'C':
	case 'A':
	case 'B':
		if (q)
			printf("\\h\\(ts-\\w\\(ts%s\\(tsu/2u\\(ts%s\\h\\(ts-\\w\\(ts%s\\(tsu/2u\\(ts", s, s, s);
		else
			printf("\\h'-\\w'%s'u/2u'%s\\h'-\\w'%s'u/2u'", s, s, s);
		break;
	case 'R':
		if (q)
			printf("\\h\\(ts-\\w\\(ts%s\\(tsu\\(ts%s", s, s);
		else
			printf("\\h'-\\w'%s'u'%s", s, s);
		break;
	}
	printf("\n");
	vpos += ((psize + 2)*240)/72;	/* Implicit newline */
	flyback();
}

line(x, y, xa, ya)	/* draw line from x,y to xa,ya */
	int x, y, xa, ya;
{
	move(x, y);
	cont(xa, ya);
}

box(x, y, xa, ya)
	int x, y, xa, ya;
{
	move(x, y);
	cont(x, ya);
	cont(xa, ya);
	cont(xa, y);
	cont(x, y);
}

cont(x, y)	/* continue line from here to x,y */
	int x, y;
{
	int h1, v1;
	int dh, dv;

	h1 = xconv(x);
	v1 = yconv(y);
	dh = h1 - hpos;
	dv = v1 - vpos;
	hvflush();
	if (!useDline && dv == 0 && abs(dh) > minline)	/* horizontal */
		printf("\\l'%du'\n", dh);
	else if (!useDline && dh == 0 && abs(dv) > minline) {	/* vertical */
		if (devtype == DEV202)
			printf("\\L'%du\\(vr'\n", dv);
		else
			printf("\\v'-.25m'\\L'%du\\(br'\\v'.25m'\n", dv);	/* add -.25m correction if use \(br */
	} else printf("\\D'l%du %du'\n", dh, dv);
	flyback();	/* expensive */
	hpos = h1;
	vpos = v1;
}

circle(x, y, r)
	int x, y, r;
{
	int d;

	d = xsc(2 * r);
	move(x-r, y);
	hvflush();
	printf("\\D'c%du'\n", d);
	flyback();
}

arc(x, y, xa, ya, xb, yb)	/* draw arc with center x,y */
	int x, y, xa, ya, xb, yb;
{

	move(xa, ya);
	hvflush();
	printf("\\D'a%du %du %du %du'\n",xsc(x-xa),ysc(y-ya),xsc(xb-x),ysc(yb-y));
	flyback();
}

erase()	/* get to bottom of frame */
{
	return;	/* for now, ignore them */
}

point(x, y)	/* put point at x,y */
	int x, y;
{
	static char *temp = "\\(mu";

	move(x, y);
	label(temp, 'L');
}

space(xa, ya, xb, yb)	/* set limits of page */
	int xa, ya, xb, yb;
{
	if (xa == xb)
		xb = xa + 1;
	if (ya == yb)
		yb = ya - 1;	/* kludge */
	X0 = xa;
	Y0 = ya;
	X1 = xb;
	Y1 = yb;
	xscale = hmax / (X1-X0);
	yscale = vmax / (Y0-Y1);
}

xconv(x)	/* convert x from external to internal form */
	int x;
{
	int v;

	v = (((float) x)-X0) * xscale + 0.5;
	return v;
}

xsc(x)	/* convert x from external to internal form, scaling only */
	int x;
{
	int v;

	v = ((float) x) * xscale + 0.5;
	return v;
}

yconv(y)	/* convert y from external to internal form */
	int y;
{
	int v;
	float yy;

	yy = ((float) y) + Y1 - ymax;
	v = (yy-Y1) * yscale + 0.5;
	return v;
}

ysc(y)	/* convert y from external to internal form, scaling only */
	int y;
{
	int v;

	v = ((float) y) * yscale + 0.5;
	return v;
}

dot() {
	hvflush();
	/* what character to draw here depends on what's available. */
	/* on the 202, l. is good but small. */
	/* on other typesetters, use a period and hope */
	if (devtype == DEV202)
		printf("\\z\\(l.\\(l.\\z\\(l.\\(l.\n");
	else
		printf("\\&.\n");
	flyback();
}
