xref: /plan9-contrib/sys/src/cmd/pic/misc.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include "pic.h"
6 #include "y.tab.h"
7 
8 int whatpos(obj *p, int corner, double *px, double *py);
9 void makeattr(int type, int sub, YYSTYPE val);
10 YYSTYPE getblk(obj *, char *);
11 
12 setdir(int n)	/* set direction (hvmode) from LEFT, RIGHT, etc. */
13 {
14 	switch (n) {
15 	case UP:	hvmode = U_DIR; break;
16 	case DOWN:	hvmode = D_DIR; break;
17 	case LEFT:	hvmode = L_DIR; break;
18 	case RIGHT:	hvmode = R_DIR; break;
19 	}
20  	return(hvmode);
21 }
22 
23 curdir(void)	/* convert current dir (hvmode) to RIGHT, LEFT, etc. */
24 {
25 	switch (hvmode) {
26 	case R_DIR:	return RIGHT;
27 	case L_DIR:	return LEFT;
28 	case U_DIR:	return UP;
29 	case D_DIR:	return DOWN;
30 	}
31 	ERROR "can't happen curdir" FATAL;
32 	return 0;
33 }
34 
35 double getcomp(obj *p, int t)	/* return component of a position */
36 {
37 	switch (t) {
38 	case DOTX:
39 		return p->o_x;
40 	case DOTY:
41 		return p->o_y;
42 	case DOTWID:
43 		switch (p->o_type) {
44 		case BOX:
45 		case BLOCK:
46 		case TEXT:
47 			return p->o_val[0];
48 		case CIRCLE:
49 		case ELLIPSE:
50 			return 2 * p->o_val[0];
51 		case LINE:
52 		case ARROW:
53 			return p->o_val[0] - p->o_x;
54 		case PLACE:
55 			return 0;
56 		}
57 	case DOTHT:
58 		switch (p->o_type) {
59 		case BOX:
60 		case BLOCK:
61 		case TEXT:
62 			return p->o_val[1];
63 		case CIRCLE:
64 		case ELLIPSE:
65 			return 2 * p->o_val[1];
66 		case LINE:
67 		case ARROW:
68 			return p->o_val[1] - p->o_y;
69 		case PLACE:
70 			return 0;
71 		}
72 	case DOTRAD:
73 		switch (p->o_type) {
74 		case CIRCLE:
75 		case ELLIPSE:
76 			return p->o_val[0];
77 		}
78 	}
79 	ERROR "you asked for a weird dimension or position" WARNING;
80 	return 0;
81 }
82 
83 double	exprlist[100];
84 int	nexpr	= 0;
85 
86 void exprsave(double f)
87 {
88 	exprlist[nexpr++] = f;
89 }
90 
91 char *sprintgen(char *fmt)
92 {
93 	char buf[1000];
94 
95 	sprintf(buf, fmt, exprlist[0], exprlist[1], exprlist[2], exprlist[3], exprlist[4]);
96 	nexpr = 0;
97 	free(fmt);
98 	return tostring(buf);
99 }
100 
101 void makefattr(int type, int sub, double f)	/* double attr */
102 {
103 	YYSTYPE val;
104 	val.f = f;
105 	makeattr(type, sub, val);
106 }
107 
108 void makeoattr(int type, obj *o)	/* obj* attr */
109 {
110 	YYSTYPE val;
111 	val.o = o;
112 	makeattr(type, 0, val);
113 }
114 
115 void makeiattr(int type, int i)	/* int attr */
116 {
117 	YYSTYPE val;
118 	val.i = i;
119 	makeattr(type, 0, val);
120 }
121 
122 void maketattr(int sub, char *p)	/* text attribute: takes two */
123 {
124 	YYSTYPE val;
125 	val.p = p;
126 	makeattr(TEXTATTR, sub, val);
127 }
128 
129 void addtattr(int sub)		/* add text attrib to existing item */
130 {
131 	attr[nattr-1].a_sub |= sub;
132 }
133 
134 void makevattr(char *p)	/* varname attribute */
135 {
136 	YYSTYPE val;
137 	val.p = p;
138 	makeattr(VARNAME, 0, val);
139 }
140 
141 void makeattr(int type, int sub, YYSTYPE val)	/* add attribute type and val */
142 {
143 	if (type == 0 && val.i == 0) {	/* clear table for next stat */
144 		nattr = 0;
145 		return;
146 	}
147 	if (nattr >= nattrlist)
148 		attr = (Attr *) grow((char *)attr, "attr", nattrlist += 100, sizeof(Attr));
149 	dprintf("attr %d:  %d %d %d\n", nattr, type, sub, val.i);
150 	attr[nattr].a_type = type;
151 	attr[nattr].a_sub = sub;
152 	attr[nattr].a_val = val;
153 	nattr++;
154 }
155 
156 void printexpr(double f)	/* print expression for debugging */
157 {
158 	printf("%g\n", f);
159 }
160 
161 void printpos(obj *p)	/* print position for debugging */
162 {
163 	printf("%g, %g\n", p->o_x, p->o_y);
164 }
165 
166 char *tostring(char *s)
167 {
168 	register char *p;
169 
170 	p = malloc(strlen(s)+1);
171 	if (p == NULL)
172 		ERROR "out of space in tostring on %s", s FATAL;
173 	strcpy(p, s);
174 	return(p);
175 }
176 
177 obj *makepos(double x, double y)	/* make a position cell */
178 {
179 	obj *p;
180 
181 	p = makenode(PLACE, 0);
182 	p->o_x = x;
183 	p->o_y = y;
184 	return(p);
185 }
186 
187 obj *makebetween(double f, obj *p1, obj *p2)	/* make position between p1 and p2 */
188 {
189 	obj *p;
190 
191 	dprintf("fraction = %.2f\n", f);
192 	p = makenode(PLACE, 0);
193 	p->o_x = p1->o_x + f * (p2->o_x - p1->o_x);
194 	p->o_y = p1->o_y + f * (p2->o_y - p1->o_y);
195 	return(p);
196 }
197 
198 obj *getpos(obj *p, int corner)	/* find position of point */
199 {
200 	double x, y;
201 
202 	whatpos(p, corner, &x, &y);
203 	return makepos(x, y);
204 }
205 
206 int whatpos(obj *p, int corner, double *px, double *py)	/* what is the position (no side effect) */
207 {
208 	double x, y, x1, y1;
209 
210 	dprintf("whatpos %o %d %d\n", p, p->o_type, corner);
211 	x = p->o_x;
212 	y = p->o_y;
213 	if (p->o_type != PLACE && p->o_type != MOVE) {
214 		x1 = p->o_val[0];
215 		y1 = p->o_val[1];
216 	}
217 	switch (p->o_type) {
218 	case PLACE:
219 		break;
220 	case BOX:
221 	case BLOCK:
222 	case TEXT:
223 		switch (corner) {
224 		case NORTH:	y += y1 / 2; break;
225 		case SOUTH:	y -= y1 / 2; break;
226 		case EAST:	x += x1 / 2; break;
227 		case WEST:	x -= x1 / 2; break;
228 		case NE:	x += x1 / 2; y += y1 / 2; break;
229 		case SW:	x -= x1 / 2; y -= y1 / 2; break;
230 		case SE:	x += x1 / 2; y -= y1 / 2; break;
231 		case NW:	x -= x1 / 2; y += y1 / 2; break;
232 		case START:
233 			if (p->o_type == BLOCK)
234 				return whatpos(objlist[(int)p->o_val[2]], START, px, py);
235 		case END:
236 			if (p->o_type == BLOCK)
237 				return whatpos(objlist[(int)p->o_val[3]], END, px, py);
238 		}
239 		break;
240 	case ARC:
241 		switch (corner) {
242 		case START:
243 			if (p->o_attr & CW_ARC) {
244 				x = p->o_val[2]; y = p->o_val[3];
245 			} else {
246 				x = x1; y = y1;
247 			}
248 			break;
249 		case END:
250 			if (p->o_attr & CW_ARC) {
251 				x = x1; y = y1;
252 			} else {
253 				x = p->o_val[2]; y = p->o_val[3];
254 			}
255 			break;
256 		}
257 		if (corner == START || corner == END)
258 			break;
259 		x1 = y1 = sqrt((x1-x)*(x1-x) + (y1-y)*(y1-y));
260 		/* Fall Through! */
261 	case CIRCLE:
262 	case ELLIPSE:
263 		switch (corner) {
264 		case NORTH:	y += y1; break;
265 		case SOUTH:	y -= y1; break;
266 		case EAST:	x += x1; break;
267 		case WEST:	x -= x1; break;
268 		case NE:	x += 0.707 * x1; y += 0.707 * y1; break;
269 		case SE:	x += 0.707 * x1; y -= 0.707 * y1; break;
270 		case NW:	x -= 0.707 * x1; y += 0.707 * y1; break;
271 		case SW:	x -= 0.707 * x1; y -= 0.707 * y1; break;
272 		}
273 		break;
274 	case LINE:
275 	case SPLINE:
276 	case ARROW:
277 		switch (corner) {
278 		case START:	break;	/* already in place */
279 		case END:	x = x1; y = y1; break;
280 		default: /* change! */
281 		case CENTER:	x = (x+x1)/2; y = (y+y1)/2; break;
282 		case NORTH:	if (y1 > y) { x = x1; y = y1; } break;
283 		case SOUTH:	if (y1 < y) { x = x1; y = y1; } break;
284 		case EAST:	if (x1 > x) { x = x1; y = y1; } break;
285 		case WEST:	if (x1 < x) { x = x1; y = y1; } break;
286 		}
287 		break;
288 	case MOVE:
289 		/* really ought to be same as line... */
290 		break;
291 	}
292 	dprintf("whatpos returns %g %g\n", x, y);
293 	*px = x;
294 	*py = y;
295 	return 1;
296 }
297 
298 obj *gethere(void)	/* make a place for curx,cury */
299 {
300 	dprintf("gethere %g %g\n", curx, cury);
301 	return(makepos(curx, cury));
302 }
303 
304 obj *getlast(int n, int t)	/* find n-th previous occurrence of type t */
305 {
306 	int i, k;
307 	obj *p;
308 
309 	k = n;
310 	for (i = nobj-1; i >= 0; i--) {
311 		p = objlist[i];
312 		if (p->o_type == BLOCKEND) {
313 			i = p->o_val[4];
314 			continue;
315 		}
316 		if (p->o_type != t)
317 			continue;
318 		if (--k > 0)
319 			continue;	/* not there yet */
320 		dprintf("got a last of x,y= %g,%g\n", p->o_x, p->o_y);
321 		return(p);
322 	}
323 	ERROR "there is no %dth last", n WARNING;
324 	return(NULL);
325 }
326 
327 obj *getfirst(int n, int t)	/* find n-th occurrence of type t */
328 {
329 	int i, k;
330 	obj *p;
331 
332 	k = n;
333 	for (i = 0; i < nobj; i++) {
334 		p = objlist[i];
335 		if (p->o_type == BLOCK && t != BLOCK) {	/* skip whole block */
336 			i = p->o_val[5] + 1;
337 			continue;
338 		}
339 		if (p->o_type != t)
340 			continue;
341 		if (--k > 0)
342 			continue;	/* not there yet */
343 		dprintf("got a first of x,y= %g,%g\n", p->o_x, p->o_y);
344 		return(p);
345 	}
346 	ERROR "there is no %dth ", n WARNING;
347 	return(NULL);
348 }
349 
350 double getblkvar(obj *p, char *s)	/* find variable s2 in block p */
351 {
352 	YYSTYPE y;
353 
354 	y = getblk(p, s);
355 	return y.f;
356 }
357 
358 obj *getblock(obj *p, char *s)	/* find variable s in block p */
359 {
360 	YYSTYPE y;
361 
362 	y = getblk(p, s);
363 	return y.o;
364 }
365 
366 YYSTYPE getblk(obj *p, char *s)	/* find union type for s in p */
367 {
368 	static YYSTYPE bug;
369 	struct symtab *stp;
370 
371 	if (p->o_type != BLOCK) {
372 		ERROR ".%s is not in that block", s WARNING;
373 		return(bug);
374 	}
375 	for (stp = p->o_symtab; stp != NULL; stp = stp->s_next)
376 		if (strcmp(s, stp->s_name) == 0) {
377 			dprintf("getblk %s found x,y= %g,%g\n",
378 				s, (stp->s_val.o)->o_x, (stp->s_val.o)->o_y);
379 			return(stp->s_val);
380 		}
381 	ERROR "there is no .%s in that []", s WARNING;
382 	return(bug);
383 }
384 
385 obj *fixpos(obj *p, double x, double y)
386 {
387 	dprintf("fixpos returns %g %g\n", p->o_x + x, p->o_y + y);
388 	return makepos(p->o_x + x, p->o_y + y);
389 }
390 
391 obj *addpos(obj *p, obj *q)
392 {
393 	dprintf("addpos returns %g %g\n", p->o_x+q->o_x, p->o_y+q->o_y);
394 	return makepos(p->o_x+q->o_x, p->o_y+q->o_y);
395 }
396 
397 obj *subpos(obj *p, obj *q)
398 {
399 	dprintf("subpos returns %g %g\n", p->o_x-q->o_x, p->o_y-q->o_y);
400 	return makepos(p->o_x-q->o_x, p->o_y-q->o_y);
401 }
402 
403 obj *makenode(int type, int n)
404 {
405 	obj *p;
406 
407 	p = (obj *) calloc(1, sizeof(obj) + (n-1)*sizeof(ofloat));
408 	if (p == NULL)
409 		ERROR "out of space in makenode" FATAL;
410 	p->o_type = type;
411 	p->o_count = n;
412 	p->o_nobj = nobj;
413 	p->o_mode = hvmode;
414 	p->o_x = curx;
415 	p->o_y = cury;
416 	p->o_nt1 = ntext1;
417 	p->o_nt2 = ntext;
418 	ntext1 = ntext;	/* ready for next caller */
419 	if (nobj >= nobjlist)
420 		objlist = (obj **) grow((char *) objlist, "objlist",
421 			nobjlist *= 2, sizeof(obj *));
422 	objlist[nobj++] = p;
423 	return(p);
424 }
425 
426 void extreme(double x, double y)	/* record max and min x and y values */
427 {
428 	if (x > xmax)
429 		xmax = x;
430 	if (y > ymax)
431 		ymax = y;
432 	if (x < xmin)
433 		xmin = x;
434 	if (y < ymin)
435 		ymin = y;
436 }
437