Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_posix/sys/src/cmd/grap/ticks.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
}