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