PWB1/sys/source/s1/graph.c
#define INF 1.e+37
#define F .25
/* following structure is arranged as two interleaved structures,
* one for x and one for y to permit growing core point-by-point
* It would be better to separate out the front matter from the
* val substructure and so eliminate much of this funny business
*/
#define NT 8 /*sleazy way to tell size of struct to transpose*/
struct xy {
int xlbf,xubf, ylbf,yubf; int pada;
int xqf,pad1, yqf,pad2; int padb;
float xa, ya; int padc;
float xb, yb; int padd;
float xlb, ylb; int pade;
float xub, yub; int padf;
float xquant, yquant; int padg;
float xmult, ymult; int padh;
struct {
float xv, yv; int lbptr;
} val[1];
} *xy;
/* labels are stored in a floating buffer at the
* top of memory, slab=size, nlab=amt in use
*/
int slab 0;
int nlab 0;
#define B 64
#define BUMP (B*sizeof(xy->val[0]))
float xsize 1.;
float ysize 1.;
float xoffset 0.;
float yoffset 0.;
int tick 50;
int top 1940;
int bot -1860;
int xbot;
int ybot;
float absbot;
int cx,cy,ty;
int n;
int framef;
int gridf;
int connf;
int symbf;
int absf;
int transf;
float dx;
char *plotsymb;
double atof();
double floor();
double ceil();
char *sbrk();
int fin;
#define BSIZ 80
char labbuf[BSIZ];
char titlebuf[BSIZ];
main(argc,argv)
char *argv[];
{
extern int fout;
fout = 1;
space(-2048,-2048,2048,2048);
xy = sbrk( sizeof(xy[0]) );
setopt(argc,argv);
if(framef)
erase();
readin();
transpose();
scale();
axes();
plot();
move(-2047,-2047);
closevt();
return(0);
}
setopt(argc,argv)
char *argv[];
{
int hflag;
char *p1, *p2;
hflag = 0;
framef = 1;
connf = 1;
gridf = 2;
symbf = 0;
absf = 0;
xy->xlbf = xy->xubf = xy->ylbf = xy->yubf = 0;
xy->xqf = xy->yqf = 0;
xy->xlb = xy->ylb = INF;
xy->xub = xy->yub = -INF;
xy->val[0].xv = xy->val[0].yv = 0;
while(--argc > 0) {
argv++;
again: switch(argv[0][0]) {
case '-':
argv[0]++;
goto again;
case 'l': /* label for plot */
p1 = titlebuf;
if (argc>=2) {
argv++;
argc--;
p2 = argv[0];
while (*p1++ = *p2++);
}
break;
case 'a': /*automatic abscissas*/
absf = 1;
dx = 1;
if(!numb(&dx,&argc,&argv)) break;
if(numb(&absbot,&argc,&argv))
absf = 2;
break;
case 'd':/*disconnected, no lines between points*/
connf = 0;
break;
case 's': /*save screen, overlay plot*/
framef = 0;
break;
case 'g': /*grid style 0 none, 1 ticks, 2 full*/
gridf = 0;
if(argv[0][1])
gridf = argv[0][1]-'0';
break;
case 'c': /*character(s) for plotting*/
if(argc >= 2) {
symbf = 1;
plotsymb = argv[1];
argv++;
argc--;
}
break;
case 't': /*transpose*/
transf = 1;
break;
case 'x': /*x limits */
limread(&xy->xlbf,&argc,&argv);
break;
case 'y':
limread(&xy->ylbf,&argc,&argv);
break;
case 'h': /*set height of plot */
numb(&ysize, &argc,&argv);
break;
case 'w': /*set width of plot */
numb(&xsize, &argc, &argv);
break;
case 'r': /* set offset to right */
numb(&xoffset, &argc, &argv);
break;
case 'u': /*set offset up the screen*/
numb(&yoffset,&argc,&argv);
break;
default:
badarg();
}
}
}
limread(p, argcp, argvp)
register struct xy *p;
{
if(!numb(&p->xlb,argcp,argvp))
return;
p->xlbf = 1;
if(!numb(&p->xub,argcp,argvp))
return;
p->xubf = 1;
if(!numb(&p->xquant,argcp,argvp))
return;
p->xqf = 1;
}
numb(np, argcp, argvp)
int *argcp;
float *np;
register char ***argvp;
{
register char c;
if(*argcp <= 1)
return(0);
while((c=(*argvp)[1][0]) == '+')
(*argvp)[1]++;
if(!(digit(c) || c=='-'&&(*argvp)[1][1]<'A' || c=='.'))
return(0);
*np = atof((*argvp)[1]);
(*argcp)--;
(*argvp)++;
return(1);
}
readin()
{
register i;
register t;
fin = dup(0);
close(0);
if(xy->xlbf && absf==1)
absbot = xy->xlb;
for(;;) {
if(more()==0)
return;
for(i=0; i<B; i++) {
if(absf)
xy->val[n].xv = n*dx + absbot;
else
if(!getfloat(&xy->val[n].xv))
return;
if(!getfloat(&xy->val[n].yv))
return;
xy->val[n].lbptr = -1;
t = getstring();
if(t>0)
xy->val[n].lbptr = copystring(t);
n++;
if(t<0)
return;
}
}
}
transpose()
{
register i;
float f;
if(!transf)
return;
for(i= -NT;i<n;i++) {
f = xy->val[i].xv;
xy->val[i].xv = xy->val[i].yv;
xy->val[i].yv = f;
}
}
more()
{
register i;
register char *p;
if(sbrk(BUMP) == -1) {
write(2,"points omitted\n",15);
return(0);
}
p = sbrk(0);
for(i=0;i<slab;i++) {
--p;
p[0] = p[-BUMP];
}
return(1);
}
copystring(k)
{
register char *p;
register i;
int q;
if(k+1+nlab>slab) {
if(more()==0)
return;
slab =+ BUMP;
}
p = sbrk(0);
q = nlab;
for(i=0;i<=k;i++)
*(p-slab+nlab++) = labbuf[i];
return(q);
}
float
modceil(f,t)
float f,t;
{
return(ceil(f/t)*t);
}
float
modfloor(f,t)
float f,t;
{
return(floor(f/t)*t);
}
getlim(p)
register struct xy *p;
{
register i;
i = 0;
do {
if(!p->xlbf && p->xlb>(p->val[i].xv))
p->xlb = p->val[i].xv;
if(!p->xubf && p->xub<(p->val[i].xv))
p->xub = p->val[i].xv;
i++;
}
while(i < n);
}
setlim(p)
register struct xy *p;
{
float r,s,t,delta,sign;
float lb,ub;
int lbf,ubf;
lb = p->xlb;
ub = p->xub;
delta = ub-lb;
if(p->xqf) {
if(delta*p->xquant <=0 )
badarg();
p->xmult = 1;
return;
}
if(delta == 0) {
if(ub > 0) {
ub = 2*ub;
lb = 0;
}
else
if(lb < 0) {
lb = 2*lb;
ub = 0;
}
else {
ub = 1;
lb = -1;
}
delta = ub-lb;
}
sign = 1;
lbf = p->xlbf;
ubf = p->xubf;
if(delta < 0) {
sign = -1;
t = lb;
lb = ub;
ub = t;
t = lbf;
lbf = ubf;
ubf = t;
delta = -delta;
}
r = s = 1;
while(delta*s < 1)
s =* 10;
delta =* s;
while(10*r < delta)
r =* 10;
lb =* s;
ub =* s;
if(r>=5*delta/6)
r =/ 5;
else if(r>=delta/2)
r =/ 2;
else if(r<delta/5)
r =* 2;
if(!ubf)
ub = modceil(ub,r);
if(!lbf)
lb = modfloor(lb,r);
if(!lbf && ub<=6*r && lb>0)
lb = 0;
else if(!ubf && lb>=-6*r && ub<0)
ub = 0;
if(sign > 0) {
p->xlb = lb;
p->xub = ub;
p->xquant = r;
}
else {
p->xlb = ub;
p->xub = lb;
p->xquant = -r;
}
p->xmult = s;
}
scale()
{
float edge;
register struct xy *p;
p = xy;
getlim(&p->xlbf);
setlim(&p->xlbf);
getlim(&p->ylbf);
setlim(&p->ylbf);
edge = top-bot;
p->xa = xsize*edge/(xy->xub-xy->xlb);
xbot = bot + edge*xoffset;
p->xb = xbot - xy->xlb*xy->xa;
p->ya = ysize*edge/(p->yub-p->ylb);
ybot = bot + edge*yoffset;
p->yb = ybot - p->ylb*p->ya;
}
axes()
{
int ix,ix0,ix1,iy,iy0,iy1;
float h,v;
extern float quant();
ix0 = xbot;
iy0 = ybot;
ix1 = xbot + (top-bot)*xsize;
iy1 = ybot + (top-bot)*ysize;
if(gridf==2) {
for(h=quant(&xy->xlbf); lim(h,&xy->xlbf); h=+xy->xquant) {
ix = h*xy->xa+xy->xb;
line(ix,iy0,ix,iy1);
}
for(v=quant(&xy->ylbf); lim(v,&xy->ylbf); v=+xy->yquant) {
iy = v*xy->ya+xy->yb;
line(ix0,iy,ix1,iy);
}
}
if(gridf==1) {
h = 0;
if((xy->xlb < 0 && xy->xub <= 0) ||
(xy->xlb >= 0 && xy->xub >= 0))
h = xy->xlb;
ix = h*xy->xa+xy->xb;
line(ix,iy0,ix,iy1);
for(v=quant(&xy->ylbf); lim(v,&xy->ylbf); v=+xy->yquant) {
iy = v*xy->ya+xy->yb;
line(ix-tick,iy,ix+tick,iy);
}
v = 0;
if((xy->ylb < 0 && xy->yub <= 0) || (xy->ylb >= 0 && xy->yub >= 0))
v = xy->ylb;
iy = v*xy->ya+xy->yb;
line(ix0,iy,ix1,iy);
for(h=quant(&xy->xlbf); lim(h,&xy->xlbf); h=+xy->xquant) {
ix = h*xy->xa+xy->xb;
line(ix,iy-tick,ix,iy+tick);
}
}
if(gridf)
title();
}
float quant(p)
register struct xy *p;
{
if(p->xquant>0)
return(modceil(p->xlb,p->xquant));
else
return(modfloor(p->xlb,p->xquant));
}
lim(l,p)
float l;
struct xy *p;
{
l =- p->xub + p->xquant/2;
if(p->xquant > 0)
return(l<0);
return(l>0);
}
plot()
{
int ix,iy,lx,ly;
int i;
int first;
first = 0;
for(i=0; i<n; i++) {
if(!inlim(xy->val[i].xv,&xy->xlbf)||
!inlim(xy->val[i].yv,&xy->ylbf)) {
first = 0;
continue;
}
ix = xy->xa*xy->val[i].xv*xy->xmult+xy->xb;
iy = xy->ya*xy->val[i].yv*xy->ymult+xy->yb;
if(connf) {
if(first > 0)
line(ix,iy,lx,ly);
lx = ix;
ly = iy;
first = 1;
}
symbol(ix,iy,xy->val[i].lbptr);
}
}
inlim(xv,p)
float xv;
register struct xy *p;
{
if(!p->xlbf&&!p->xubf)
return(1);
if(p->xquant >0)
return(xv>=p->xlb&xv<=p->xub);
else
return(xv>=p->xub&xv<=p->xlb);
}
char savchar ' ';
getfloat(p)
float *p;
{
register i;
while(blank(savchar)) {
if((savchar=getchar())==0)
return(0);
}
for(i=0; i<BSIZ-1; ) {
labbuf[i] = savchar;
if((savchar=getchar())==0)
return(0);
i++;
if(digit(savchar))
continue;
switch(savchar) {
case '.':
case '+':
case '-':
case 'E':
case 'e':
continue;
}
break;
}
labbuf[i] = ' ';
*p = atof(labbuf);
return(1);
}
getstring()
{
register i;
i = 0;
labbuf[0] = 0;
while(blank(savchar)) {
if((savchar=getchar())==0)
return(-1);
}
if(digit(savchar))
return(0);
switch(savchar) {
case '.':
case '+':
case '-':
return(0);
}
if(savchar=='"') {
while(i<BSIZ-1) {
switch(savchar=getchar()){
case 0:
return(-1);
case '"':
savchar = ' ';
case '\n':
break;
default:
labbuf[i++] = savchar;
continue;
}
break;
}
} else {
for(;;) {
labbuf[i++] = savchar;
if((savchar=getchar())==0)
return(-1);
if(blank(savchar))
break;
}
}
labbuf[i] = 0;
return(i);
}
digit(c)
{
return('0'<=c&c<='9');
}
blank(c)
{
switch(c) {
case ' ':
case '\t':
case '\n':
return(1);
}
return(0);
}
symbol(ix,iy,k)
{
if(symbf==0&&k<0) {
if(connf==0)
point(ix,iy);
}
else {
move(ix,iy);
label(k>=0?sbrk(0)-slab+k:plotsymb);
}
}
title()
{
move(xbot,ybot-60);
bound(xy->xlb,&xy->xlbf);
label(" -x- ");
bound(xy->xub,&xy->xlbf);
label(" ");
bound(xy->ylb,&xy->ylbf);
label(" -y- ");
bound(xy->yub,&xy->ylbf);
if (titlebuf[0]) {
label(" ");
label(titlebuf);
}
}
char putbuf[30];
int putpos;
bound(f,p)
float f;
struct xy *p;
{
fconv(putbuf,f/p->xmult);
label(putbuf);
}
fconv(cp,f)
double f;
char *cp;
{
char *cdig;
int decpt, sign, i;
cdig = fcvt(f, 6, &decpt, &sign);
if (sign)
*cp++ = '-';
if(decpt<0)
*cp++ = '.';
for(i=0;i>decpt;i--)
*cp++ = '0';
for (i=0; i < 6; i++)
{
if (i== decpt)
*cp++ = '.';
*cp++ = *cdig++;
}
*cp = '\0';
}
badarg()
{
write(2,"bad argument\n",13);
exit(1);
}