#ifndef lint static char sccsid[] = "@(#)graph.c 4.2 3/30/83"; #endif #include #include #include #define INF HUGE #define F .25 struct xy { int xlbf; /*flag:explicit lower bound*/ int xubf; /*flag:explicit upper bound*/ int xqf; /*flag:explicit quantum*/ double (*xf)(); /*transform function, e.g. log*/ float xa,xb; /*scaling coefficients*/ float xlb,xub; /*lower and upper bound*/ float xquant; /*quantum*/ float xoff; /*screen offset fraction*/ float xsize; /*screen fraction*/ int xbot,xtop; /*screen coords of border*/ float xmult; /*scaling constant*/ } xd,yd; struct val { float xv; float yv; int lblptr; } *xx; char *labs; int labsiz; int tick = 50; int top = 4000; int bot = 200; float absbot; int n; int erasf = 1; int gridf = 2; int symbf = 0; int absf = 0; int transf; int brkf; float dx; char *plotsymb; double atof(); #define BSIZ 80 char labbuf[BSIZ]; char titlebuf[BSIZ]; char *modes[] = { "disconnected", "solid", "dotted", "dotdashed", "shortdashed", "longdashed" }; int mode = 1; char *realloc(); char *malloc(); double ident(x) double x; { return(x); } main(argc,argv) char *argv[]; { space(0,0,4096,4096); init(&xd); init(&yd); xd.xsize = yd.xsize = 1.; xx = (struct val *)malloc((unsigned)sizeof(struct val)); labs = malloc(1); labs[labsiz++] = 0; setopt(argc,argv); if(erasf) erase(); readin(); transpose(); scale(&xd,(struct val *)&xx->xv); scale(&yd,(struct val *)&xx->yv); axes(); title(); plot(); move(1,1); closevt(); return(0); } init(p) struct xy *p; { p->xf = ident; p->xmult = 1; } setopt(argc,argv) char *argv[]; { char *p1, *p2; float temp; xd.xlb = yd.xlb = INF; xd.xub = yd.xub = -INF; 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 'd': /*disconnected,obsolete option*/ case 'm': /*line mode*/ mode = 0; if(!numb(&temp,&argc,&argv)) break; if(temp>=sizeof(modes)/sizeof(*modes)) mode = 1; else if(temp>=0) mode = temp; break; case 'a': /*automatic abscissas*/ absf = 1; dx = 1; if(!numb(&dx,&argc,&argv)) break; if(numb(&absbot,&argc,&argv)) absf = 2; break; case 's': /*save screen, overlay plot*/ erasf = 0; break; case 'g': /*grid style 0 none, 1 ticks, 2 full*/ gridf = 0; if(!numb(&temp,&argc,&argv)) temp = argv[0][1]-'0'; /*for caompatibility*/ if(temp>=0&&temp<=2) gridf = temp; 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 'b': /*breaks*/ brkf = 1; break; case 'x': /*x limits */ limread(&xd,&argc,&argv); break; case 'y': limread(&yd,&argc,&argv); break; case 'h': /*set height of plot */ if(!numb(&yd.xsize, &argc,&argv)) badarg(); break; case 'w': /*set width of plot */ if(!numb(&xd.xsize, &argc, &argv)) badarg(); break; case 'r': /* set offset to right */ if(!numb(&xd.xoff, &argc, &argv)) badarg(); break; case 'u': /*set offset up the screen*/ if(!numb(&yd.xoff,&argc,&argv)) badarg(); break; default: badarg(); } } } limread(p, argcp, argvp) register struct xy *p; int *argcp; char ***argvp; { if(*argcp>1 && (*argvp)[1][0]=='l') { (*argcp)--; (*argvp)++; p->xf = log10; } 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(!(isdigit(c) || c=='-'&&(*argvp)[1][1]<'A' || c=='.')) return(0); *np = atof((*argvp)[1]); (*argcp)--; (*argvp)++; return(1); } readin() { register t; struct val *temp; if(absf==1) { if(xd.xlbf) absbot = xd.xlb; else if(xd.xf==log10) absbot = 1; } for(;;) { temp = (struct val *)realloc((char*)xx, (unsigned)(n+1)*sizeof(struct val)); if(temp==0) return; xx = temp; if(absf) xx[n].xv = n*dx + absbot; else if(!getfloat(&xx[n].xv)) return; if(!getfloat(&xx[n].yv)) return; xx[n].lblptr = -1; t = getstring(); if(t>0) xx[n].lblptr = copystring(t); n++; if(t<0) return; } } transpose() { register i; float f; struct xy t; if(!transf) return; t = xd; xd = yd; yd = t; for(i= 0;ixlbf && p->xlb>v[i].xv) p->xlb = v[i].xv; if(!p->xubf && p->xubxub = v[i].xv; i++; } while(i < n); } struct z { float lb,ub,mult,quant; } setloglim(), setlinlim(); setlim(p) register struct xy *p; { float t,delta,sign; struct z z; int mark[50]; float lb,ub; int lbf,ubf; lb = p->xlb; ub = p->xub; delta = ub-lb; if(p->xqf) { if(delta*p->xquant <=0 ) badarg(); return; } 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; } else 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; } } if(p->xf==log10 && lb>0 && ub>lb) { z = setloglim(lbf,ubf,lb,ub); p->xlb = z.lb; p->xub = z.ub; p->xmult *= z.mult; p->xquant = z.quant; if(setmark(mark,p)<2) { p->xqf = lbf = ubf = 1; lb = z.lb; ub = z.ub; } else return; } z = setlinlim(lbf,ubf,lb,ub); if(sign > 0) { p->xlb = z.lb; p->xub = z.ub; } else { p->xlb = z.ub; p->xub = z.lb; } p->xmult *= z.mult; p->xquant = sign*z.quant; } struct z setloglim(lbf,ubf,lb,ub) float lb,ub; { float r,s,t; struct z z; for(s=1; lb*s<1; s*=10) ; lb *= s; ub *= s; for(r=1; 10*r<=lb; r*=10) ; for(t=1; t= 5*z.lb) z.lb *= 5; else if(lb >= 2*z.lb) z.lb *= 2; } if(!ubf) { if(ub*5 <= z.ub) z.ub /= 5; else if(ub*2 <= z.ub) z.ub /= 2; } } z.mult = s; z.quant = r; return(z); } struct z setlinlim(lbf,ubf,xlb,xub) int lbf,ubf; float xlb,xub; { struct z z; float r,s,delta; float ub,lb; loop: ub = xub; lb = xlb; delta = ub - lb; /*scale up by s, a power of 10, so range (delta) exceeds 1*/ /*find power of 10 quantum, r, such that delta/10<=r=delta/2) r /= 2; else if(r0) { xlb = 0; goto loop; } else if(!ubf && z.ub>=-r && z.ub<0) { xub = 0; goto loop; } z.quant = r; z.mult = s; return(z); } scale(p,v) register struct xy *p; struct val *v; { float edge; getlim(p,v); setlim(p); edge = top-bot; p->xa = p->xsize*edge/((*p->xf)(p->xub) - (*p->xf)(p->xlb)); p->xbot = bot + edge*p->xoff; p->xtop = p->xbot + (top-bot)*p->xsize; p->xb = p->xbot - (*p->xf)(p->xlb)*p->xa + .5; } axes() { register i; int mark[50]; int xn, yn; if(gridf==0) return; line(xd.xbot,yd.xbot,xd.xtop,yd.xbot); cont(xd.xtop,yd.xtop); cont(xd.xbot,yd.xtop); cont(xd.xbot,yd.xbot); xn = setmark(mark,&xd); for(i=0; ixf==log10&&!p->xqf) { for(x=p->xquant; xxub; x*=10) { submark(xmark,&xn,x,p); if(p->xub/p->xlb<=100) { submark(xmark,&xn,2*x,p); submark(xmark,&xn,5*x,p); } } } else { xn = 0; q = p->xquant; if(q>0) { xl = modceil(p->xlb+q/6,q); xu = modfloor(p->xub-q/6,q)+q/2; } else { xl = modceil(p->xub-q/6,q); xu = modfloor(p->xlb+q/6,q)-q/2; } for(x=xl; x<=xu; x+=fabs(p->xquant)) xmark[xn++] = (*p->xf)(x)*p->xa + p->xb; } return(xn); } submark(xmark,pxn,x,p) int *xmark; int *pxn; float x; struct xy *p; { if(1.001*p->xlb < x && .999*p->xub > x) xmark[(*pxn)++] = log10(x)*p->xa + p->xb; } plot() { int ix,iy; int i; int conn; conn = 0; if(mode!=0) linemod(modes[mode]); for(i=0; ixa*(*p->xf)(xv*p->xmult) + p->xb; if(ixxbot || ix>p->xtop) return(0); *ip = ix; return(1); } getfloat(p) float *p; { register i; i = scanf("%f",p); return(i==1); } getstring() { register i; char junk[20]; i = scanf("%1s",labbuf); if(i==-1) return(-1); switch(*labbuf) { default: if(!isdigit(*labbuf)) { ungetc(*labbuf,stdin); i = scanf("%s",labbuf); break; } case '.': case '+': case '-': ungetc(*labbuf,stdin); return(0); case '"': i = scanf("%[^\"\n]",labbuf); scanf("%[\"]",junk); break; } if(i==-1) return(-1); return(strlen(labbuf)); } symbol(ix,iy,k) { if(symbf==0&&k<0) { if(mode==0) point(ix,iy); return(1); } else { move(ix,iy); label(k>=0?labs+k:plotsymb); move(ix,iy); return(!brkf|k<0); } } title() { move(xd.xbot,yd.xbot-60); if (titlebuf[0]) { label(titlebuf); label(" "); } if(erasf&&gridf) { axlab('x',&xd); label(" "); axlab('y',&yd); } } axlab(c,p) char c; struct xy *p; { char buf[50]; sprintf(buf,"%g -%s%c- %g", p->xlb/p->xmult, p->xf==log10?"log ":"", c, p->xub/p->xmult); label(buf); } badarg() { fprintf(stderr,"graph: error in arguments\n"); exit(1); }