1: #ifndef lint 2: static char sccsid[] = "@(#)graph.c 4.2 3/30/83"; 3: #endif 4: 5: #include <stdio.h> 6: #include <ctype.h> 7: #include <math.h> 8: #define INF HUGE 9: #define F .25 10: 11: struct xy { 12: int xlbf; /*flag:explicit lower bound*/ 13: int xubf; /*flag:explicit upper bound*/ 14: int xqf; /*flag:explicit quantum*/ 15: double (*xf)(); /*transform function, e.g. log*/ 16: float xa,xb; /*scaling coefficients*/ 17: float xlb,xub; /*lower and upper bound*/ 18: float xquant; /*quantum*/ 19: float xoff; /*screen offset fraction*/ 20: float xsize; /*screen fraction*/ 21: int xbot,xtop; /*screen coords of border*/ 22: float xmult; /*scaling constant*/ 23: } xd,yd; 24: struct val { 25: float xv; 26: float yv; 27: int lblptr; 28: } *xx; 29: 30: char *labs; 31: int labsiz; 32: 33: int tick = 50; 34: int top = 4000; 35: int bot = 200; 36: float absbot; 37: int n; 38: int erasf = 1; 39: int gridf = 2; 40: int symbf = 0; 41: int absf = 0; 42: int transf; 43: int brkf; 44: float dx; 45: char *plotsymb; 46: 47: double atof(); 48: #define BSIZ 80 49: char labbuf[BSIZ]; 50: char titlebuf[BSIZ]; 51: 52: char *modes[] = { 53: "disconnected", 54: "solid", 55: "dotted", 56: "dotdashed", 57: "shortdashed", 58: "longdashed" 59: }; 60: int mode = 1; 61: char *realloc(); 62: char *malloc(); 63: 64: double ident(x) 65: double x; 66: { 67: return(x); 68: } 69: 70: main(argc,argv) 71: char *argv[]; 72: { 73: 74: space(0,0,4096,4096); 75: init(&xd); 76: init(&yd); 77: xd.xsize = yd.xsize = 1.; 78: xx = (struct val *)malloc((unsigned)sizeof(struct val)); 79: labs = malloc(1); 80: labs[labsiz++] = 0; 81: setopt(argc,argv); 82: if(erasf) 83: erase(); 84: readin(); 85: transpose(); 86: scale(&xd,(struct val *)&xx->xv); 87: scale(&yd,(struct val *)&xx->yv); 88: axes(); 89: title(); 90: plot(); 91: move(1,1); 92: closevt(); 93: return(0); 94: } 95: 96: init(p) 97: struct xy *p; 98: { 99: p->xf = ident; 100: p->xmult = 1; 101: } 102: 103: setopt(argc,argv) 104: char *argv[]; 105: { 106: char *p1, *p2; 107: float temp; 108: 109: xd.xlb = yd.xlb = INF; 110: xd.xub = yd.xub = -INF; 111: while(--argc > 0) { 112: argv++; 113: again: switch(argv[0][0]) { 114: case '-': 115: argv[0]++; 116: goto again; 117: case 'l': /* label for plot */ 118: p1 = titlebuf; 119: if (argc>=2) { 120: argv++; 121: argc--; 122: p2 = argv[0]; 123: while (*p1++ = *p2++); 124: } 125: break; 126: 127: case 'd': /*disconnected,obsolete option*/ 128: case 'm': /*line mode*/ 129: mode = 0; 130: if(!numb(&temp,&argc,&argv)) 131: break; 132: if(temp>=sizeof(modes)/sizeof(*modes)) 133: mode = 1; 134: else if(temp>=0) 135: mode = temp; 136: break; 137: 138: case 'a': /*automatic abscissas*/ 139: absf = 1; 140: dx = 1; 141: if(!numb(&dx,&argc,&argv)) 142: break; 143: if(numb(&absbot,&argc,&argv)) 144: absf = 2; 145: break; 146: 147: case 's': /*save screen, overlay plot*/ 148: erasf = 0; 149: break; 150: 151: case 'g': /*grid style 0 none, 1 ticks, 2 full*/ 152: gridf = 0; 153: if(!numb(&temp,&argc,&argv)) 154: temp = argv[0][1]-'0'; /*for caompatibility*/ 155: if(temp>=0&&temp<=2) 156: gridf = temp; 157: break; 158: 159: case 'c': /*character(s) for plotting*/ 160: if(argc >= 2) { 161: symbf = 1; 162: plotsymb = argv[1]; 163: argv++; 164: argc--; 165: } 166: break; 167: 168: case 't': /*transpose*/ 169: transf = 1; 170: break; 171: case 'b': /*breaks*/ 172: brkf = 1; 173: break; 174: case 'x': /*x limits */ 175: limread(&xd,&argc,&argv); 176: break; 177: case 'y': 178: limread(&yd,&argc,&argv); 179: break; 180: case 'h': /*set height of plot */ 181: if(!numb(&yd.xsize, &argc,&argv)) 182: badarg(); 183: break; 184: case 'w': /*set width of plot */ 185: if(!numb(&xd.xsize, &argc, &argv)) 186: badarg(); 187: break; 188: case 'r': /* set offset to right */ 189: if(!numb(&xd.xoff, &argc, &argv)) 190: badarg(); 191: break; 192: case 'u': /*set offset up the screen*/ 193: if(!numb(&yd.xoff,&argc,&argv)) 194: badarg(); 195: break; 196: default: 197: badarg(); 198: } 199: } 200: } 201: 202: limread(p, argcp, argvp) 203: register struct xy *p; 204: int *argcp; 205: char ***argvp; 206: { 207: if(*argcp>1 && (*argvp)[1][0]=='l') { 208: (*argcp)--; 209: (*argvp)++; 210: p->xf = log10; 211: } 212: if(!numb(&p->xlb,argcp,argvp)) 213: return; 214: p->xlbf = 1; 215: if(!numb(&p->xub,argcp,argvp)) 216: return; 217: p->xubf = 1; 218: if(!numb(&p->xquant,argcp,argvp)) 219: return; 220: p->xqf = 1; 221: } 222: 223: numb(np, argcp, argvp) 224: int *argcp; 225: float *np; 226: register char ***argvp; 227: { 228: register char c; 229: 230: if(*argcp <= 1) 231: return(0); 232: while((c=(*argvp)[1][0]) == '+') 233: (*argvp)[1]++; 234: if(!(isdigit(c) || c=='-'&&(*argvp)[1][1]<'A' || c=='.')) 235: return(0); 236: *np = atof((*argvp)[1]); 237: (*argcp)--; 238: (*argvp)++; 239: return(1); 240: } 241: 242: readin() 243: { 244: register t; 245: struct val *temp; 246: 247: if(absf==1) { 248: if(xd.xlbf) 249: absbot = xd.xlb; 250: else if(xd.xf==log10) 251: absbot = 1; 252: } 253: for(;;) { 254: temp = (struct val *)realloc((char*)xx, 255: (unsigned)(n+1)*sizeof(struct val)); 256: if(temp==0) 257: return; 258: xx = temp; 259: if(absf) 260: xx[n].xv = n*dx + absbot; 261: else 262: if(!getfloat(&xx[n].xv)) 263: return; 264: if(!getfloat(&xx[n].yv)) 265: return; 266: xx[n].lblptr = -1; 267: t = getstring(); 268: if(t>0) 269: xx[n].lblptr = copystring(t); 270: n++; 271: if(t<0) 272: return; 273: } 274: } 275: 276: transpose() 277: { 278: register i; 279: float f; 280: struct xy t; 281: if(!transf) 282: return; 283: t = xd; xd = yd; yd = t; 284: for(i= 0;i<n;i++) { 285: f = xx[i].xv; xx[i].xv = xx[i].yv; xx[i].yv = f; 286: } 287: } 288: 289: copystring(k) 290: { 291: register char *temp; 292: register i; 293: int q; 294: 295: temp = realloc(labs,(unsigned)(labsiz+1+k)); 296: if(temp==0) 297: return(0); 298: labs = temp; 299: q = labsiz; 300: for(i=0;i<=k;i++) 301: labs[labsiz++] = labbuf[i]; 302: return(q); 303: } 304: 305: float 306: modceil(f,t) 307: float f,t; 308: { 309: 310: t = fabs(t); 311: return(ceil(f/t)*t); 312: } 313: 314: float 315: modfloor(f,t) 316: float f,t; 317: { 318: t = fabs(t); 319: return(floor(f/t)*t); 320: } 321: 322: getlim(p,v) 323: register struct xy *p; 324: struct val *v; 325: { 326: register i; 327: 328: i = 0; 329: do { 330: if(!p->xlbf && p->xlb>v[i].xv) 331: p->xlb = v[i].xv; 332: if(!p->xubf && p->xub<v[i].xv) 333: p->xub = v[i].xv; 334: i++; 335: } while(i < n); 336: } 337: 338: struct z { 339: float lb,ub,mult,quant; 340: } setloglim(), setlinlim(); 341: 342: setlim(p) 343: register struct xy *p; 344: { 345: float t,delta,sign; 346: struct z z; 347: int mark[50]; 348: float lb,ub; 349: int lbf,ubf; 350: 351: lb = p->xlb; 352: ub = p->xub; 353: delta = ub-lb; 354: if(p->xqf) { 355: if(delta*p->xquant <=0 ) 356: badarg(); 357: return; 358: } 359: sign = 1; 360: lbf = p->xlbf; 361: ubf = p->xubf; 362: if(delta < 0) { 363: sign = -1; 364: t = lb; 365: lb = ub; 366: ub = t; 367: t = lbf; 368: lbf = ubf; 369: ubf = t; 370: } 371: else if(delta == 0) { 372: if(ub > 0) { 373: ub = 2*ub; 374: lb = 0; 375: } 376: else 377: if(lb < 0) { 378: lb = 2*lb; 379: ub = 0; 380: } 381: else { 382: ub = 1; 383: lb = -1; 384: } 385: } 386: if(p->xf==log10 && lb>0 && ub>lb) { 387: z = setloglim(lbf,ubf,lb,ub); 388: p->xlb = z.lb; 389: p->xub = z.ub; 390: p->xmult *= z.mult; 391: p->xquant = z.quant; 392: if(setmark(mark,p)<2) { 393: p->xqf = lbf = ubf = 1; 394: lb = z.lb; ub = z.ub; 395: } else 396: return; 397: } 398: z = setlinlim(lbf,ubf,lb,ub); 399: if(sign > 0) { 400: p->xlb = z.lb; 401: p->xub = z.ub; 402: } else { 403: p->xlb = z.ub; 404: p->xub = z.lb; 405: } 406: p->xmult *= z.mult; 407: p->xquant = sign*z.quant; 408: } 409: 410: struct z 411: setloglim(lbf,ubf,lb,ub) 412: float lb,ub; 413: { 414: float r,s,t; 415: struct z z; 416: 417: for(s=1; lb*s<1; s*=10) ; 418: lb *= s; 419: ub *= s; 420: for(r=1; 10*r<=lb; r*=10) ; 421: for(t=1; t<ub; t*=10) ; 422: z.lb = !lbf ? r : lb; 423: z.ub = !ubf ? t : ub; 424: if(ub/lb<100) { 425: if(!lbf) { 426: if(lb >= 5*z.lb) 427: z.lb *= 5; 428: else if(lb >= 2*z.lb) 429: z.lb *= 2; 430: } 431: if(!ubf) { 432: if(ub*5 <= z.ub) 433: z.ub /= 5; 434: else if(ub*2 <= z.ub) 435: z.ub /= 2; 436: } 437: } 438: z.mult = s; 439: z.quant = r; 440: return(z); 441: } 442: 443: struct z 444: setlinlim(lbf,ubf,xlb,xub) 445: int lbf,ubf; 446: float xlb,xub; 447: { 448: struct z z; 449: float r,s,delta; 450: float ub,lb; 451: 452: loop: 453: ub = xub; 454: lb = xlb; 455: delta = ub - lb; 456: /*scale up by s, a power of 10, so range (delta) exceeds 1*/ 457: /*find power of 10 quantum, r, such that delta/10<=r<delta*/ 458: r = s = 1; 459: while(delta*s < 10) 460: s *= 10; 461: delta *= s; 462: while(10*r < delta) 463: r *= 10; 464: lb *= s; 465: ub *= s; 466: /*set r=(1,2,5)*10**n so that 3-5 quanta cover range*/ 467: if(r>=delta/2) 468: r /= 2; 469: else if(r<delta/5) 470: r *= 2; 471: z.ub = ubf? ub: modceil(ub,r); 472: z.lb = lbf? lb: modfloor(lb,r); 473: if(!lbf && z.lb<=r && z.lb>0) { 474: xlb = 0; 475: goto loop; 476: } 477: else if(!ubf && z.ub>=-r && z.ub<0) { 478: xub = 0; 479: goto loop; 480: } 481: z.quant = r; 482: z.mult = s; 483: return(z); 484: } 485: 486: scale(p,v) 487: register struct xy *p; 488: struct val *v; 489: { 490: float edge; 491: 492: getlim(p,v); 493: setlim(p); 494: edge = top-bot; 495: p->xa = p->xsize*edge/((*p->xf)(p->xub) - (*p->xf)(p->xlb)); 496: p->xbot = bot + edge*p->xoff; 497: p->xtop = p->xbot + (top-bot)*p->xsize; 498: p->xb = p->xbot - (*p->xf)(p->xlb)*p->xa + .5; 499: } 500: 501: axes() 502: { 503: register i; 504: int mark[50]; 505: int xn, yn; 506: if(gridf==0) 507: return; 508: 509: line(xd.xbot,yd.xbot,xd.xtop,yd.xbot); 510: cont(xd.xtop,yd.xtop); 511: cont(xd.xbot,yd.xtop); 512: cont(xd.xbot,yd.xbot); 513: 514: xn = setmark(mark,&xd); 515: for(i=0; i<xn; i++) { 516: if(gridf==2) 517: line(mark[i],yd.xbot,mark[i],yd.xtop); 518: if(gridf==1) { 519: line(mark[i],yd.xbot,mark[i],yd.xbot+tick); 520: line(mark[i],yd.xtop-tick,mark[i],yd.xtop); 521: } 522: } 523: yn = setmark(mark,&yd); 524: for(i=0; i<yn; i++) { 525: if(gridf==2) 526: line(xd.xbot,mark[i],xd.xtop,mark[i]); 527: if(gridf==1) { 528: line(xd.xbot,mark[i],xd.xbot+tick,mark[i]); 529: line(xd.xtop-tick,mark[i],xd.xtop,mark[i]); 530: } 531: } 532: } 533: 534: setmark(xmark,p) 535: int *xmark; 536: register struct xy *p; 537: { 538: int xn = 0; 539: float x,xl,xu; 540: float q; 541: if(p->xf==log10&&!p->xqf) { 542: for(x=p->xquant; x<p->xub; x*=10) { 543: submark(xmark,&xn,x,p); 544: if(p->xub/p->xlb<=100) { 545: submark(xmark,&xn,2*x,p); 546: submark(xmark,&xn,5*x,p); 547: } 548: } 549: } else { 550: xn = 0; 551: q = p->xquant; 552: if(q>0) { 553: xl = modceil(p->xlb+q/6,q); 554: xu = modfloor(p->xub-q/6,q)+q/2; 555: } else { 556: xl = modceil(p->xub-q/6,q); 557: xu = modfloor(p->xlb+q/6,q)-q/2; 558: } 559: for(x=xl; x<=xu; x+=fabs(p->xquant)) 560: xmark[xn++] = (*p->xf)(x)*p->xa + p->xb; 561: } 562: return(xn); 563: } 564: submark(xmark,pxn,x,p) 565: int *xmark; 566: int *pxn; 567: float x; 568: struct xy *p; 569: { 570: if(1.001*p->xlb < x && .999*p->xub > x) 571: xmark[(*pxn)++] = log10(x)*p->xa + p->xb; 572: } 573: 574: plot() 575: { 576: int ix,iy; 577: int i; 578: int conn; 579: 580: conn = 0; 581: if(mode!=0) 582: linemod(modes[mode]); 583: for(i=0; i<n; i++) { 584: if(!conv(xx[i].xv,&xd,&ix) || 585: !conv(xx[i].yv,&yd,&iy)) { 586: conn = 0; 587: continue; 588: } 589: if(mode!=0) { 590: if(conn != 0) 591: cont(ix,iy); 592: else 593: move(ix,iy); 594: conn = 1; 595: } 596: conn &= symbol(ix,iy,xx[i].lblptr); 597: } 598: linemod(modes[1]); 599: } 600: 601: conv(xv,p,ip) 602: float xv; 603: register struct xy *p; 604: int *ip; 605: { 606: long ix; 607: ix = p->xa*(*p->xf)(xv*p->xmult) + p->xb; 608: if(ix<p->xbot || ix>p->xtop) 609: return(0); 610: *ip = ix; 611: return(1); 612: } 613: 614: getfloat(p) 615: float *p; 616: { 617: register i; 618: 619: i = scanf("%f",p); 620: return(i==1); 621: } 622: 623: getstring() 624: { 625: register i; 626: char junk[20]; 627: i = scanf("%1s",labbuf); 628: if(i==-1) 629: return(-1); 630: switch(*labbuf) { 631: default: 632: if(!isdigit(*labbuf)) { 633: ungetc(*labbuf,stdin); 634: i = scanf("%s",labbuf); 635: break; 636: } 637: case '.': 638: case '+': 639: case '-': 640: ungetc(*labbuf,stdin); 641: return(0); 642: case '"': 643: i = scanf("%[^\"\n]",labbuf); 644: scanf("%[\"]",junk); 645: break; 646: } 647: if(i==-1) 648: return(-1); 649: return(strlen(labbuf)); 650: } 651: 652: 653: symbol(ix,iy,k) 654: { 655: 656: if(symbf==0&&k<0) { 657: if(mode==0) 658: point(ix,iy); 659: return(1); 660: } 661: else { 662: move(ix,iy); 663: label(k>=0?labs+k:plotsymb); 664: move(ix,iy); 665: return(!brkf|k<0); 666: } 667: } 668: 669: title() 670: { 671: move(xd.xbot,yd.xbot-60); 672: if (titlebuf[0]) { 673: label(titlebuf); 674: label(" "); 675: } 676: if(erasf&&gridf) { 677: axlab('x',&xd); 678: label(" "); 679: axlab('y',&yd); 680: } 681: } 682: 683: axlab(c,p) 684: char c; 685: struct xy *p; 686: { 687: char buf[50]; 688: sprintf(buf,"%g -%s%c- %g", p->xlb/p->xmult, 689: p->xf==log10?"log ":"", c, p->xub/p->xmult); 690: label(buf); 691: } 692: 693: badarg() 694: { 695: fprintf(stderr,"graph: error in arguments\n"); 696: exit(1); 697: }