[net.micro.atari16] A simple VDI interface for XY plotting

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

[]

For a long time I wanted to create a very simple, easy-to-use system
for plotting functions, data, etc from a C program.  I am thinking of
scientific/engineering applications, where quick, one-shot plots are
wanted, not fancy, perfect, art pieces.

Well, I did it after all - it wasn't as hard as I thought, since I have
already done it before in Applesoft BASIC.  Happy plotting!

- Moshe Braner

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

/*
 * Simple VDI Interface for X-Y Plotting
 *
 *      by Moshe Braner,   860924
 *
 * #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	xlog, ylog, curx, cury, curvalid;
static	int	plothand=0;
static	double	p, q, r, s;

/*
 * Subroutine to set up graphics
 *
 * 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 of origion
 *    xmode, ymode = 0 for linear, 1 for log-scale
 */
initplot(xmin,xmax,xtik,ymin,ymax,ytik,xorg,yorg,xmode,ymode)
	double	xmin,xmax,xtik,ymin,ymax,ytik,xorg,yorg;
	int	xmode, ymode;
{
	int	i, pxy[4];
	double	w;

	puts("\033E");			/* clear screen			*/
	puts("\033f");			/* cursor invisible		*/

	/* initialize VDI */

	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 );
	vsf_color(plothand, 1);		/* black			*/
	vswr_mode(plothand, 1);		/* "Replace" mode		*/

	/* initialize our params */

	xlog = xmode;
	ylog = ymode;
	if (xlog) {
		xmin = log(xmin);
		xmax = log(xmax);
		xtik = log(xtik);
		xorg = log(xorg);
	}
	if (ylog) {
		ymin = log(ymin);
		ymax = log(ymax);
		ytik = log(ytik);
		yorg = log(yorg);
	}

	r = 599.0/(xmax-xmin);
	s = 399.0/(ymax-ymin);
	p = xmin;
	q = ymin;

	/* draw X-axis */

	pxy[0] = (int)(r * (xmin-p)) + 40;
	pxy[1] = (int)(s * (q-yorg)) + 399;
	pxy[2] = (int)(r * (xmax-p)) + 40;
	pxy[3] = pxy[1];
	v_pline(plothand, 2, pxy);
	w = xorg;
	while (w >= xmin)  w -= xtik;
	pxy[1] = (int)(s * (q-yorg)) + 395;
	pxy[3] = pxy[1] + 3;
	while ((w+=xtik) <= xmax) {
		pxy[0] = (int)(r * (w-p)) + 40;
		pxy[2] = pxy[0];
		v_pline(plothand, 2, pxy);
	}

	/* draw y-axis */

	pxy[0] = (int)(r * (xorg-p)) + 40;
	pxy[1] = (int)(s * (q-ymin)) + 399;
	pxy[2] = pxy[0];
	pxy[3] = (int)(s * (q-ymax)) + 399;
	v_pline(plothand, 2, pxy);
	w = yorg;
	while (w >= ymin)  w -= ytik;
	pxy[0] = (int)(r * (xorg-p)) + 41;
	pxy[2] = pxy[0] + 3;
	while ((w+=ytik) <= ymax) {
		pxy[1] = (int)(s * (q-w)) + 399;
		pxy[3] = pxy[1];
		v_pline(plothand, 2, pxy);
	}

	curvalid = 0;
}

/*
 * Subroutine to plot a point
 *
 *   (First call initplot() for setup.)
 *
 * Plots with the pen up if z==0, else pen down.
 * Uses the preset p, q, r, s, xlog, ylog 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() before plot()!");
		exit(0);
	}
	if (xlog)  x = log(x);
	if (ylog)  y = log(y);
	xi = (int)(r * (x-p)) + 40;
	yi = (int)(s * (q-y)) + 399;
	if (xi<0 || xi>639) {
		/* puts("plot(): x out of range!"); */
		return;
	}
	if (yi<0 || yi>399) {
		/* puts("plot(): y out of range!"); */
		return;
	}
	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);	
}

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

------------- example program ------------------

#include <stdio.h>
#include <math.h>
#include "plotxyz.c"

main()
{
	double	x,y,xmin,xmax,xtik,ymin,ymax,ytik,xorg,yorg;

	xmin = -2.0;
	xmax = 6.0;
	ymin = -1.3;
	ymax = 1.3;
	xtik = 1.0;
	ytik = 0.25;
	xorg = 0.0;
	yorg = 0.0;

	initplot(xmin,xmax,xtik,ymin,ymax,ytik,xorg,yorg,0,0);

	for (x=xmin; x<xmax; x+=0.05) {
		y = sin(x);
		plot(x,y,1);
	}

	cleanplot();
	getchar();
}