|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)graph.c 4.2 3/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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.