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