1 #ifndef lint 2 static char sccsid[] = "@(#)graph.c 4.2 03/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 } 698