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