xref: /plan9/sys/src/cmd/pic/misc.c (revision 392dc26962a4986819d746514f28dfe13b47a3d3)
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 
setdir(int n)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 
curdir(void)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 
getcomp(obj * p,int t)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 
exprsave(double f)86 void exprsave(double f)
87 {
88 	exprlist[nexpr++] = f;
89 }
90 
sprintgen(char * fmt)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 
makefattr(int type,int sub,double f)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 
makeoattr(int type,obj * o)108 void makeoattr(int type, obj *o)	/* obj* attr */
109 {
110 	YYSTYPE val;
111 	val.o = o;
112 	makeattr(type, 0, val);
113 }
114 
makeiattr(int type,int i)115 void makeiattr(int type, int i)	/* int attr */
116 {
117 	YYSTYPE val;
118 	val.i = i;
119 	makeattr(type, 0, val);
120 }
121 
maketattr(int sub,char * p)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 
addtattr(int sub)129 void addtattr(int sub)		/* add text attrib to existing item */
130 {
131 	attr[nattr-1].a_sub |= sub;
132 }
133 
makevattr(char * p)134 void makevattr(char *p)	/* varname attribute */
135 {
136 	YYSTYPE val;
137 	val.p = p;
138 	makeattr(VARNAME, 0, val);
139 }
140 
makeattr(int type,int sub,YYSTYPE val)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 
printexpr(double f)156 void printexpr(double f)	/* print expression for debugging */
157 {
158 	printf("%g\n", f);
159 }
160 
printpos(obj * p)161 void printpos(obj *p)	/* print position for debugging */
162 {
163 	printf("%g, %g\n", p->o_x, p->o_y);
164 }
165 
tostring(char * s)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 
makepos(double x,double y)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 
makebetween(double f,obj * p1,obj * p2)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 
getpos(obj * p,int corner)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 
whatpos(obj * p,int corner,double * px,double * py)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 	if (p == NULL)
211 		ERROR "null object" FATAL;
212 	dprintf("whatpos %o %d %d\n", p, p->o_type, corner);
213 	x = p->o_x;
214 	y = p->o_y;
215 	if (p->o_type != PLACE && p->o_type != MOVE) {
216 		x1 = p->o_val[0];
217 		y1 = p->o_val[1];
218 	}
219 	switch (p->o_type) {
220 	case PLACE:
221 		break;
222 	case BOX:
223 	case BLOCK:
224 	case TEXT:
225 		switch (corner) {
226 		case NORTH:	y += y1 / 2; break;
227 		case SOUTH:	y -= y1 / 2; break;
228 		case EAST:	x += x1 / 2; break;
229 		case WEST:	x -= x1 / 2; break;
230 		case NE:	x += x1 / 2; y += y1 / 2; break;
231 		case SW:	x -= x1 / 2; y -= y1 / 2; break;
232 		case SE:	x += x1 / 2; y -= y1 / 2; break;
233 		case NW:	x -= x1 / 2; y += y1 / 2; break;
234 		case START:
235 			if (p->o_type == BLOCK)
236 				return whatpos(objlist[(int)p->o_val[2]], START, px, py);
237 		case END:
238 			if (p->o_type == BLOCK)
239 				return whatpos(objlist[(int)p->o_val[3]], END, px, py);
240 		}
241 		break;
242 	case ARC:
243 		switch (corner) {
244 		case START:
245 			if (p->o_attr & CW_ARC) {
246 				x = p->o_val[2]; y = p->o_val[3];
247 			} else {
248 				x = x1; y = y1;
249 			}
250 			break;
251 		case END:
252 			if (p->o_attr & CW_ARC) {
253 				x = x1; y = y1;
254 			} else {
255 				x = p->o_val[2]; y = p->o_val[3];
256 			}
257 			break;
258 		}
259 		if (corner == START || corner == END)
260 			break;
261 		x1 = y1 = sqrt((x1-x)*(x1-x) + (y1-y)*(y1-y));
262 		/* Fall Through! */
263 	case CIRCLE:
264 	case ELLIPSE:
265 		switch (corner) {
266 		case NORTH:	y += y1; break;
267 		case SOUTH:	y -= y1; break;
268 		case EAST:	x += x1; break;
269 		case WEST:	x -= x1; break;
270 		case NE:	x += 0.707 * x1; y += 0.707 * y1; break;
271 		case SE:	x += 0.707 * x1; y -= 0.707 * y1; break;
272 		case NW:	x -= 0.707 * x1; y += 0.707 * y1; break;
273 		case SW:	x -= 0.707 * x1; y -= 0.707 * y1; break;
274 		}
275 		break;
276 	case LINE:
277 	case SPLINE:
278 	case ARROW:
279 		switch (corner) {
280 		case START:	break;	/* already in place */
281 		case END:	x = x1; y = y1; break;
282 		default: /* change! */
283 		case CENTER:	x = (x+x1)/2; y = (y+y1)/2; break;
284 		case NORTH:	if (y1 > y) { x = x1; y = y1; } break;
285 		case SOUTH:	if (y1 < y) { x = x1; y = y1; } break;
286 		case EAST:	if (x1 > x) { x = x1; y = y1; } break;
287 		case WEST:	if (x1 < x) { x = x1; y = y1; } break;
288 		}
289 		break;
290 	case MOVE:
291 		/* really ought to be same as line... */
292 		break;
293 	}
294 	dprintf("whatpos returns %g %g\n", x, y);
295 	*px = x;
296 	*py = y;
297 	return 1;
298 }
299 
gethere(void)300 obj *gethere(void)	/* make a place for curx,cury */
301 {
302 	dprintf("gethere %g %g\n", curx, cury);
303 	return(makepos(curx, cury));
304 }
305 
getlast(int n,int t)306 obj *getlast(int n, int t)	/* find n-th previous occurrence of type t */
307 {
308 	int i, k;
309 	obj *p;
310 
311 	k = n;
312 	for (i = nobj-1; i >= 0; i--) {
313 		p = objlist[i];
314 		if (p->o_type == BLOCKEND) {
315 			i = p->o_val[4];
316 			continue;
317 		}
318 		if (p->o_type != t)
319 			continue;
320 		if (--k > 0)
321 			continue;	/* not there yet */
322 		dprintf("got a last of x,y= %g,%g\n", p->o_x, p->o_y);
323 		return(p);
324 	}
325 	ERROR "there is no %dth last", n FATAL;
326 	return(NULL);
327 }
328 
getfirst(int n,int t)329 obj *getfirst(int n, int t)	/* find n-th occurrence of type t */
330 {
331 	int i, k;
332 	obj *p;
333 
334 	k = n;
335 	for (i = 0; i < nobj; i++) {
336 		p = objlist[i];
337 		if (p->o_type == BLOCK && t != BLOCK) {	/* skip whole block */
338 			i = p->o_val[5] + 1;
339 			continue;
340 		}
341 		if (p->o_type != t)
342 			continue;
343 		if (--k > 0)
344 			continue;	/* not there yet */
345 		dprintf("got a first of x,y= %g,%g\n", p->o_x, p->o_y);
346 		return(p);
347 	}
348 	ERROR "there is no %dth ", n FATAL;
349 	return(NULL);
350 }
351 
getblkvar(obj * p,char * s)352 double getblkvar(obj *p, char *s)	/* find variable s2 in block p */
353 {
354 	YYSTYPE y;
355 
356 	y = getblk(p, s);
357 	return y.f;
358 }
359 
getblock(obj * p,char * s)360 obj *getblock(obj *p, char *s)	/* find variable s in block p */
361 {
362 	YYSTYPE y;
363 
364 	y = getblk(p, s);
365 	return y.o;
366 }
367 
getblk(obj * p,char * s)368 YYSTYPE getblk(obj *p, char *s)	/* find union type for s in p */
369 {
370 	static YYSTYPE bug;
371 	struct symtab *stp;
372 
373 	if (p->o_type != BLOCK) {
374 		ERROR ".%s is not in that block", s WARNING;
375 		return(bug);
376 	}
377 	for (stp = p->o_symtab; stp != NULL; stp = stp->s_next)
378 		if (strcmp(s, stp->s_name) == 0) {
379 			dprintf("getblk %s found x,y= %g,%g\n",
380 				s, (stp->s_val.o)->o_x, (stp->s_val.o)->o_y);
381 			return(stp->s_val);
382 		}
383 	ERROR "there is no .%s in that []", s WARNING;
384 	return(bug);
385 }
386 
fixpos(obj * p,double x,double y)387 obj *fixpos(obj *p, double x, double y)
388 {
389 	dprintf("fixpos returns %g %g\n", p->o_x + x, p->o_y + y);
390 	return makepos(p->o_x + x, p->o_y + y);
391 }
392 
addpos(obj * p,obj * q)393 obj *addpos(obj *p, obj *q)
394 {
395 	dprintf("addpos returns %g %g\n", p->o_x+q->o_x, p->o_y+q->o_y);
396 	return makepos(p->o_x+q->o_x, p->o_y+q->o_y);
397 }
398 
subpos(obj * p,obj * q)399 obj *subpos(obj *p, obj *q)
400 {
401 	dprintf("subpos returns %g %g\n", p->o_x-q->o_x, p->o_y-q->o_y);
402 	return makepos(p->o_x-q->o_x, p->o_y-q->o_y);
403 }
404 
makenode(int type,int n)405 obj *makenode(int type, int n)
406 {
407 	obj *p;
408 
409 	p = (obj *) calloc(1, sizeof(obj) + (n-1)*sizeof(ofloat));
410 	if (p == NULL)
411 		ERROR "out of space in makenode" FATAL;
412 	p->o_type = type;
413 	p->o_count = n;
414 	p->o_nobj = nobj;
415 	p->o_mode = hvmode;
416 	p->o_x = curx;
417 	p->o_y = cury;
418 	p->o_nt1 = ntext1;
419 	p->o_nt2 = ntext;
420 	ntext1 = ntext;	/* ready for next caller */
421 	if (nobj >= nobjlist)
422 		objlist = (obj **) grow((char *) objlist, "objlist",
423 			nobjlist *= 2, sizeof(obj *));
424 	objlist[nobj++] = p;
425 	return(p);
426 }
427 
extreme(double x,double y)428 void extreme(double x, double y)	/* record max and min x and y values */
429 {
430 	if (x > xmax)
431 		xmax = x;
432 	if (y > ymax)
433 		ymax = y;
434 	if (x < xmin)
435 		xmin = x;
436 	if (y < ymin)
437 		ymin = y;
438 }
439