|
|
1.1 root 1: #include <stdio.h>
2: #include "grap.h"
3: #include "y.tab.h"
4:
5: #define MAXTICK 200
6: int ntick = 0;
7: double tickval[MAXTICK]; /* tick values (one axis at a time */
8: char *tickstr[MAXTICK]; /* and labels */
9:
10: int tside = 0;
11: int tlist = 0; /* 1 => explicit values given */
12: int toffside = 0; /* no ticks on these sides */
13: int tick_dir = OUT;
14: double ticklen = TICKLEN; /* default tick length */
15: int autoticks = LEFT|BOT;
16: int autodir = 0; /* set LEFT, etc. if automatic ticks go in */
17:
18: savetick(f, s) /* remember tick location and label */
19: double f;
20: char *s;
21: {
22: if (ntick >= MAXTICK)
23: fatal("too many ticks (%d)", MAXTICK);
24: tickval[ntick] = f;
25: tickstr[ntick] = s;
26: ntick++;
27: }
28:
29: dflt_tick(f)
30: double f;
31: {
32: if (f >= 0.0)
33: savetick(f, tostring("%g"));
34: else
35: savetick(f, tostring("\\%g"));
36: }
37:
38: tickside(n) /* remember which side these ticks go on */
39: int n;
40: {
41: tside |= n;
42: }
43:
44: tickoff(side) /* remember explicit sides */
45: int side;
46: {
47: toffside |= side;
48: }
49:
50: setlist() /* remember that there was an explicit list */
51: {
52: tlist = 1;
53: }
54:
55: tickdir(dir, val, explicit) /* remember in/out [expr] */
56: int dir, explicit;
57: double val;
58: {
59: tick_dir = dir;
60: if (explicit)
61: ticklen = val;
62: }
63:
64: ticks() /* set autoticks after ticks statement */
65: {
66: /* was there an explicit "ticks [side] off"? */
67: if (toffside)
68: autoticks &= ~toffside;
69: /* was there an explicit list? (eg "ticks at ..." or "ticks from ...") */
70: if (tlist) {
71: if (tside & (BOT|TOP))
72: autoticks &= ~(BOT|TOP);
73: if (tside & (LEFT|RIGHT))
74: autoticks &= ~(LEFT|RIGHT);
75: }
76: /* was there a side without a list? (eg "ticks left in") */
77: if (tside && !tlist) {
78: if (tick_dir == IN)
79: autodir |= tside;
80: if (tside & (BOT|TOP))
81: autoticks = (autoticks & ~(BOT|TOP)) | (tside & (BOT|TOP));
82: if (tside & (LEFT|RIGHT))
83: autoticks = (autoticks & ~(LEFT|RIGHT)) | (tside & (LEFT|RIGHT));
84: }
85: tlist = tside = toffside = 0;
86: tick_dir = OUT;
87: }
88:
89: double modfloor(f, t)
90: double f, t;
91: {
92: t = fabs(t);
93: return floor(f/t) * t;
94: }
95:
96: double modceil(f, t)
97: double f, t;
98: {
99: t = fabs(t);
100: return ceil(f/t) * t;
101: }
102:
103: double xtmin, xtmax; /* range of ticks */
104: double ytmin, ytmax;
105: double xquant, xmult; /* quantization & scale for auto x ticks */
106: double yquant, ymult;
107: double lograt = 5;
108:
109: do_autoticks(p) /* make set of ticks for default coord only */
110: Obj *p;
111: {
112: double x, xl, xu, q;
113:
114: if (p == NULL)
115: return;
116: fprintf(tfd, "Autoticks:\t# x %g..%g, y %g..%g",
117: p->pt.x, p->pt1.x, p->pt.y, p->pt1.y);
118: fprintf(tfd, "; xt %g,%g, yt %g,%g, xq,xm = %g,%g, yq,ym = %g,%g\n",
119: xtmin, xtmax, ytmin, ytmax, xquant, xmult, yquant, ymult);
120: if ((autoticks & (BOT|TOP)) && p->pt1.x >= p->pt.x) { /* make x ticks */
121: q = xquant;
122: xl = p->pt.x;
123: xu = p->pt1.x;
124: if (xl >= xu)
125: dflt_tick(xl);
126: else if ((p->log & XFLAG) && xu/xl >= lograt) {
127: for (x = q; x < xu; x *= 10) {
128: logtick(x, xl, xu);
129: if (xu/xl <= 100) {
130: logtick(2*x, xl, xu);
131: logtick(5*x, xl, xu);
132: }
133: }
134: } else {
135: xl = modceil(xtmin - q/100, q);
136: xu = modfloor(xtmax + q/100, q) + q/2;
137: for (x = xl; x <= xu; x += q)
138: dflt_tick(x);
139: }
140: tside = autoticks & (BOT|TOP);
141: ticklist(p, 0);
142: }
143: if ((autoticks & (LEFT|RIGHT)) && p->pt1.y >= p->pt.y) { /* make y ticks */
144: q = yquant;
145: xl = p->pt.y;
146: xu = p->pt1.y;
147: if (xl >= xu)
148: dflt_tick(xl);
149: else if ((p->log & YFLAG) && xu/xl >= lograt) {
150: for (x = q; x < xu; x *= 10) {
151: logtick(x, xl, xu);
152: if (xu/xl <= 100) {
153: logtick(2*x, xl, xu);
154: logtick(5*x, xl, xu);
155: }
156: }
157: } else {
158: xl = modceil(ytmin - q/100, q);
159: xu = modfloor(ytmax + q/100, q) + q/2;
160: for (x = xl; x <= xu; x += q)
161: dflt_tick(x);
162: }
163: tside = autoticks & (LEFT|RIGHT);
164: ticklist(p, 0);
165: }
166: }
167:
168: logtick(v, lb, ub)
169: double v, lb, ub;
170: {
171: float slop = 1.0; /* was 1.001 */
172:
173: if (slop * lb <= v && ub >= slop * v)
174: dflt_tick(v);
175: }
176:
177: Obj *setauto() /* compute new min,max, and quant & mult */
178: {
179: Obj *p, *q;
180:
181: if ((q = lookup("lograt",0)) != NULL)
182: lograt = q->fval;
183: for (p = objlist; p; p = p->next)
184: if (p->type == NAME && strcmp(p->name,dflt_coord) == 0)
185: break;
186: if (p) {
187: if ((p->log & XFLAG) && p->pt1.x/p->pt.x >= lograt)
188: autolog(p, 'x');
189: else
190: autoside(p, 'x');
191: if ((p->log & YFLAG) && p->pt1.y/p->pt.y >= lograt)
192: autolog(p, 'y');
193: else
194: autoside(p, 'y');
195: }
196: return p;
197: }
198:
199: autoside(p, side)
200: Obj *p;
201: int side;
202: {
203: double r, s, d, ub, lb;
204:
205: if (side == 'x') {
206: xtmin = lb = p->pt.x;
207: xtmax = ub = p->pt1.x;
208: } else {
209: ytmin = lb = p->pt.y;
210: ytmax = ub = p->pt1.y;
211: }
212: if (ub <= lb)
213: return 0; /* cop out on little ranges */
214: d = ub - lb;
215: r = s = 1;
216: while (d * s < 10)
217: s *= 10;
218: d *= s;
219: lb *= s;
220: ub *= s;
221: while (10 * r < d)
222: r *= 10;
223: if (r > d/3)
224: r /= 2;
225: else if (r <= d/6)
226: r *= 2;
227: if (side == 'x') {
228: xquant = r / s;
229: } else {
230: yquant = r / s;
231: }
232: }
233:
234: autolog(p, side)
235: Obj *p;
236: int side;
237: {
238: double r, s, t, d, ub, lb;
239: int flg;
240:
241: if (side == 'x') {
242: xtmin = lb = p->pt.x;
243: xtmax = ub = p->pt1.x;
244: flg = p->coord & XFLAG;
245: } else {
246: ytmin = lb = p->pt.y;
247: ytmax = ub = p->pt1.y;
248: flg = p->coord & YFLAG;
249: }
250: for (s = 1; lb * s < 1; s *= 10)
251: ;
252: lb *= s;
253: ub *= s;
254: for (r = 1; 10 * r < lb; r *= 10)
255: ;
256: for (t = 1; t < ub; t *= 10)
257: ;
258: if (side == 'x')
259: xquant = r / s;
260: else
261: yquant = r / s;
262: if (flg)
263: return;
264: if (ub / lb < 100) {
265: if (lb >= 5 * r)
266: r *= 5;
267: else if (lb >= 2 * r)
268: r *= 2;
269: if (ub * 5 <= t)
270: t /= 5;
271: else if (ub * 2 <= t)
272: t /= 2;
273: if (side == 'x') {
274: xtmin = r / s;
275: xtmax = t / s;
276: } else {
277: ytmin = r / s;
278: ytmax = t / s;
279: }
280: }
281: }
282:
283: iterator(from, to, op, by, fmt) /* create an iterator */
284: double from, to, by;
285: int op;
286: char *fmt;
287: {
288: double x;
289:
290: /* should validate limits, etc. */
291: /* punt for now */
292:
293: dprintf("iterate from %g to %g by %g, op = %c, fmt=%s\n",
294: from, to, by, op, fmt ? fmt : "");
295: switch (op) {
296: case '+':
297: case ' ':
298: for (x = from; x <= to + (SLOP-1) * by; x += by)
299: if (fmt)
300: savetick(x, tostring(fmt));
301: else
302: dflt_tick(x);
303: break;
304: case '-':
305: for (x = from; x >= to; x -= by)
306: if (fmt)
307: savetick(x, tostring(fmt));
308: else
309: dflt_tick(x);
310: break;
311: case '*':
312: for (x = from; x <= SLOP * to; x *= by)
313: if (fmt)
314: savetick(x, tostring(fmt));
315: else
316: dflt_tick(x);
317: break;
318: case '/':
319: for (x = from; x >= to; x /= by)
320: if (fmt)
321: savetick(x, tostring(fmt));
322: else
323: dflt_tick(x);
324: break;
325: }
326: if (fmt)
327: free(fmt);
328: }
329:
330: ticklist(p, explicit) /* fire out the accumulated ticks */
331: Obj *p;
332: int explicit; /* 1 => list, 0 => auto */
333: {
334: if (p == NULL)
335: return;
336: fprintf(tfd, "Ticks_%s:\n\tticklen = %g\n", p->name, ticklen);
337: print_ticks(TICKS, explicit, p, "ticklen", "");
338: }
339:
340: print_ticks(type, explicit, p, lenstr, descstr)
341: int type, explicit;
342: Obj *p;
343: char *lenstr, *descstr;
344: {
345: int i, logflag, inside;
346: char buf[100];
347: double tv;
348:
349: for (i = 0; i < ntick; i++) /* any ticks given explicitly? */
350: if (tickstr[i] != NULL)
351: break;
352: if (i >= ntick && type == TICKS) /* no, so use values */
353: for (i = 0; i < ntick; i++) {
354: if (tickval[i] >= 0.0)
355: sprintf(buf, "%g", tickval[i]);
356: else
357: sprintf(buf, "\\-%g", -tickval[i]);
358: tickstr[i] = tostring(buf);
359: }
360: else
361: for (i = 0; i < ntick; i++) {
362: if (tickstr[i] != NULL) {
363: sprintf(buf, tickstr[i], tickval[i]);
364: free(tickstr[i]);
365: tickstr[i] = tostring(buf);
366: }
367: }
368: logflag = sidelog(p->log, tside);
369: for (i = 0; i < ntick; i++) {
370: tv = tickval[i];
371: halfrange(p, tside, tv);
372: if (logflag) {
373: if (tv <= 0.0)
374: fatal("can't take log of tick value %g", tv);
375: logit(tv);
376: }
377: if (type == GRID)
378: inside = LEFT|RIGHT|TOP|BOT;
379: else if (explicit)
380: inside = (tick_dir == IN) ? tside : 0;
381: else
382: inside = autodir;
383: if (tside & BOT)
384: maketick(p->name, BOT, inside, tv, tickstr[i], lenstr, descstr);
385: if (tside & TOP)
386: maketick(p->name, TOP, inside, tv, tickstr[i], lenstr, descstr);
387: if (tside & LEFT)
388: maketick(p->name, LEFT, inside, tv, tickstr[i], lenstr, descstr);
389: if (tside & RIGHT)
390: maketick(p->name, RIGHT, inside, tv, tickstr[i], lenstr, descstr);
391: if (tickstr[i]) {
392: free(tickstr[i]);
393: tickstr[i] = NULL;
394: }
395: }
396: ntick = 0;
397: }
398:
399: maketick(name, side, inflag, val, lab, lenstr, descstr)
400: char *name;
401: int side, inflag;
402: double val;
403: char *lab, *lenstr, *descstr;
404: {
405: char *sidestr, *td;
406:
407: fprintf(tfd, "\tline %s ", descstr);
408: inflag &= side;
409: switch (side) {
410: case BOT:
411: case 0:
412: td = inflag ? "up" : "down";
413: fprintf(tfd, "%s %s from (x_%s(%g),0)", td, lenstr, name, val);
414: break;
415: case TOP:
416: td = inflag ? "down" : "up";
417: fprintf(tfd, "%s %s from (x_%s(%g),frameht)", td, lenstr, name, val);
418: break;
419: case LEFT:
420: td = inflag ? "right" : "left";
421: fprintf(tfd, "%s %s from (0,y_%s(%g))", td, lenstr, name, val);
422: break;
423: case RIGHT:
424: td = inflag ? "left" : "right";
425: fprintf(tfd, "%s %s from (framewid,y_%s(%g))", td, lenstr, name, val);
426: break;
427: }
428: fprintf(tfd, "\n");
429: sidestr = tick_dir == IN ? "start" : "end";
430: if (lab != NULL) {
431: /* BUG: should fix size of lab here */
432: switch (side) {
433: case BOT: case 0:
434: /* can drop "box invis" with new pic */
435: fprintf(tfd, "\tbox invis \"%s\" ht .25 wid 0 with .n at last line.%s",
436: lab, sidestr);
437: break;
438: case TOP:
439: fprintf(tfd, "\tbox invis \"%s\" ht .2 wid 0 with .s at last line.%s",
440: lab, sidestr);
441: break;
442: case LEFT:
443: fprintf(tfd, "\t\"%s \" rjust at last line.%s",
444: lab, sidestr);
445: break;
446: case RIGHT:
447: fprintf(tfd, "\t\" %s\" ljust at last line.%s",
448: lab, sidestr);
449: break;
450: }
451: /* BUG: works only if "down x" comes before "at wherever" */
452: lab_adjust();
453: fprintf(tfd, "\n");
454: }
455: }
456:
457: Attr *grid_desc = 0;
458:
459: griddesc(a)
460: Attr *a;
461: {
462: grid_desc = a;
463: }
464:
465: gridlist(p)
466: Obj *p;
467: {
468: int i, logflag;
469: double tv;
470: char *framestr;
471:
472: if ((tside & (BOT|TOP)) || tside == 0)
473: framestr = "frameht";
474: else
475: framestr = "framewid";
476: fprintf(tfd, "Grid_%s:\n", p->name);
477: tick_dir = IN;
478: print_ticks(GRID, 0, p, framestr, desc_str(grid_desc));
479: if (grid_desc) {
480: freeattr(grid_desc);
481: grid_desc = 0;
482: }
483: }
484:
485: char *desc_str(a) /* convert DOT to "dotted", etc. */
486: Attr *a;
487: {
488: static char buf[50], *p;
489:
490: if (a == NULL)
491: return p = "";
492: switch (a->type) {
493: case DOT: p = "dotted"; break;
494: case DASH: p = "dashed"; break;
495: case INVIS: p = "invis"; break;
496: default: p = "";
497: }
498: if (a->fval != 0.0) {
499: sprintf(buf, "%s %g", p, a->fval);
500: return buf;
501: } else
502: return p;
503: }
504:
505: sidelog(logflag, side) /* figure out whether to scale a side */
506: int logflag, side;
507: {
508: if ((logflag & XFLAG) && ((side & (BOT|TOP)) || side == 0))
509: return 1;
510: else if ((logflag & YFLAG) && (side & (LEFT|RIGHT)))
511: return 1;
512: else
513: return 0;
514: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.