[net.micro.atari16] X-Y plotting, improved

braner@batcomputer.TN.CORNELL.EDU (braner) (09/30/86)

[]

Here is an improved version of my X-Y plotting program.

Note that I took the log-scale stuff out.  That's because I didn't
like having to link to the math lib all the time.  Instead, take logs
before you call plot().

I added a settable plotting area with VDI clipping, and also a cooked
call to v_pmarker.  You are still limited to one plot at a time as long
as you use this simple approach.

Personally, I am AMAZED how fast this thing runs!

- Moshe Braner

---------------- cut here ------------------------

/*
 * Simple VDI Interface for X-Y Plotting - version 2.
 *
 *      by Moshe Braner,   860929
 *
 * #include "plotxyz.c" (this file) in your program.
 *
 */

/* globally define arrays to be used by VDI: */

int contrl[12], intin[128], ptsin[128], intout[128], ptsout[128];

/* our own globals */

static	int	work_in[11], work_out[57];	
static	int	plothand=0;
static	int	xl, xr, yt, yb;
static	int	curx, cury, curvalid;
static	double	p, q, r, s;

/*
 * Subroutine to set up the VDI workstation.
 * You have to call this first!
 * You have to call cleanplot() before you call this again!
 *
 * The parameters define the clipping area, in screen coords.
 * Suggested values (monochrome): 40,639,0,399.
 */
initplot(xmin, xmax, ymin, ymax)
    int  xmin, xmax, ymin, ymax;
{
	int	i, pxy[4];

	/* initialize VDI */

	if (plothand != 0) {
		puts("initplot(): Recall - cleanplot() first!");
		exit(0);
	}
	for(i=0; i<10; i++)		/* init workstation params	*/
		work_in[i]=1;
	work_in[10]= 2;			/* use raster coords		*/
	v_opnvwk( work_in, &plothand, work_out );
	vswr_mode(plothand, 1);		/* "Replace" mode		*/
	vsf_color(plothand, 1);		/* black			*/

	/* set up clipping boundaries	*/

	pxy[0] = xmin;
	pxy[1] = ymin;
	pxy[2] = xmax;
	pxy[3] = ymax;
	vs_clip(plothand, 1, pxy);

	/* store the boundaries in our globals	*/

	xl = xmin;
	xr = xmax;
	yt = ymin;
	yb = ymax;
}

/*
 * Subroutine to translate from user coords to screen coords.
 */
coords(x, y, pix, piy)
	double	x, y;
	int	*pix, *piy;
{
	*pix = (int)(r * (x-p)) + xl;
	*piy = (int)(s * (q-y)) + yb;
}

/*
 * Subroutine to set up axes and rescaling.
 * You may call this repeatedly.
 * The whole screen is cleared, and also the (text) cursor.
 *
 * Parameters:
 *
 *    xmin = lowest X-value
 *    xmax = highest X-value
 *    xtik = tick interval for X (ratio if log)
 *    ymin = lowest Y-value
 *    ymax = highest Y-value
 *    ytik = tick interval for Y (ratio if log)
 *    xorg, yorg = position where axes cross
 *    mode - if 0 then just remember scaling, alse draw the axes.
 */
axes(xmin,xmax,xtik,ymin,ymax,ytik,xorg,yorg,mode)
	double	xmin,xmax,xtik,ymin,ymax,ytik,xorg,yorg;
	int	mode;
{
	int	i, pxy[4];
	double	w;

	if (plothand == 0) {
		puts("Must call initplot() before axes()!");
		exit(0);
	}

	r = ((double)(xr-xl))/(xmax-xmin);
	s = ((double)(yb-yt))/(ymax-ymin);
	p = xmin;
	q = ymin;

	puts("\033E");			/* clear screen			*/
	puts("\033f");			/* cursor invisible		*/
	curvalid = 0;
	if (mode == 0)
		return;

	/* draw X-axis */

	coords(xmin, yorg, &pxy[0], &pxy[1]);
	coords(xmax, yorg, &pxy[2], &pxy[3]);
	v_pline(plothand, 2, pxy);
	w = xorg;
	while (w >= xmin)
		w -= xtik;
	while ((w+=xtik) <= xmax) {
		coords(w, yorg, &pxy[2], &pxy[3]);
		pxy[0] = pxy[2];
		pxy[1] = pxy[3] - 4;
		v_pline(plothand, 2, pxy);
	}

	/* draw y-axis */

	coords(xorg, ymax, &pxy[0], &pxy[1]);
	coords(xorg, ymin, &pxy[2], &pxy[3]);
	v_pline(plothand, 2, pxy);
	w = yorg;
	while (w >= ymin)
		w -= ytik;
	while ((w+=ytik) <= ymax) {
		coords(xorg, w, &pxy[0], &pxy[1]);
		pxy[2] = pxy[0] + 4;
		pxy[3] = pxy[1];
		v_pline(plothand, 2, pxy);
	}
}

/*
 * Subroutine to plot a point
 *
 *   (First call initplot() and axes().)
 *
 * Plots with the pen up if z==0, else pen down.
 * Uses the preset p, q, r, s, for rescaling.
 * Uses the remembered curx, cury if pen down.
 */
plot(x, y, z)
	double	x, y;
	int	z;
{
	int	xi, yi, pxy[4];

	if (plothand == 0) {
		puts("Must call initplot() and axes() before plot()!");
		exit(0);
	}
	coords(x, y, &xi, &yi);
	if (z && curvalid) {
		pxy[0] = curx;
		pxy[1] = cury;
	} else {
		pxy[0] = xi;
		pxy[1] = yi;
	}
	curx = xi;
	cury = yi;
	curvalid = 1;
	pxy[2] = xi;
	pxy[3] = yi;
	v_pline(plothand, 2, pxy);	
}

/*
 * Subroutine to draw a marker.
 *
 *   (First call initplot() and axes().)
 *
 * Last argument is the marker type, a char: ./+/X/#/^/*
 */
mark(x, y, type)
	double	x, y;
	int	type;
{
	static int types[] = {' ', '.', '+', '*', '#', 'X', '^'};
	int	i, xi, yi, pxy[2];

	if (plothand == 0) {
		puts("Must call initplot() and axes() before mark()!");
		exit(0);
	}
	for (i=1; i<7; i++)
		if (type == types[i])
			break;
	vsm_type(plothand, i);
	coords(x, y, &pxy[0], &pxy[1]);
	v_pmarker(plothand, 1, pxy);	
}

/*
 * clean up when you're done, or else you'll get cherry bombs!
 */
cleanplot()
{
	v_clsvwk(plothand);
	plothand = 0;
}