9 int xlbf; /*flag:explicit lower bound*/
10 int xubf; /*flag:explicit upper bound*/
11 int xqf; /*flag:explicit quantum*/
12 double (*xf)(double); /*transform function, e.g. log*/
13 float xa,xb; /*scaling coefficients*/
14 float xlb,xub; /*lower and upper bound*/
15 float xquant; /*quantum*/
16 float xoff; /*screen offset fraction*/
17 float xsize; /*screen fraction*/
18 int xbot,xtop; /*screen coords of border*/
19 float xmult; /*scaling constant*/
59 double ident(double x){
64 float lb,ub,mult,quant;
66 void init(struct xy *);
67 void setopt(int, char *[]);
70 void getlim(struct xy *, struct val *);
71 void equilibrate(struct xy *, struct xy *);
72 void scale(struct xy *);
73 void limread(struct xy *, int *, char ***);
74 int numb(float *, int *, char ***);
76 struct z setloglim(int, int, float, float);
77 struct z setlinlim(int, int, float, float);
79 int setmark(int *, struct xy *);
80 void submark(int *, int *, float, struct xy *);
82 int getfloat(float *);
86 int conv(float, struct xy *, int *);
87 int symbol(int, int, int);
88 void axlab(char, struct xy *, char *);
90 int main(int argc,char *argv[]){
96 xd.xsize = yd.xsize = 1.;
97 xx = (struct val *)malloc((unsigned)sizeof(struct val));
99 labels[labelsiz++] = 0;
105 getlim(&xd,(struct val *)&xx->xv);
106 getlim(&yd,(struct val *)&xx->yv);
108 equilibrate(&xd,&yd);
109 equilibrate(&yd,&xd);
121 void init(struct xy *p){
126 void setopt(int argc, char *argv[]){
130 xd.xlb = yd.xlb = INF;
131 xd.xub = yd.xub = -INF;
134 again: switch(argv[0][0]) {
138 case 'l': /* label for plot */
144 while (*p1++ = *p2++);
148 case 'd': /*disconnected,obsolete option*/
149 case 'm': /*line mode*/
151 if(!numb(&temp,&argc,&argv))
153 if(temp>=sizeof(modes)/sizeof(*modes))
160 if(numb(&temp,&argc,&argv) && temp>=1)
163 case 'a': /*automatic abscissas*/
166 if(!numb(&dx,&argc,&argv))
168 if(numb(&absbot,&argc,&argv))
172 case 's': /*save screen, overlay plot*/
176 case 'g': /*grid style 0 none, 1 ticks, 2 full*/
178 if(!numb(&temp,&argc,&argv))
179 temp = argv[0][1]-'0'; /*for caompatibility*/
184 case 'c': /*character(s) for plotting*/
193 case 't': /*transpose*/
196 case 'e': /*equal scales*/
202 case 'x': /*x limits */
203 limread(&xd,&argc,&argv);
206 limread(&yd,&argc,&argv);
208 case 'h': /*set height of plot */
209 if(!numb(&yd.xsize, &argc,&argv))
212 case 'w': /*set width of plot */
213 if(!numb(&xd.xsize, &argc, &argv))
216 case 'r': /* set offset to right */
217 if(!numb(&xd.xoff, &argc, &argv))
220 case 'u': /*set offset up the screen*/
221 if(!numb(&yd.xoff,&argc,&argv))
230 void limread(struct xy *p, int *argcp, char ***argvp){
231 if(*argcp>1 && (*argvp)[1][0]=='l') {
236 if(!numb(&p->xlb,argcp,argvp))
239 if(!numb(&p->xub,argcp,argvp))
242 if(!numb(&p->xquant,argcp,argvp))
249 return '0'<=c && c<='9';
254 numb(float *np, int *argcp, char ***argvp){
259 while((c=(*argvp)[1][0]) == '+')
261 if(!(isdigit((uchar)c) || c=='-'&&(*argvp)[1][1]<'A' || c=='.'))
263 *np = atof((*argvp)[1]);
276 else if(xd.xf==log10)
280 temp = (struct val *)realloc((char*)xx,
281 (unsigned)(n+ovlay)*sizeof(struct val));
286 xx[n].xv = n*dx/ovlay + absbot;
288 if(!getfloat(&xx[n].xv))
290 t = 0; /* silence compiler */
291 for(i=0;i<ovlay;i++) {
292 xx[n+i].xv = xx[n].xv;
293 if(!getfloat(&xx[n+i].yv))
298 xx[n+i].lblptr = copystring(t);
308 void transpose(void){
314 t = xd; xd = yd; yd = t;
316 f = xx[i].xv; xx[i].xv = xx[i].yv; xx[i].yv = f;
320 int copystring(int k){
325 temp = realloc(labels,(unsigned)(labelsiz+1+k));
331 labels[labelsiz++] = labbuf[i];
335 float modceil(float f, float t){
342 modfloor(float f, float t){
344 return(floor(f/t)*t);
347 void getlim(struct xy *p, struct val *v){
352 if(!p->xlbf && p->xlb>v[i].xv)
354 if(!p->xubf && p->xub<v[i].xv)
360 void setlim(struct xy *p){
371 if(delta*p->xquant <=0 )
387 else if(delta == 0) {
402 if(p->xf==log10 && lb>0 && ub>lb) {
403 z = setloglim(lbf,ubf,lb,ub);
408 if(setmark(mark,p)<2) {
409 p->xqf = lbf = ubf = 1;
410 lb = z.lb; ub = z.ub;
414 z = setlinlim(lbf,ubf,lb,ub);
423 p->xquant = sign*z.quant;
427 setloglim(int lbf, int ubf, float lb, float ub){
431 for(s=1; lb*s<1; s*=10) ;
434 for(r=1; 10*r<=lb; r*=10) ;
435 for(t=1; t<ub; t*=10) ;
436 z.lb = !lbf ? r : lb;
437 z.ub = !ubf ? t : ub;
442 else if(lb >= 2*z.lb)
448 else if(ub*2 <= z.ub)
458 setlinlim(int lbf, int ubf, float xlb, float xub){
467 /*scale up by s, a power of 10, so range (delta) exceeds 1*/
468 /*find power of 10 quantum, r, such that delta/10<=r<delta*/
477 /*set r=(1,2,5)*10**n so that 3-5 quanta cover range*/
482 z.ub = ubf? ub: modceil(ub,r);
483 z.lb = lbf? lb: modfloor(lb,r);
484 if(!lbf && z.lb<=r && z.lb>0) {
488 else if(!ubf && z.ub>=-r && z.ub<0) {
497 void scale(struct xy *p){
502 p->xa = p->xsize*edge/((*p->xf)(p->xub) - (*p->xf)(p->xlb));
503 p->xbot = bot + edge*p->xoff;
504 p->xtop = p->xbot + (top-bot)*p->xsize;
505 p->xb = p->xbot - (*p->xf)(p->xlb)*p->xa + .5;
508 void equilibrate(struct xy *p, struct xy *q){
509 if(p->xlbf|| /* needn't test xubf; it implies xlbf*/
510 q->xubf&&q->xlb>q->xub)
529 line(xd.xbot,yd.xbot,xd.xtop,yd.xbot);
530 vec(xd.xtop,yd.xtop);
531 vec(xd.xbot,yd.xtop);
532 vec(xd.xbot,yd.xbot);
534 xn = setmark(mark,&xd);
535 for(i=0; i<xn; i++) {
537 line(mark[i],yd.xbot,mark[i],yd.xtop);
539 line(mark[i],yd.xbot,mark[i],yd.xbot+tick);
540 line(mark[i],yd.xtop-tick,mark[i],yd.xtop);
543 yn = setmark(mark,&yd);
544 for(i=0; i<yn; i++) {
546 line(xd.xbot,mark[i],xd.xtop,mark[i]);
548 line(xd.xbot,mark[i],xd.xbot+tick,mark[i]);
549 line(xd.xtop-tick,mark[i],xd.xtop,mark[i]);
555 setmark(int *xmark, struct xy *p){
559 if(p->xf==log10&&!p->xqf) {
560 for(x=p->xquant; x<p->xub; x*=10) {
561 submark(xmark,&xn,x,p);
562 if(p->xub/p->xlb<=100) {
563 submark(xmark,&xn,2*x,p);
564 submark(xmark,&xn,5*x,p);
571 xl = modceil(p->xlb+q/6,q);
572 xu = modfloor(p->xub-q/6,q)+q/2;
574 xl = modceil(p->xub-q/6,q);
575 xu = modfloor(p->xlb+q/6,q)-q/2;
577 for(x=xl; x<=xu; x+=fabs(p->xquant))
578 xmark[xn++] = (*p->xf)(x)*p->xa + p->xb;
582 void submark(int *xmark, int *pxn, float x, struct xy *p){
583 if(1.001*p->xlb < x && .999*p->xub > x)
584 xmark[(*pxn)++] = log10(x)*p->xa + p->xb;
592 for(j=0;j<ovlay;j++) {
595 pen(modes[j%(sizeof modes/sizeof *modes-1)+1]);
603 for(i=j; i<n; i+=ovlay) {
604 if(!conv(xx[i].xv,&xd,&ix) ||
605 !conv(xx[i].yv,&yd,&iy)) {
616 conn &= symbol(ix,iy,xx[i].lblptr);
623 conv(float xv, struct xy *p, int *ip){
625 ix = p->xa*(*p->xf)(xv*p->xmult) + p->xb;
626 if(ix<p->xbot || ix>p->xtop)
644 i = scanf("%1s",labbuf);
649 if(!isdigit((uchar)*labbuf)) {
650 ungetc(*labbuf,stdin);
651 i = scanf("%s",labbuf);
657 ungetc(*labbuf,stdin);
660 i = scanf("%[^\"\n]",labbuf);
666 return(strlen(labbuf));
670 symbol(int ix, int iy, int k){
679 text(k>=0?labels+k:plotsymb);
690 strcpy(buf+3,titlebuf);
696 move(xd.xbot,yd.xbot-60);
700 void axlab(char c, struct xy *p, char *b){
702 dir = p->xlb<p->xub? "<=": ">=";
703 sprintf(b+strlen(b), " %g %s %c%s %s %g", p->xlb/p->xmult,
704 dir, c, p->xf==log10?" (log)":"", dir, p->xub/p->xmult);
708 fprintf(stderr,"graph: error in arguments\n");