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