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