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