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