1 /* pltroff.c	(Berkeley)	1.5	83/10/07
2  *	This version has code generators to drive the old-style troff
3  *	that produces output for the Graphic Systems C/A/T.
4  *	Very few people actually have a C/A/T; they instead typically
5  *	use some other typesetter that simulates it.  This is slow and
6  *	rather silly, but compatibility with the past is important.
7  *	Or so they say.  Anyway ...
8 
9  *	The code generator can be turned on to old-style troff by setting
10  *	the constant OLDTROFF with a #define statement;  this will also
11  *	have the effect of setting the default typesetter to the C/A/T
12  *	in a consistent manner.
13  */
14 
15 #include <stdio.h>
16 #include <math.h>
17 extern int dbg;
18 
19 /* this is the place to define OLDTROFF if you're going to */
20 #ifdef	OLDTROFF
21 #	define	OLDSTYLE	1
22 #	define  MAXMOT		8192
23 #else
24 #	define	OLDSTYLE	0
25 #	define  MAXMOT		32768
26 #endif
27 
28 #define	abs(n)	(n >= 0 ? n : -(n))
29 #define	max(x,y)	((x)>(y) ? (x) : (y))
30 #define	PI	3.141592654
31 #define	PI2	PI/2
32 
33 extern	int	res;
34 extern	int	DX;	/* step size in x */
35 extern	int	DY;	/* step size in y */
36 
37 int	minline	= 245;	/* draw lines shorter than this with dots on 202 */
38 			/* ought to be point-size dependent, but what's that? */
39 			/* this is big enough to handle 202 up to 36 points */
40 int	drawdot	= '.';	/* character to use when drawing */
41 
42 int	useDline	= 1;	/* if set, produce \D for all lines */
43 extern	float	hshift;	/* how much to move left by for text */
44 extern	float	vshift;	/* how much down */
45 
46 /* scaling stuff, specific to typesetter */
47 /* defined by s command as X0,Y0 to X1,Y1 */
48 /* output dimensions set by -l,-w options to 0,0 to hmax, vmax */
49 /* default output is 6x6 inches */
50 
51 
52 float	xscale;
53 float	yscale;
54 
55 int	hpos	= 0;	/* current horizontal position in output coordinate system */
56 int	vpos	= 0;	/* current vertical position; 0 is top of page */
57 
58 int	htrue	= 0;	/* where we really are */
59 int	vtrue	= 0;
60 
61 float	X0, Y0;		/* left bottom of input */
62 float	X1, Y1;		/* right top of input */
63 
64 int	hmax;		/* right end of output */
65 int	vmax;		/* top of output (down is positive) */
66 
67 extern	float	deltx;
68 extern	float	delty;
69 extern	float	xbound;
70 extern	float	ybound;
71 extern	float	xmin, ymin, xmax, ymax, sxmin, symin, sxmax, symax;
72 extern	int	crop;
73 
74 openpl(s)	/* initialize device */
75 	char *s;	/* residue of .PS invocation line */
76 {
77 	float maxdelt;
78 
79 	hpos = vpos = 0;
80 	hmax = vmax = 6 * res;	/* default = 6 x 6 */
81 	if (deltx > xbound) {		/* default 8 inches */
82 		fprintf(stderr, "pic: %g X %g picture shrunk to", deltx, delty);
83 		deltx *= xbound/deltx;
84 		delty *= xbound/deltx;
85 		fprintf(stderr, " %g X %g\n", deltx, delty);
86 	}
87 	if (delty > ybound) {		/* default 10 inches */
88 		fprintf(stderr, "pic: %g X %g picture shrunk to", deltx, delty);
89 		deltx *= ybound/delty;
90 		delty *= ybound/delty;
91 		fprintf(stderr, " %g X %g\n", deltx, delty);
92 	}
93 	if (deltx > 0 && delty > 0) {	/* have to change default size */
94 		hmax = res * deltx;
95 		vmax = res * delty;
96 	}
97 	if (crop) {
98 		if (xmax == xmin)
99 			space(xmin, ymin, xmin + ymax-ymin, ymax);
100 		else
101 			space(xmin, ymin, xmax, ymin + xmax-xmin);	/* assumes 1:1 aspect ratio */
102 	}
103 	else
104 		space(sxmin, symin, sxmax, symax);
105 	printf("... %g %g %g %g %g %g %g %g\n",
106 		xmin, ymin, xmax, ymax, sxmin, symin, sxmax, symax);
107 	printf("... %du %du %du %du %du %du %du %du\n",
108 		xconv(xmin), yconv(ymin), xconv(xmax), yconv(ymax),
109 		xconv(sxmin), yconv(symin), xconv(sxmax), yconv(symax));
110 	printf(".PS %d %d %s", yconv(ymin), xconv(xmax), s);
111 		/* assumes \n comes as part of s */
112 	if (xconv(xmax) >= MAXMOT || yconv(ymax) >= MAXMOT) {	/* internal troff limit: 15 bits for motion */
113 		fprintf(stderr, "picture too high or wide");
114 		exit(1);
115 	}
116 	printf(".br\n");
117 }
118 
119 closepl(type)	/* clean up after finished */
120 {
121 	movehv(0, 0);	/* get back to where we started */
122 	if (type == 'F')
123 		printf(".PF\n");
124 	else {
125 		printf(".sp 1+%du\n", yconv(ymin));
126 		printf(".PE\n");
127 	}
128 }
129 
130 move(x, y)	/* go to position x, y in external coords */
131 	float x, y;
132 {
133 	hgoto(xconv(x));
134 	vgoto(yconv(y));
135 }
136 
137 movehv(h, v)	/* go to internal position h, v */
138 	int h, v;
139 {
140 	hgoto(h);
141 	vgoto(v);
142 }
143 
144 hmot(n)	/* generate n units of horizontal motion */
145 	int n;
146 {
147 	hpos += n;
148 }
149 
150 vmot(n)	/* generate n units of vertical motion */
151 	int n;
152 {
153 	vpos += n;
154 }
155 
156 hgoto(n)
157 {
158 	hpos = n;
159 }
160 
161 vgoto(n)
162 {
163 	vpos = n;
164 }
165 
166 hvflush()	/* get to proper point for output */
167 {
168 	if (hpos != htrue) {
169 		printf("\\h'%du'", hpos - htrue);
170 		htrue = hpos;
171 	}
172 	if (vpos != vtrue) {
173 		printf("\\v'%du'", vpos - vtrue);
174 		vtrue = vpos;
175 	}
176 }
177 
178 flyback()	/* return to upper left corner (entry point) */
179 {
180 	printf(".sp -1\n");
181 	htrue = vtrue = 0;
182 }
183 
184 troff(s)	/* output troff right here */
185 	char *s;
186 {
187 	printf("%s\n", s);
188 }
189 
190 label(s, t, nh)	/* text s of type t nh half-lines up */
191 	char *s;
192 	int t, nh;
193 {
194 	int q;
195 	char *p;
196 
197 	hvflush();
198 	printf("\\h'-%.1fm'\\v'%.1fm'", hshift, vshift);	/* shift down and left */
199 			/*  .3 .3 is best for PO in circuit diagrams */
200 	if (t == 'A')
201 		nh++;
202 	else if (t == 'B')
203 		nh--;
204 	if (nh)
205 		printf("\\v'%du*\\n(.vu/2u'", -nh);
206 	/* just in case the text contains a quote: */
207 	q = 0;
208 	for (p = s; *p; p++)
209 		if (*p == '\'') {
210 			q = 1;
211 			break;
212 		}
213 	switch (t) {
214 	case 'L':
215 	default:
216 		printf("%s", s);
217 		break;
218 	case 'C':
219 	case 'A':
220 	case 'B':
221 		if (q)
222 			printf("\\h\\(ts-\\w\\(ts%s\\(tsu/2u\\(ts%s\\h\\(ts-\\w\\(ts%s\\(tsu/2u\\(ts", s, s, s);
223 		else
224 			printf("\\h'-\\w'%s'u/2u'%s\\h'-\\w'%s'u/2u'", s, s, s);
225 		break;
226 	case 'R':
227 		if (q)
228 			printf("\\h\\(ts-\\w\\(ts%s\\(tsu\\(ts%s", s, s);
229 		else
230 			printf("\\h'-\\w'%s'u'%s", s, s);
231 		break;
232 	}
233 	/* don't need these if flyback called immediately */
234 	printf("\n");
235 	flyback();
236 }
237 
238 line(x0, y0, x1, y1)	/* draw line from x0,y0 to x1,y1 */
239 	float x0, y0, x1, y1;
240 {
241 	move(x0, y0);
242 	cont(x1, y1);
243 }
244 
245 arrow(x0, y0, x1, y1, w, h)	/* draw arrow (without line), head wid w & len h */
246 	float x0, y0, x1, y1, w, h;
247 {
248 	double alpha, rot, hyp;
249 	float dx, dy;
250 
251 	rot = atan2( w / 2, h );
252 	hyp = sqrt(w/2 * w/2 + h * h);
253 	alpha = atan2(y1-y0, x1-x0);
254 	if (dbg)
255 		printf("rot=%f, hyp=%f, alpha=%f\n", rot, hyp, alpha);
256 	dx = hyp * cos(alpha + PI + rot);
257 	dy = hyp * sin(alpha + PI + rot);
258 	if (dbg) printf("dx,dy = %g,%g\n", dx, dy);
259 	line(x1+dx, y1+dy, x1, y1);
260 	dx = hyp * cos(alpha + PI - rot);
261 	dy = hyp * sin(alpha + PI - rot);
262 	if (dbg) printf("dx,dy = %g,%g\n", dx, dy);
263 	line(x1+dx, y1+dy, x1, y1);
264 }
265 
266 box(x0, y0, x1, y1)
267 	float x0, y0, x1, y1;
268 {
269 	move(x0, y0);
270 	cont(x0, y1);
271 	cont(x1, y1);
272 	cont(x1, y0);
273 	cont(x0, y0);
274 }
275 
276 cont(x, y)	/* continue line from here to x,y */
277 	float x, y;
278 {
279 	int h1, v1;
280 	int dh, dv;
281 
282 	h1 = xconv(x);
283 	v1 = yconv(y);
284 	dh = h1 - hpos;
285 	dv = v1 - vpos;
286 	downsize();
287 	hvflush();
288 	if (!useDline && dv == 0 && abs(dh) > minline)	/* horizontal */
289 		printf("\\l'%du'\n", dh);
290 	else if (!useDline && dh == 0 && abs(dv) > minline) {	/* vertical */
291 		printf("\\v'-.25m'\\L'%du\\(br'\\v'.25m'\n", dv);
292 					/* add -.25m correction if use \(br */
293 	} else {
294 		if (OLDSTYLE)
295 			drawline(dh, dv);
296 		else
297 			printf("\\D'l%du %du'\n", dh, dv);
298 	}
299 	upsize();
300 	flyback();	/* expensive */
301 	hpos = h1;
302 	vpos = v1;
303 }
304 
305 circle(x, y, r)
306 	float x, y, r;
307 {
308 	int d;
309 
310 	downsize();
311 	d = xsc(2 * r);
312 	move(x-r, y);
313 	hvflush();
314 	if (OLDSTYLE)
315 		drawcircle(d);
316 	else
317 		printf("\\D'c%du'\n", d);
318 	upsize();
319 	flyback();
320 }
321 
322 spline(x, y, n, p)
323 	float x, y, *p;
324 	float n;
325 {
326 	int i, j, dx, dy;
327 	char temp[1000];
328 
329 	downsize();
330 	move(x, y);
331 	hvflush();
332 	if (OLDSTYLE) {
333 		temp[0] = 0;
334 		for (i = 0; i < 2 * n; i += 2) {
335 			dx = xsc(p[i]);
336 			dy = ysc(p[i+1]);
337 			sprintf(&temp[strlen(temp)], " %d %d", dx, dy);
338 		}
339 		drawspline(temp);
340 	}
341 	else {
342 		printf("\\D'~");
343 		for (i = 0; i < 2 * n; i += 2) {
344 			dx = xsc(p[i]);
345 			dy = ysc(p[i+1]);
346 			printf(" %du %du", dx, dy);
347 		}
348 		printf("'\n");
349 	}
350 	upsize();
351 	flyback();
352 }
353 
354 ellipse(x, y, r1, r2)
355 	float x, y, r1, r2;
356 {
357 	int ir1, ir2;
358 
359 	downsize();
360 	move(x-r1, y);
361 	hvflush();
362 	ir1 = xsc(r1);
363 	ir2 = ysc(r2);
364 	if (OLDSTYLE)
365 		drawellipse(2 * ir1, 2 * abs(ir2));
366 	else
367 		printf("\\D'e%du %du'\n", 2 * ir1, 2 * abs(ir2));
368 	upsize();
369 	flyback();
370 }
371 
372 arc(x, y, x0, y0, x1, y1, r)	/* draw arc with center x,y */
373 	float x, y, x0, y0, x1, y1, r;
374 {
375 
376 	downsize();
377 	move(x0, y0);
378 	hvflush();
379 	if (OLDSTYLE) {
380 		drawarc(xsc(x1-x0), ysc(y1-y0), xsc(r));
381 	} else {
382 		printf("\\D'a%du %du %du %du'\n",
383 			xsc(x-x0), ysc(y-y0), xsc(x1-x), ysc(y1-y));
384 	}
385 	upsize();
386 	flyback();
387 }
388 
389 erase()	/* get to bottom of frame */
390 {
391 	return;	/* for now, ignore them */
392 }
393 
394 point(x, y)	/* put point at x,y */
395 	float x, y;
396 {
397 	static char *temp = ".";
398 
399 	move(x, y);
400 	label(temp, 'L');
401 }
402 
403 space(x0, y0, x1, y1)	/* set limits of page */
404 	float x0, y0, x1, y1;
405 {
406 	if (x0 == x1)
407 		x1 = x0 + 1;
408 	if (y0 == y1)
409 		y1 = y0 - 1;	/* kludge */
410 	X0 = x0;
411 	Y0 = y0;
412 	X1 = x1;
413 	Y1 = y1;
414 	xscale = hmax / (X1-X0);
415 	yscale = vmax / (Y0-Y1);
416 }
417 
418 xconv(x)	/* convert x from external to internal form */
419 	float x;
420 {
421 	int v;
422 
423 	v = (x-X0) * xscale + 0.5;
424 	if (OLDSTYLE) {
425 		v = (v + DX - 1) / DX;
426 		v *= DX;
427 	}
428 	return v;
429 }
430 
431 xsc(x)	/* convert x from external to internal form, scaling only */
432 	float x;
433 {
434 	int v;
435 
436 	v = (x) * xscale + 0.5;
437 	if (OLDSTYLE) {
438 		v = (v + DX - 1) / DX;
439 		v *= DX;
440 	}
441 	return v;
442 }
443 
444 yconv(y)	/* convert y from external to internal form */
445 	float y;
446 {
447 	int v;
448 
449 	y += Y1 - ymax;
450 	v = (y-Y1) * yscale + 0.5;
451 	if (OLDSTYLE) {
452 		v = (v + DY - 1) / DY;
453 		v *= DY;
454 	}
455 	return v;
456 }
457 
458 ysc(y)	/* convert y from external to internal form, scaling only */
459 	float y;
460 {
461 	int v;
462 
463 	v = (y) * yscale + 0.5;
464 	if (OLDSTYLE) {
465 		v = (v + DY - 1) / DY;
466 		v *= DY;
467 	}
468 	return v;
469 }
470 
471 linemod(s)
472 	char *s;
473 {
474 }
475 
476 dot() {
477 	hvflush();
478 	if (OLDSTYLE) printf("\\&.\n");
479 	else printf("\\D'l 0 0'\n");
480 	flyback();
481 }
482 
483 #ifndef	OLDTROFF
484 
485 	/* satisfy the loader... */
486 
487 drawline(){;}
488 drawcircle(){;}
489 drawspline(){;}
490 drawellipse(){;}
491 drawarc(){;}
492 upsize(){;}
493 downsize(){;}
494 
495 #endif
496 
497 #ifdef	OLDTROFF
498 
499 	/* these are for real */
500 
501 int	drawsize	= 2;	/* shrink point size by this factor */
502 
503 #define	sgn(n)	((n > 0) ? 1 : ((n < 0) ? -1 : 0))
504 #define	arcmove(x,y)	{ hgoto(x); vmot(-vpos-(y)); }
505 
506 put1(c) /* output one character, usually a dot */
507 {
508 	static int nput = 0;
509 
510 	if (nput++ > 100) {	/* crude approx: troff input buffer ~ 400 */
511 		nput = 0;
512 		printf("\n");	/* someday this will give a spurious break */
513 		flyback();
514 		printf("\\\&");
515 	}
516 	hvflush();	/* crude! */
517 	printf("\\z%c", c);
518 }
519 
520 downsize()	/* set size lower to make it lighter */
521 {
522 	if (drawsize != 1) {
523 		printf(".nr .. \\n(.s/%d\n", drawsize);
524 		printf(".ps \\n(..\n");
525 	}
526 }
527 
528 upsize()	/* undo downsize */
529 {
530 	printf(".ps\n");	/* God help anyone who fiddles .ps */
531 }
532 
533 drawline(dx, dy)	/* draw line from here to dx, dy */
534 int dx, dy;
535 {
536 	int xd, yd;
537 	float val, slope;
538 	int i, numdots;
539 	int dirmot, perp;
540 	int motincr, perpincr;
541 	int ohpos, ovpos, osize;
542 	float incrway;
543 
544         ohpos = hpos;
545 	ovpos = vpos;
546 	xd = dx / DX;
547 	yd = dy / DX;
548 	printf("\\\&");
549 	put1(drawdot);
550 	if (xd == 0) {
551 		numdots = abs (yd);
552 		motincr = DX * sgn (yd);
553 		for (i = 0; i < numdots; i++) {
554 			vmot(motincr);
555 			put1(drawdot);
556 		}
557 		vgoto(ovpos + dy);
558 		printf("\n");
559 		return;
560 	}
561 	if (yd == 0) {
562 		numdots = abs (xd);
563 		motincr = DX * sgn (xd);
564 		for (i = 0; i < numdots; i++) {
565 			hmot(motincr);
566 			put1(drawdot);
567 		}
568 		hgoto(ohpos + dx);
569 		printf("\n");
570 		return;
571 	}
572 	if (abs (xd) > abs (yd)) {
573 		val = slope = (float) xd/yd;
574 		numdots = abs (xd);
575 		dirmot = 'h';
576 		perp = 'v';
577 		motincr = DX * sgn (xd);
578 		perpincr = DX * sgn (yd);
579 	}
580 	else {
581 		val = slope = (float) yd/xd;
582 		numdots = abs (yd);
583 		dirmot = 'v';
584 		perp = 'h';
585 		motincr = DX * sgn (yd);
586 		perpincr = DX * sgn (xd);
587 	}
588 	incrway = sgn ((int) slope);
589 	for (i = 0; i < numdots; i++) {
590 		val -= incrway;
591 		if (dirmot == 'h')
592 			hmot(motincr);
593 		else
594 			vmot(motincr);
595 		if (val * slope < 0) {
596 			if (perp == 'h')
597 				hmot(perpincr);
598 			else
599 				vmot(perpincr);
600 			val += slope;
601 		}
602 		put1(drawdot);
603 	}
604 	hgoto(ohpos + dx);
605 	vgoto(ovpos + dy);
606 	printf("\n");
607 }
608 
609 drawspline(s)	/* draw spline curve */
610 	char *s;
611 {
612 	int x[50], y[50], xp, yp, pxp, pyp;
613 	float t1, t2, t3, w;
614 	int i, j, steps, N, prevsteps;
615 
616 	N = sscanf(s, "%d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d  %d %d ",
617 	&x[2], &y[2], &x[3], &y[3], &x[4], &y[4], &x[5], &y[5], &x[6], &y[6], &x[7], &y[7], &x[8], &y[8], &x[9], &y[9], &x[10], &y[10], &x[11], &y[11], &x[12], &y[12],
618 &x[13], &y[13], &x[14], &y[14], &x[15], &y[15], &x[16], &y[16], &x[17], &y[17], &x[18], &y[18], &x[19], &y[19], &x[20], &y[20], &x[21], &y[21], &x[22], &y[22], &x[23], &y[23], &x[24], &y[24],
619 &x[25], &y[25], &x[26], &y[26], &x[27], &y[27], &x[28], &y[28], &x[29], &y[29], &x[30], &y[30], &x[31], &y[31], &x[32], &y[32], &x[33], &y[33], &x[34], &y[34], &x[35], &y[35], &x[36], &y[36],
620 &x[37], &y[37]);
621 	N = N/2 + 2;
622 	x[0] = x[1] = hpos;
623 	y[0] = y[1] = vpos;
624 	for (i = 1; i < N; i++) {
625 		x[i+1] += x[i];
626 		y[i+1] += y[i];
627 	}
628 	x[N] = x[N-1];
629 	y[N] = y[N-1];
630 	prevsteps = 0;
631 	pxp = pyp = -9999;
632 	printf("\\\&");
633 	for (i = 0; i < N-1; i++) {	/* interval */
634 		steps = (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;
635 		steps /= DX;
636 		for (j = 0; j < steps; j++) {	/* points within */
637 			w = (float) j / steps;
638 			t1 = 0.5 * w * w;
639 			w = w - 0.5;
640 			t2 = 0.75 - w * w;
641 			w = w - 0.5;
642 			t3 = 0.5 * w * w;
643 			xp = t1 * x[i+2] + t2 * x[i+1] + t3 * x[i] + 0.5;
644 			yp = t1 * y[i+2] + t2 * y[i+1] + t3 * y[i] + 0.5;
645 			xp = round(xp, DX);
646 			yp = round(yp, DY);
647 			if (xp != pxp || yp != pyp) {
648 				hgoto(xp);
649 				vgoto(yp);
650 				put1(drawdot);
651 				pxp = xp;
652 				pyp = yp;
653 			}
654 		}
655 	}
656 	printf("\n");
657 }
658 
659 drawcirc(d)
660 {
661 	int xc, yc;
662 
663 	xc = hpos;
664 	yc = vpos;
665 	printf("\\\&");
666 	conicarc(hpos + d/2, -vpos, hpos, -vpos, hpos, -vpos, d/2, d/2);
667 	hgoto(xc + d);	/* circle goes to right side */
668 	vgoto(yc);
669 	printf("\n");
670 }
671 
672 dist(x1, y1, x2, y2)	/* integer distance from x1,y1 to x2,y2 */
673 {
674 	float dx, dy;
675 
676 	dx = x2 - x1;
677 	dy = y2 - y1;
678 	return sqrt(dx*dx + dy*dy) + 0.5;
679 }
680 
681 drawarc(x, y, r)
682 {
683 	int x0, y0;
684 	float dx, dy, phi, d, ht, ang;
685 
686 	if (r == 0)
687 		r = 1;
688 	if (r < 0)
689 		ang = PI / 2;
690 	else
691 		ang = -(PI / 2);
692 	dx = x / 2;
693 	dy = y / 2;
694 	phi = atan2(dy, dx) + ang;
695 	while ((d = (float)r * r - (dx*dx + dy*dy)) < 0.0)
696 		r *= 2;
697 	ht = sqrt(d);
698 	x0 = hpos + dx + ht * cos(phi) + 0.5;
699 	y0 = vpos + dy + ht * sin(phi) + 0.5;
700 	printf("\\\&");
701 	conicarc(x0, -y0, hpos, -vpos, hpos+x, -vpos-y, r, r);
702 	printf("\n");
703 }
704 
705 drawellip(a, b)
706 {
707 	int xc, yc;
708 
709 	xc = hpos;
710 	yc = vpos;
711 	printf("\\\&");
712 	conicarc(hpos + a/2, -vpos, hpos, -vpos, hpos, -vpos, a/2, b/2);
713 	hgoto(xc + a);
714 	vgoto(yc);
715 	printf("\n");
716 }
717 
718 #define sqr(x) (long int)(x)*(x)
719 
720 conicarc(x, y, x0, y0, x1, y1, a, b)
721 {
722 	/* based on Bresenham, CACM, Feb 77, pp 102-3 */
723 	/* by Chris Van Wyk */
724 	/* capitalized vars are an internal reference frame */
725 	long dotcount = 0;
726 	int	xs, ys, xt, yt, Xs, Ys, qs, Xt, Yt, qt,
727 	M1x, M1y, M2x, M2y, M3x, M3y,
728 	Q, move, Xc, Yc;
729 	int	delta;
730 	float	xc, yc;
731 	float	radius, slope;
732 	float	xstep, ystep;
733 	if (a != b)	/* an arc of an ellipse; internally, will still think of circle */
734 		if (a > b) {
735 			xstep = (float)a / b;
736 			ystep = 1;
737 			radius = b;
738 		}
739 		else
740 		 {
741 			xstep = 1;
742 			ystep = (float)b / a;
743 			radius = a;
744 		}
745 	else	/* a circular arc; radius is computed from center and first point */	 {
746 		xstep = ystep = 1;
747 		radius = sqrt((float)(sqr(x0 - x) + sqr(y0 - y)));
748 	}
749 
750 
751 	xc = x0;
752 	yc = y0;
753 	/* now, use start and end point locations to figure out
754    the angle at which start and end happen; use these
755    angles with known radius to figure out where start
756    and end should be */
757 	slope = atan2((double)(y0 - y), (double)(x0 - x)
758 	    );
759 	if ((slope == 0.0)
760 	     && (x0 < x)
761 	    )
762 		slope = 3.14159265;
763 	x0 = x + radius * cos(slope)
764 	 + 0.5;
765 	y0 = y + radius * sin(slope)
766 	 + 0.5;
767 	slope = atan2((double)(y1 - y), (double)(x1 - x)
768 	    );
769 	if ((slope == 0.0)
770 	     && (x1 < x)
771 	    )
772 		slope = 3.14159265;
773 	x1 = x + radius * cos(slope)
774 	 + 0.5;
775 	y1 = y + radius * sin(slope)
776 	 + 0.5;
777 	/* step 2: translate to zero-centered circle */
778 	xs = x0 - x;
779 	ys = y0 - y;
780 	xt = x1 - x;
781 	yt = y1 - y;
782 	/* step 3: normalize to first quadrant */
783 	if (xs < 0)
784 		if (ys < 0) {
785 			Xs = abs(ys);
786 			Ys = abs(xs);
787 			qs = 3;
788 			M1x = 0;
789 			M1y = -1;
790 			M2x = 1;
791 			M2y = -1;
792 			M3x = 1;
793 			M3y = 0;
794 		}
795 		else {
796 			Xs = abs(xs);
797 			Ys = abs(ys);
798 			qs = 2;
799 			M1x = -1;
800 			M1y = 0;
801 			M2x = -1;
802 			M2y = -1;
803 			M3x = 0;
804 			M3y = -1;
805 		}
806 	else if (ys < 0) {
807 		Xs = abs(xs);
808 		Ys = abs(ys);
809 		qs = 0;
810 		M1x = 1;
811 		M1y = 0;
812 		M2x = 1;
813 		M2y = 1;
814 		M3x = 0;
815 		M3y = 1;
816 	} else {
817 		Xs = abs(ys);
818 		Ys = abs(xs);
819 		qs = 1;
820 		M1x = 0;
821 		M1y = 1;
822 		M2x = -1;
823 		M2y = 1;
824 		M3x = -1;
825 		M3y = 0;
826 	}
827 
828 
829 	Xc = Xs;
830 	Yc = Ys;
831 	if (xt < 0)
832 		if (yt < 0) {
833 			Xt = abs(yt);
834 			Yt = abs(xt);
835 			qt = 3;
836 		}
837 		else {
838 			Xt = abs(xt);
839 			Yt = abs(yt);
840 			qt = 2;
841 		}
842 	else if (yt < 0) {
843 		Xt = abs(xt);
844 		Yt = abs(yt);
845 		qt = 0;
846 	} else {
847 		Xt = abs(yt);
848 		Yt = abs(xt);
849 		qt = 1;
850 	}
851 
852 
853 	/* step 4: calculate number of quadrant crossings */
854 	if (((4 + qt - qs)
855 	     % 4 == 0)
856 	     && (Xt <= Xs)
857 	     && (Yt >= Ys)
858 	    )
859 		Q = 3;
860 	else
861 		Q = (4 + qt - qs) % 4 - 1;
862 	/* step 5: calculate initial decision difference */
863 	delta = sqr(Xs + 1)
864 	 + sqr(Ys - 1)
865 	-sqr(xs)
866 	-sqr(ys);
867 	/* here begins the work of drawing
868    we hope it ends here too */
869 	while ((Q >= 0)
870 	     || ((Q > -2)
871 	     && ((Xt > Xc)
872 	     || (Yt < Yc)
873 	    )
874 	    )
875 	    ) {
876 		if (dotcount++ % DX == 0)
877 			putdot(round((int) xc, DX), round((int) yc, DY));
878 		if (Yc < 0.5) {
879 			/* reinitialize */
880 			Xs = Xc = 0;
881 			Ys = Yc = sqrt((float)(sqr(xs) + sqr(ys)));
882 			delta = sqr(Xs + 1) + sqr(Ys - 1) - sqr(xs) - sqr(ys);
883 			Q--;
884 			M1x = M3x;
885 			M1y = M3y;
886 			 {
887 				int	T;
888 				T = M2y;
889 				M2y = M2x;
890 				M2x = -T;
891 				T = M3y;
892 				M3y = M3x;
893 				M3x = -T;
894 			}
895 		} else {
896 			if (delta <= 0)
897 				if (2 * delta + 2 * Yc - 1 <= 0)
898 					move = 1;
899 				else
900 					move = 2;
901 			else if (2 * delta - 2 * Xc - 1 <= 0)
902 				move = 2;
903 			else
904 				move = 3;
905 			switch (move) {
906 			case 1:
907 				Xc++;
908 				delta += 2 * Xc + 1;
909 				xc += M1x * xstep;
910 				yc += M1y * ystep;
911 				break;
912 			case 2:
913 				Xc++;
914 				Yc--;
915 				delta += 2 * Xc - 2 * Yc + 2;
916 				xc += M2x * xstep;
917 				yc += M2y * ystep;
918 				break;
919 			case 3:
920 				Yc--;
921 				delta -= 2 * Yc + 1;
922 				xc += M3x * xstep;
923 				yc += M3y * ystep;
924 				break;
925 			}
926 		}
927 	}
928 
929 
930 }
931 
932 putdot(x, y)
933 {
934 	arcmove(x, y);
935 	put1(drawdot);
936 }
937 
938 round(x, dx)	/* round x relative to dx */
939 {
940 	x = (x + dx - 1) / dx;
941 	return x * dx;
942 }
943 #endif
944