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