xref: /illumos-gate/usr/src/cmd/troff/troff.d/draw.c (revision 59d65d31)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1989 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 #include	<stdio.h>
41 #include	<math.h>
42 #define	PI	3.141592654
43 #define	hmot(n)		hpos += n
44 #define	hgoto(n)	hpos = n
45 #define	vmot(n)		vgoto(vpos + n)
46 
47 extern	int	hpos;
48 extern	int	vpos;
49 extern	int	size;
50 extern	short	*pstab;
51 extern	int	DX;	/* step size in x */
52 extern	int	DY;	/* step size in y */
53 extern	int	drawdot;	/* character to use when drawing */
54 extern	int	drawsize;	/* shrink point size by this facter */
55 
56 int	maxdots	= 32000;	/* maximum number of dots in an object */
57 
58 #define	sgn(n)	((n > 0) ? 1 : ((n < 0) ? -1 : 0))
59 #define	abs(n)	((n) >= 0 ? (n) : -(n))
60 #define	max(x,y)	((x) > (y) ? (x) : (y))
61 #define	min(x,y)	((x) < (y) ? (x) : (y))
62 #define	arcmove(x,y)	{ hgoto(x); vmot(-vpos-(y)); }
63 
64 int
65 drawline(dx, dy, s)	/* draw line from here to dx, dy using s */
66 int dx, dy;
67 char *s;
68 {
69 	int xd, yd;
70 	float val, slope;
71 	int i, numdots;
72 	int dirmot, perp;
73 	int motincr, perpincr;
74 	int ohpos, ovpos, osize, ofont;
75 	float incrway;
76 
77 	int itemp; /*temp. storage for value returned byint function sgn*/
78 	osize = size;
79 	setsize(t_size(pstab[osize-1] / drawsize));
80 	ohpos = hpos;
81 	ovpos = vpos;
82 	xd = dx / DX;
83 	yd = dy / DX;
84 	if (xd == 0) {
85 		numdots = abs (yd);
86 		numdots = min(numdots, maxdots);
87 		motincr = DX * sgn (yd);
88 		for (i = 0; i < numdots; i++) {
89 			vmot(motincr);
90 			put1(drawdot);
91 		}
92 		vgoto(ovpos + dy);
93 		setsize(osize);
94 		return (0);
95 	}
96 	if (yd == 0) {
97 		numdots = abs (xd);
98 		motincr = DX * sgn (xd);
99 		for (i = 0; i < numdots; i++) {
100 			hmot(motincr);
101 			put1(drawdot);
102 		}
103 		hgoto(ohpos + dx);
104 		setsize(osize);
105 		return (0);
106 	}
107 	if (abs (xd) > abs (yd)) {
108 		val = slope = (float) xd/yd;
109 		numdots = abs (xd);
110 		numdots = min(numdots, maxdots);
111 		dirmot = 'h';
112 		perp = 'v';
113 		motincr = DX * sgn (xd);
114 		perpincr = DX * sgn (yd);
115 	}
116 	else {
117 		val = slope = (float) yd/xd;
118 		numdots = abs (yd);
119 		numdots = min(numdots, maxdots);
120 		dirmot = 'v';
121 		perp = 'h';
122 		motincr = DX * sgn (yd);
123 		perpincr = DX * sgn (xd);
124 	}
125 	incrway = itemp = sgn ((int) slope);
126 	for (i = 0; i < numdots; i++) {
127 		val -= incrway;
128 		if (dirmot == 'h')
129 			hmot(motincr);
130 		else
131 			vmot(motincr);
132 		if (val * slope < 0) {
133 			if (perp == 'h')
134 				hmot(perpincr);
135 			else
136 				vmot(perpincr);
137 			val += slope;
138 		}
139 		put1(drawdot);
140 	}
141 	hgoto(ohpos + dx);
142 	vgoto(ovpos + dy);
143 	setsize(osize);
144 
145 	return (0);
146 }
147 
148 int
149 drawwig(s)	/* draw wiggly line */
150 	char *s;
151 {
152 	int x[50], y[50], xp, yp, pxp, pyp;
153 	float t1, t2, t3, w;
154 	int i, j, numdots, N;
155 	int osize, ofont;
156 	char temp[50], *p, *getstr();
157 
158 	osize = size;
159 	setsize(t_size(pstab[osize-1] / drawsize));
160 	p = s;
161 	for (N = 2; (p=getstr(p,temp)) != NULL && N < sizeof(x)/sizeof(x[0]); N++) {
162 		x[N] = atoi(temp);
163 		p = getstr(p, temp);
164 		y[N] = atoi(temp);
165 	}
166 	x[0] = x[1] = hpos;
167 	y[0] = y[1] = vpos;
168 	for (i = 1; i < N; i++) {
169 		x[i+1] += x[i];
170 		y[i+1] += y[i];
171 	}
172 	x[N] = x[N-1];
173 	y[N] = y[N-1];
174 	pxp = pyp = -9999;
175 	for (i = 0; i < N-1; i++) {	/* interval */
176 		numdots = (dist(x[i],y[i], x[i+1],y[i+1]) + dist(x[i+1],y[i+1], x[i+2],y[i+2])) / 2;
177 		numdots /= DX;
178 		numdots = min(numdots, maxdots);
179 		for (j = 0; j < numdots; j++) {	/* points within */
180 			w = (float) j / numdots;
181 			t1 = 0.5 * w * w;
182 			w = w - 0.5;
183 			t2 = 0.75 - w * w;
184 			w = w - 0.5;
185 			t3 = 0.5 * w * w;
186 			xp = t1 * x[i+2] + t2 * x[i+1] + t3 * x[i] + 0.5;
187 			yp = t1 * y[i+2] + t2 * y[i+1] + t3 * y[i] + 0.5;
188 			if (xp != pxp || yp != pyp) {
189 				hgoto(xp);
190 				vgoto(yp);
191 				put1(drawdot);
192 				pxp = xp;
193 				pyp = yp;
194 			}
195 		}
196 	}
197 	setsize(osize);
198 
199 	return (0);
200 }
201 
202 char *getstr(p, temp)	/* copy next non-blank string from p to temp, update p */
203 char *p, *temp;
204 {
205 	while (*p == ' ' || *p == '\t' || *p == '\n')
206 		p++;
207 	if (*p == '\0') {
208 		temp[0] = 0;
209 		return(NULL);
210 	}
211 	while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
212 		*temp++ = *p++;
213 	*temp = '\0';
214 	return(p);
215 }
216 
217 int
218 drawcirc(d)
219 {
220 	int xc, yc;
221 
222 	xc = hpos;
223 	yc = vpos;
224 	conicarc(hpos + d/2, -vpos, hpos, -vpos, hpos, -vpos, d/2, d/2);
225 	hgoto(xc + d);	/* circle goes to right side */
226 	vgoto(yc);
227 
228 	return (0);
229 }
230 
231 int
232 dist(x1, y1, x2, y2)	/* integer distance from x1,y1 to x2,y2 */
233 {
234 	float dx, dy;
235 
236 	dx = x2 - x1;
237 	dy = y2 - y1;
238 	return sqrt(dx*dx + dy*dy) + 0.5;
239 }
240 
241 int
242 drawarc(dx1, dy1, dx2, dy2)
243 {
244 	int x0, y0, x2, y2, r;
245 
246 	x0 = hpos + dx1;	/* center */
247 	y0 = vpos + dy1;
248 	x2 = x0 + dx2;	/* "to" */
249 	y2 = y0 + dy2;
250 	r = sqrt((float) dx1 * dx1 + (float) dy1 * dy1) + 0.5;
251 	conicarc(x0, -y0, hpos, -vpos, x2, -y2, r, r);
252 
253 	return (0);
254 }
255 
256 int
257 drawellip(a, b)
258 {
259 	int xc, yc;
260 
261 	xc = hpos;
262 	yc = vpos;
263 	conicarc(hpos + a/2, -vpos, hpos, -vpos, hpos, -vpos, a/2, b/2);
264 	hgoto(xc + a);
265 	vgoto(yc);
266 
267 	return (0);
268 }
269 
270 #define sqr(x) (long int)(x)*(x)
271 
272 int
273 conicarc(x, y, x0, y0, x1, y1, a, b)
274 {
275 	/* based on Bresenham, CACM, Feb 77, pp 102-3 */
276 	/* by Chris Van Wyk */
277 	/* capitalized vars are an internal reference frame */
278 	long dotcount = 0;
279 	int osize, ofont;
280 	int	xs, ys, xt, yt, Xs, Ys, qs, Xt, Yt, qt,
281 		M1x, M1y, M2x, M2y, M3x, M3y,
282 		Q, move, Xc, Yc;
283 	int ox1, oy1;
284 	long	delta;
285 	float	xc, yc;
286 	float	radius, slope;
287 	float	xstep, ystep;
288 
289 	osize = size;
290 	setsize(t_size(pstab[osize-1] / drawsize));
291 	ox1 = x1;
292 	oy1 = y1;
293 	if (a != b)	/* an arc of an ellipse; internally, will still think of circle */
294 		if (a > b) {
295 			xstep = (float)a / b;
296 			ystep = 1;
297 			radius = b;
298 		} else {
299 			xstep = 1;
300 			ystep = (float)b / a;
301 			radius = a;
302 		}
303 	else {	/* a circular arc; radius is computed from center and first point */
304 		xstep = ystep = 1;
305 		radius = sqrt((float)(sqr(x0 - x) + sqr(y0 - y)));
306 	}
307 
308 
309 	xc = x0;
310 	yc = y0;
311 	/* now, use start and end point locations to figure out
312 	the angle at which start and end happen; use these
313 	angles with known radius to figure out where start
314 	and end should be
315 	*/
316 	slope = atan2((double)(y0 - y), (double)(x0 - x) );
317 	if (slope == 0.0 && x0 < x)
318 		slope = 3.14159265;
319 	x0 = x + radius * cos(slope) + 0.5;
320 	y0 = y + radius * sin(slope) + 0.5;
321 	slope = atan2((double)(y1 - y), (double)(x1 - x));
322 	if (slope == 0.0 && x1 < x)
323 		slope = 3.14159265;
324 	x1 = x + radius * cos(slope) + 0.5;
325 	y1 = y + radius * sin(slope) + 0.5;
326 	/* step 2: translate to zero-centered circle */
327 	xs = x0 - x;
328 	ys = y0 - y;
329 	xt = x1 - x;
330 	yt = y1 - y;
331 	/* step 3: normalize to first quadrant */
332 	if (xs < 0)
333 		if (ys < 0) {
334 			Xs = abs(ys);
335 			Ys = abs(xs);
336 			qs = 3;
337 			M1x = 0;
338 			M1y = -1;
339 			M2x = 1;
340 			M2y = -1;
341 			M3x = 1;
342 			M3y = 0;
343 		} else {
344 			Xs = abs(xs);
345 			Ys = abs(ys);
346 			qs = 2;
347 			M1x = -1;
348 			M1y = 0;
349 			M2x = -1;
350 			M2y = -1;
351 			M3x = 0;
352 			M3y = -1;
353 		}
354 	else if (ys < 0) {
355 		Xs = abs(xs);
356 		Ys = abs(ys);
357 		qs = 0;
358 		M1x = 1;
359 		M1y = 0;
360 		M2x = 1;
361 		M2y = 1;
362 		M3x = 0;
363 		M3y = 1;
364 	} else {
365 		Xs = abs(ys);
366 		Ys = abs(xs);
367 		qs = 1;
368 		M1x = 0;
369 		M1y = 1;
370 		M2x = -1;
371 		M2y = 1;
372 		M3x = -1;
373 		M3y = 0;
374 	}
375 
376 
377 	Xc = Xs;
378 	Yc = Ys;
379 	if (xt < 0)
380 		if (yt < 0) {
381 			Xt = abs(yt);
382 			Yt = abs(xt);
383 			qt = 3;
384 		} else {
385 			Xt = abs(xt);
386 			Yt = abs(yt);
387 			qt = 2;
388 		}
389 	else if (yt < 0) {
390 		Xt = abs(xt);
391 		Yt = abs(yt);
392 		qt = 0;
393 	} else {
394 		Xt = abs(yt);
395 		Yt = abs(xt);
396 		qt = 1;
397 	}
398 
399 
400 	/* step 4: calculate number of quadrant crossings */
401 	if (((4 + qt - qs)
402 	     % 4 == 0)
403 	     && (Xt <= Xs)
404 	     && (Yt >= Ys)
405 	    )
406 		Q = 3;
407 	else
408 		Q = (4 + qt - qs) % 4 - 1;
409 	/* step 5: calculate initial decision difference */
410 	delta = sqr(Xs + 1)
411 	 + sqr(Ys - 1)
412 	-sqr(xs)
413 	-sqr(ys);
414 	/* here begins the work of drawing
415    we hope it ends here too */
416 	while ((Q >= 0)
417 	     || ((Q > -2)
418 	     && ((Xt > Xc)
419 	     && (Yt < Yc)
420 	    )
421 	    )
422 	    ) {
423 		if (dotcount++ % DX == 0)
424 			putdot((int)xc, (int)yc);
425 		if (Yc < 0.5) {
426 			/* reinitialize */
427 			Xs = Xc = 0;
428 			Ys = Yc = sqrt((float)(sqr(xs) + sqr(ys)));
429 			delta = sqr(Xs + 1) + sqr(Ys - 1) - sqr(xs) - sqr(ys);
430 			Q--;
431 			M1x = M3x;
432 			M1y = M3y;
433 			 {
434 				int	T;
435 				T = M2y;
436 				M2y = M2x;
437 				M2x = -T;
438 				T = M3y;
439 				M3y = M3x;
440 				M3x = -T;
441 			}
442 		} else {
443 			if (delta <= 0)
444 				if (2 * delta + 2 * Yc - 1 <= 0)
445 					move = 1;
446 				else
447 					move = 2;
448 			else if (2 * delta - 2 * Xc - 1 <= 0)
449 				move = 2;
450 			else
451 				move = 3;
452 			switch (move) {
453 			case 1:
454 				Xc++;
455 				delta += 2 * Xc + 1;
456 				xc += M1x * xstep;
457 				yc += M1y * ystep;
458 				break;
459 			case 2:
460 				Xc++;
461 				Yc--;
462 				delta += 2 * Xc - 2 * Yc + 2;
463 				xc += M2x * xstep;
464 				yc += M2y * ystep;
465 				break;
466 			case 3:
467 				Yc--;
468 				delta -= 2 * Yc + 1;
469 				xc += M3x * xstep;
470 				yc += M3y * ystep;
471 				break;
472 			}
473 		}
474 	}
475 
476 
477 	setsize(osize);
478 	drawline((int)xc-ox1,(int)yc-oy1,".");
479 
480 	return (0);
481 }
482 
483 int
484 putdot(x, y)
485 {
486 	arcmove(x, y);
487 	put1(drawdot);
488 
489 	return (0);
490 }
491