Blob


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
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;
27 char *labels;
28 int labelsiz;
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;
46 #define BSIZ 80
47 char labbuf[BSIZ];
48 char titlebuf[BSIZ];
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 }
63 struct z {
64 float lb,ub,mult,quant;
65 };
66 void init(struct xy *);
67 void setopt(int, char *[]);
68 void readin(void);
69 void transpose(void);
70 void getlim(struct xy *, struct val *);
71 void equilibrate(struct xy *, struct xy *);
72 void scale(struct xy *);
73 void limread(struct xy *, int *, char ***);
74 int numb(float *, int *, char ***);
75 int copystring(int);
76 struct z setloglim(int, int, float, float);
77 struct z setlinlim(int, int, float, float);
78 void axes(void);
79 int setmark(int *, struct xy *);
80 void submark(int *, int *, float, struct xy *);
81 void plot(void);
82 int getfloat(float *);
83 int getstring(void);
84 void title(void);
85 void badarg(void);
86 int conv(float, struct xy *, int *);
87 int symbol(int, int, int);
88 void axlab(char, struct xy *, char *);
90 int main(int argc,char *argv[]){
92 openpl();
93 range(0,0,4096,4096);
94 init(&xd);
95 init(&yd);
96 xd.xsize = yd.xsize = 1.;
97 xx = (struct val *)malloc((unsigned)sizeof(struct val));
98 labels = malloc(1);
99 labels[labelsiz++] = 0;
100 setopt(argc,argv);
101 if(erasf)
102 erase();
103 readin();
104 transpose();
105 getlim(&xd,(struct val *)&xx->xv);
106 getlim(&yd,(struct val *)&xx->yv);
107 if(equf) {
108 equilibrate(&xd,&yd);
109 equilibrate(&yd,&xd);
111 scale(&xd);
112 scale(&yd);
113 axes();
114 title();
115 plot();
116 closepl();
117 exits(0);
118 return 0; /* gcc */
121 void init(struct xy *p){
122 p->xf = ident;
123 p->xmult = 1;
126 void setopt(int argc, char *argv[]){
127 char *p1, *p2;
128 float temp;
130 xd.xlb = yd.xlb = INF;
131 xd.xub = yd.xub = -INF;
132 while(--argc > 0) {
133 argv++;
134 again: switch(argv[0][0]) {
135 case '-':
136 argv[0]++;
137 goto again;
138 case 'l': /* label for plot */
139 p1 = titlebuf;
140 if (argc>=2) {
141 argv++;
142 argc--;
143 p2 = argv[0];
144 while (*p1++ = *p2++);
146 break;
148 case 'd': /*disconnected,obsolete option*/
149 case 'm': /*line mode*/
150 mode = 0;
151 if(!numb(&temp,&argc,&argv))
152 break;
153 if(temp>=sizeof(modes)/sizeof(*modes))
154 mode = 1;
155 else if(temp>=-1)
156 mode = temp;
157 break;
159 case 'o':
160 if(numb(&temp,&argc,&argv) && temp>=1)
161 ovlay = temp;
162 break;
163 case 'a': /*automatic abscissas*/
164 absf = 1;
165 dx = 1;
166 if(!numb(&dx,&argc,&argv))
167 break;
168 if(numb(&absbot,&argc,&argv))
169 absf = 2;
170 break;
172 case 's': /*save screen, overlay plot*/
173 erasf = 0;
174 break;
176 case 'g': /*grid style 0 none, 1 ticks, 2 full*/
177 gridf = 0;
178 if(!numb(&temp,&argc,&argv))
179 temp = argv[0][1]-'0'; /*for caompatibility*/
180 if(temp>=0&&temp<=2)
181 gridf = temp;
182 break;
184 case 'c': /*character(s) for plotting*/
185 if(argc >= 2) {
186 symbf = 1;
187 plotsymb = argv[1];
188 argv++;
189 argc--;
191 break;
193 case 't': /*transpose*/
194 transf = 1;
195 break;
196 case 'e': /*equal scales*/
197 equf = 1;
198 break;
199 case 'b': /*breaks*/
200 brkf = 1;
201 break;
202 case 'x': /*x limits */
203 limread(&xd,&argc,&argv);
204 break;
205 case 'y':
206 limread(&yd,&argc,&argv);
207 break;
208 case 'h': /*set height of plot */
209 if(!numb(&yd.xsize, &argc,&argv))
210 badarg();
211 break;
212 case 'w': /*set width of plot */
213 if(!numb(&xd.xsize, &argc, &argv))
214 badarg();
215 break;
216 case 'r': /* set offset to right */
217 if(!numb(&xd.xoff, &argc, &argv))
218 badarg();
219 break;
220 case 'u': /*set offset up the screen*/
221 if(!numb(&yd.xoff,&argc,&argv))
222 badarg();
223 break;
224 default:
225 badarg();
230 void limread(struct xy *p, int *argcp, char ***argvp){
231 if(*argcp>1 && (*argvp)[1][0]=='l') {
232 (*argcp)--;
233 (*argvp)++;
234 p->xf = log10;
236 if(!numb(&p->xlb,argcp,argvp))
237 return;
238 p->xlbf = 1;
239 if(!numb(&p->xub,argcp,argvp))
240 return;
241 p->xubf = 1;
242 if(!numb(&p->xquant,argcp,argvp))
243 return;
244 p->xqf = 1;
247 #ifdef NOTDEF
248 isdigit(char c){
249 return '0'<=c && c<='9';
251 #endif
253 int
254 numb(float *np, int *argcp, char ***argvp){
255 char c;
257 if(*argcp <= 1)
258 return(0);
259 while((c=(*argvp)[1][0]) == '+')
260 (*argvp)[1]++;
261 if(!(isdigit(c) || c=='-'&&(*argvp)[1][1]<'A' || c=='.'))
262 return(0);
263 *np = atof((*argvp)[1]);
264 (*argcp)--;
265 (*argvp)++;
266 return(1);
269 void readin(void){
270 int i, t;
271 struct val *temp;
273 if(absf==1) {
274 if(xd.xlbf)
275 absbot = xd.xlb;
276 else if(xd.xf==log10)
277 absbot = 1;
279 for(;;) {
280 temp = (struct val *)realloc((char*)xx,
281 (unsigned)(n+ovlay)*sizeof(struct val));
282 if(temp==0)
283 return;
284 xx = temp;
285 if(absf)
286 xx[n].xv = n*dx/ovlay + absbot;
287 else
288 if(!getfloat(&xx[n].xv))
289 return;
290 t = 0; /* silence compiler */
291 for(i=0;i<ovlay;i++) {
292 xx[n+i].xv = xx[n].xv;
293 if(!getfloat(&xx[n+i].yv))
294 return;
295 xx[n+i].lblptr = -1;
296 t = getstring();
297 if(t>0)
298 xx[n+i].lblptr = copystring(t);
299 if(t<0 && i+1<ovlay)
300 return;
302 n += ovlay;
303 if(t<0)
304 return;
308 void transpose(void){
309 int i;
310 float f;
311 struct xy t;
312 if(!transf)
313 return;
314 t = xd; xd = yd; yd = t;
315 for(i= 0;i<n;i++) {
316 f = xx[i].xv; xx[i].xv = xx[i].yv; xx[i].yv = f;
320 int copystring(int k){
321 char *temp;
322 int i;
323 int q;
325 temp = realloc(labels,(unsigned)(labelsiz+1+k));
326 if(temp==0)
327 return(0);
328 labels = temp;
329 q = labelsiz;
330 for(i=0;i<=k;i++)
331 labels[labelsiz++] = labbuf[i];
332 return(q);
335 float modceil(float f, float t){
337 t = fabs(t);
338 return(ceil(f/t)*t);
341 float
342 modfloor(float f, float t){
343 t = fabs(t);
344 return(floor(f/t)*t);
347 void getlim(struct xy *p, struct val *v){
348 int i;
350 i = 0;
351 do {
352 if(!p->xlbf && p->xlb>v[i].xv)
353 p->xlb = v[i].xv;
354 if(!p->xubf && p->xub<v[i].xv)
355 p->xub = v[i].xv;
356 i++;
357 } while(i < n);
360 void setlim(struct xy *p){
361 float t,delta,sign;
362 struct z z;
363 int mark[50];
364 float lb,ub;
365 int lbf,ubf;
367 lb = p->xlb;
368 ub = p->xub;
369 delta = ub-lb;
370 if(p->xqf) {
371 if(delta*p->xquant <=0 )
372 badarg();
373 return;
375 sign = 1;
376 lbf = p->xlbf;
377 ubf = p->xubf;
378 if(delta < 0) {
379 sign = -1;
380 t = lb;
381 lb = ub;
382 ub = t;
383 t = lbf;
384 lbf = ubf;
385 ubf = t;
387 else if(delta == 0) {
388 if(ub > 0) {
389 ub = 2*ub;
390 lb = 0;
392 else
393 if(lb < 0) {
394 lb = 2*lb;
395 ub = 0;
397 else {
398 ub = 1;
399 lb = -1;
402 if(p->xf==log10 && lb>0 && ub>lb) {
403 z = setloglim(lbf,ubf,lb,ub);
404 p->xlb = z.lb;
405 p->xub = z.ub;
406 p->xmult *= z.mult;
407 p->xquant = z.quant;
408 if(setmark(mark,p)<2) {
409 p->xqf = lbf = ubf = 1;
410 lb = z.lb; ub = z.ub;
411 } else
412 return;
414 z = setlinlim(lbf,ubf,lb,ub);
415 if(sign > 0) {
416 p->xlb = z.lb;
417 p->xub = z.ub;
418 } else {
419 p->xlb = z.ub;
420 p->xub = z.lb;
422 p->xmult *= z.mult;
423 p->xquant = sign*z.quant;
426 struct z
427 setloglim(int lbf, int ubf, float lb, float ub){
428 float r,s,t;
429 struct z z;
431 for(s=1; lb*s<1; s*=10) ;
432 lb *= s;
433 ub *= s;
434 for(r=1; 10*r<=lb; r*=10) ;
435 for(t=1; t<ub; t*=10) ;
436 z.lb = !lbf ? r : lb;
437 z.ub = !ubf ? t : ub;
438 if(ub/lb<100) {
439 if(!lbf) {
440 if(lb >= 5*z.lb)
441 z.lb *= 5;
442 else if(lb >= 2*z.lb)
443 z.lb *= 2;
445 if(!ubf) {
446 if(ub*5 <= z.ub)
447 z.ub /= 5;
448 else if(ub*2 <= z.ub)
449 z.ub /= 2;
452 z.mult = s;
453 z.quant = r;
454 return(z);
457 struct z
458 setlinlim(int lbf, int ubf, float xlb, float xub){
459 struct z z;
460 float r,s,delta;
461 float ub,lb;
463 loop:
464 ub = xub;
465 lb = xlb;
466 delta = ub - lb;
467 /*scale up by s, a power of 10, so range (delta) exceeds 1*/
468 /*find power of 10 quantum, r, such that delta/10<=r<delta*/
469 r = s = 1;
470 while(delta*s < 10)
471 s *= 10;
472 delta *= s;
473 while(10*r < delta)
474 r *= 10;
475 lb *= s;
476 ub *= s;
477 /*set r=(1,2,5)*10**n so that 3-5 quanta cover range*/
478 if(r>=delta/2)
479 r /= 2;
480 else if(r<delta/5)
481 r *= 2;
482 z.ub = ubf? ub: modceil(ub,r);
483 z.lb = lbf? lb: modfloor(lb,r);
484 if(!lbf && z.lb<=r && z.lb>0) {
485 xlb = 0;
486 goto loop;
488 else if(!ubf && z.ub>=-r && z.ub<0) {
489 xub = 0;
490 goto loop;
492 z.quant = r;
493 z.mult = s;
494 return(z);
497 void scale(struct xy *p){
498 float edge;
500 setlim(p);
501 edge = top-bot;
502 p->xa = p->xsize*edge/((*p->xf)(p->xub) - (*p->xf)(p->xlb));
503 p->xbot = bot + edge*p->xoff;
504 p->xtop = p->xbot + (top-bot)*p->xsize;
505 p->xb = p->xbot - (*p->xf)(p->xlb)*p->xa + .5;
508 void equilibrate(struct xy *p, struct xy *q){
509 if(p->xlbf|| /* needn't test xubf; it implies xlbf*/
510 q->xubf&&q->xlb>q->xub)
511 return;
512 if(p->xlb>q->xlb) {
513 p->xlb = q->xlb;
514 p->xlbf = q->xlbf;
516 if(p->xub<q->xub) {
517 p->xub = q->xub;
518 p->xubf = q->xubf;
522 void axes(void){
523 int i;
524 int mark[50];
525 int xn, yn;
526 if(gridf==0)
527 return;
529 line(xd.xbot,yd.xbot,xd.xtop,yd.xbot);
530 vec(xd.xtop,yd.xtop);
531 vec(xd.xbot,yd.xtop);
532 vec(xd.xbot,yd.xbot);
534 xn = setmark(mark,&xd);
535 for(i=0; i<xn; i++) {
536 if(gridf==2)
537 line(mark[i],yd.xbot,mark[i],yd.xtop);
538 if(gridf==1) {
539 line(mark[i],yd.xbot,mark[i],yd.xbot+tick);
540 line(mark[i],yd.xtop-tick,mark[i],yd.xtop);
543 yn = setmark(mark,&yd);
544 for(i=0; i<yn; i++) {
545 if(gridf==2)
546 line(xd.xbot,mark[i],xd.xtop,mark[i]);
547 if(gridf==1) {
548 line(xd.xbot,mark[i],xd.xbot+tick,mark[i]);
549 line(xd.xtop-tick,mark[i],xd.xtop,mark[i]);
554 int
555 setmark(int *xmark, struct xy *p){
556 int xn = 0;
557 float x,xl,xu;
558 float q;
559 if(p->xf==log10&&!p->xqf) {
560 for(x=p->xquant; x<p->xub; x*=10) {
561 submark(xmark,&xn,x,p);
562 if(p->xub/p->xlb<=100) {
563 submark(xmark,&xn,2*x,p);
564 submark(xmark,&xn,5*x,p);
567 } else {
568 xn = 0;
569 q = p->xquant;
570 if(q>0) {
571 xl = modceil(p->xlb+q/6,q);
572 xu = modfloor(p->xub-q/6,q)+q/2;
573 } else {
574 xl = modceil(p->xub-q/6,q);
575 xu = modfloor(p->xlb+q/6,q)-q/2;
577 for(x=xl; x<=xu; x+=fabs(p->xquant))
578 xmark[xn++] = (*p->xf)(x)*p->xa + p->xb;
580 return(xn);
582 void submark(int *xmark, int *pxn, float x, struct xy *p){
583 if(1.001*p->xlb < x && .999*p->xub > x)
584 xmark[(*pxn)++] = log10(x)*p->xa + p->xb;
587 void plot(void){
588 int ix,iy;
589 int i,j;
590 int conn;
592 for(j=0;j<ovlay;j++) {
593 switch(mode) {
594 case -1:
595 pen(modes[j%(sizeof modes/sizeof *modes-1)+1]);
596 break;
597 case 0:
598 break;
599 default:
600 pen(modes[mode]);
602 conn = 0;
603 for(i=j; i<n; i+=ovlay) {
604 if(!conv(xx[i].xv,&xd,&ix) ||
605 !conv(xx[i].yv,&yd,&iy)) {
606 conn = 0;
607 continue;
609 if(mode!=0) {
610 if(conn != 0)
611 vec(ix,iy);
612 else
613 move(ix,iy);
614 conn = 1;
616 conn &= symbol(ix,iy,xx[i].lblptr);
619 pen(modes[1]);
622 int
623 conv(float xv, struct xy *p, int *ip){
624 long ix;
625 ix = p->xa*(*p->xf)(xv*p->xmult) + p->xb;
626 if(ix<p->xbot || ix>p->xtop)
627 return(0);
628 *ip = ix;
629 return(1);
632 int
633 getfloat(float *p){
634 int i;
636 i = scanf("%f",p);
637 return(i==1);
640 int
641 getstring(void){
642 int i;
643 char junk[20];
644 i = scanf("%1s",labbuf);
645 if(i==-1)
646 return(-1);
647 switch(*labbuf) {
648 default:
649 if(!isdigit(*labbuf)) {
650 ungetc(*labbuf,stdin);
651 i = scanf("%s",labbuf);
652 break;
654 case '.':
655 case '+':
656 case '-':
657 ungetc(*labbuf,stdin);
658 return(0);
659 case '"':
660 i = scanf("%[^\"\n]",labbuf);
661 scanf("%[\"]",junk);
662 break;
664 if(i==-1)
665 return(-1);
666 return(strlen(labbuf));
669 int
670 symbol(int ix, int iy, int k){
672 if(symbf==0&&k<0) {
673 if(mode==0)
674 point(ix,iy);
675 return(1);
677 else {
678 move(ix,iy);
679 text(k>=0?labels+k:plotsymb);
680 move(ix,iy);
681 return(!brkf|k<0);
685 void title(void){
686 char buf[BSIZ+100];
687 buf[0] = ' ';
688 buf[1] = ' ';
689 buf[2] = ' ';
690 strcpy(buf+3,titlebuf);
691 if(erasf&&gridf) {
692 axlab('x',&xd,buf);
693 strcat(buf,",");
694 axlab('y',&yd,buf);
696 move(xd.xbot,yd.xbot-60);
697 text(buf);
700 void axlab(char c, struct xy *p, char *b){
701 char *dir;
702 dir = p->xlb<p->xub? "<=": ">=";
703 sprintf(b+strlen(b), " %g %s %c%s %s %g", p->xlb/p->xmult,
704 dir, c, p->xf==log10?" (log)":"", dir, p->xub/p->xmult);
707 void badarg(void){
708 fprintf(stderr,"graph: error in arguments\n");
709 closepl();
710 exits("bad arg");