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