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