1 /*
2  * TransFig: Facility for Translating Fig code
3  * Copyright (c) 1991 by Micah Beck
4  * Copyright (c) 1988 by Conrad Kwok
5  * Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
6  * Parts Copyright (c) 1989-2002 by Brian V. Smith
7  *
8  * Any party obtaining a copy of these files is granted, free of charge, a
9  * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
10  * nonexclusive right and license to deal in this software and
11  * documentation files (the "Software"), including without limitation the
12  * rights to use, copy, modify, merge, publish and/or distribute copies of
13  * the Software, and to permit persons who receive copies from any such
14  * party to do so, with the only requirement being that this copyright
15  * notice remain intact.
16  *
17  */
18 
19 /*
20  *	gentpic : TPIC driver for fig2dev
21  *
22  *	Author: Conrad Kwok, UC Davis, 12/88
23  *      Modified: Richard Auletta, George Mason Univ., 6/21/89
24  *		Added code comments are marked with "rja".
25  *      	Added: Support for native pic arrowheads.
26  *      	Added: Support for arrowheads at both ends of lines, arc, splines.
27  *	Modified: Modified from pic to tpic. Baron Grey, UCLA. 10/2/90.
28  *
29  *		This driver supports TeX's virtual font mechanism. Any Fig
30  *		font whose ordinal number is greater than 6 is treated as
31  *		a TeX virtual PostScript font. Virtual PostScript font
32  *		names are defined in tpicfonts.h (you should define
33  *		corresponding names in Fig in file change.c). Customize to
34  *		suit your virtual font availability or your name preferences.
35  *
36  *		There are no restrictions on font sizes in this driver, but
37  *		keep in mind that TeX only supports fonts up to 2048 points!
38  *		Since PostScript fonts are scaleable, virtual PS fonts can have
39  *		any point size within the limits imposed by TeX or by your
40  *		PostScript interpreter. If you are using
41  *		standard predefined LaTeX fonts (assumed to be the first
42  *		6 positions in Fig's ordinal font numbering scheme), font
43  *		sizes are mapped into the nearest valid normally-available
44  *		LaTeX font sizes -- look at tpicfonts.h to see how this is
45  *		done; you can modify it for fonts at your site.
46  *
47  *		Additional features of this driver are:
48  *		1) Support for all Fig features except text at nonzero
49  *		   angles.  (In fact, any limitations of this driver are
50  *		   actually tpic limitations.)
51  *		2) Boxes with rounded corners are supported in two ways.
52  *		   If (when) tpic is extended to use the "radius" attribute
53  *		   with a "box" specification, the driver will generate the
54  *		   appropriate box specification. Otherwise, it creates
55  *		   rounded-corner boxes from line and arc segments using
56  *		   existing tpic primitives. In the former case, rounded-
57  *		   corner boxes can be shaded; in the latter, they can't.
58  *		   Define TPIC_ARC_BOX for the first case (the default);
59  *		   undefine it otherwise.
60  *		3) Supports Fig's ability to texture (shade) objects.
61  *		   Bitmapped PostScript texture patterns are supported;
62  *		   they are defined in "tpicfonts.h". The tpic ".tx"
63  *		   primitive is used for this. Your dvi-to-PostScript
64  *		   driver must be adapted to support them.
65  *		4) If an object's line "thickness" is 0, it is given tpic's
66  *		   `invis' attribute. That is, tpic will treat it as an
67  *		   invisible object in the normal tpic sense.
68  *		5) This driver supports tpic 2.0. It will work with tpic 1.0,
69  *		   but some object attributes will not be available.
70  *		6) The default line thickness is 8 milli inches (in tpic
71  *		   units). This corresponds to 1 pixel width in Fig. The
72  *		   formula is: line_thickness = Fig_line_thickness *
73  *		   default_tpic_line_thickness.
74  *		7) The default font size is (assumed to be) 10 points!
75  */
76 
77 #include "fig2dev.h"
78 #include "object.h"
79 #include "tpicfonts.h"
80 
81 /*
82  * Define TPIC_ARC_BOX if your tpic supports rounded-corner boxes
83  * via a "radius" attribute of a box specification.
84  */
85 #define TPIC_ARC_BOX
86 
87 #define			TOP	10.5	/* top of page is 10.5 inch */
88 static int		line_width = 8;	/* milli-inches */
89 static int		vfont = 0; /* true if using a virtual TeX font */
90 
91 void gentpic_ctl_spline(), gentpic_itp_spline();
92 void gentpic_open_spline(), gentpic_closed_spline();
93 void gentpic_spline(), gentpic_ellipse(), gentpic_text();
94 void gentpic_arc(), gentpic_line();
95 static void bezier_spline();
96 static void newline();
97 
gentpic_option(opt,optarg)98 void gentpic_option(opt, optarg)
99 char opt, *optarg;
100 {
101 	switch (opt) {
102 
103 	case 'f':		/* set default text font */
104 	        {   int i;
105 
106 		    for ( i = 1; i <= MAX_TPICFONT; i++ )
107 			if ( !strcmp(optarg, texfontnames[i]) ) break;
108 
109 		    if ( i > MAX_FONT)
110 			    vfont = 1; /* assume a virtual font */
111 		}
112 
113 		texfontnames[0] = optarg;
114 		break;
115 
116 	case 's':
117 	case 'm':
118 	case 'L':
119 		break;
120 
121  	default:
122 		put_msg(Err_badarg, opt, "tpic");
123 		exit(1);
124 	}
125 }
126 
convy(a)127 static double convy(a)
128 double	a;
129 {
130 	return((double) TOP-a);
131 }
132 
gentpic_start(objects)133 void gentpic_start(objects)
134 F_compound	*objects;
135 {
136 	ppi = ppi/mag;
137 
138 	fprintf(tfp, ".PS\n");	/* PIC preamble */
139 }
140 
141 int
gentpic_end()142 gentpic_end()
143 {
144   	fprintf(tfp, ".PE\n");				/* PIC ending */
145 
146 	/* all ok */
147 	return 0;
148 }
149 
150 /*
151  * tpic's line thickness is given in milli-inches with a default of 8
152  * milli-inches. We simply multiply this default with the Fig pixel width.
153  */
set_linewidth(w)154 static void set_linewidth(w)
155 int	w;
156 {
157 	static int	cur_thickness = -1;
158 
159 	if (w == 0) return;
160 	if (w != cur_thickness) {
161 	    cur_thickness = w;
162 	    fprintf(tfp, ".ps %d\n", round(cur_thickness * line_width * 80/ppi));
163 	    }
164 	}
165 
set_style(s,v)166 static void set_style(s, v)
167 int	s;
168 float	v;
169 {
170 	static float	style_val = -1;
171 
172 	if (s == DASH_LINE || s == DOTTED_LINE) {
173 	    if (v == style_val || v == 0.0) return;
174 	    style_val = v;
175 	    fprintf(tfp, "dashwid = %.3fi\n", style_val/ppi);
176 	    }
177 	}
178 
set_baseline(b)179 static void set_baseline(b)
180 int	b;
181 {
182 	static int	cur_baseline = -1;
183 
184 	if (b != cur_baseline) {
185 		fprintf(tfp, ".baseline %d\n", b);
186 		cur_baseline = b;
187 	}
188 }
189 
set_texture(cur_texture)190 static void set_texture(cur_texture)
191 int	cur_texture;
192 {
193 	/*
194 	 * This applies only to bitmapped texture patterns defined in
195 	 * tpicfonts.h. See set_fill() below for normal shading.
196 	 */
197 	if (cur_texture <= BLACK_FILL || cur_texture > MAXPATTERNS + BLACK_FILL)
198 		return;
199 	fprintf(tfp, ".tx 16 %s\n",
200 		texture_patterns[cur_texture - BLACK_FILL - 1]);
201 }
202 
203 /*
204  * Set the shade for filling an object. Your dvi-to-postscript driver must
205  * distinguish between a "shaded" attribute with or without a parameter.
206  * If there is no parameter, then it should do a bitmap texture fill;
207  * otherwise, it should do a normal gray-scale fill. Note that the gray-
208  * scale fill parameter is wired for fig2.X (the constant 0.05).
209  */
set_fill(cur_fill)210 static void set_fill(cur_fill)
211 int	cur_fill;
212 {
213 	if(cur_fill < WHITE_FILL ||
214 	   cur_fill > BLACK_FILL + MAXPATTERNS)
215 		return;
216 	switch(cur_fill) {
217 	case BLACK_FILL:
218 		fprintf(tfp, " black");
219 		break;
220 	case WHITE_FILL:
221 		fprintf(tfp, " white");
222 		break;
223 	default:
224 		if (cur_fill > BLACK_FILL)
225 			fprintf (tfp, " shaded");
226 		else
227 			fprintf(tfp, " shaded %0.3f", (cur_fill-1)*0.05);
228 		break;
229 	}
230 }
231 
232 #ifdef TPIC_ARC_BOX
gentpic_line(l)233 void gentpic_line(l)
234 F_line	*l;
235 {
236 	F_point		*p, *q;
237 	int	llx, lly, urx, ury;
238 
239 	set_linewidth(l->thickness);
240 	set_style(l->style, l->style_val);
241 	set_texture(l->fill_style);
242 	p = l->points;
243 	q = p->next;
244 	if (q == NULL) { /* A single point line */
245 	    fprintf(tfp, "line from %.3f,%.3f to %.3f,%.3f",
246 			p->x/ppi, convy(p->y/ppi), p->x/ppi, convy(p->y/ppi));
247 	    newline();
248 	    return;
249 	    }
250 
251 	if (l->type == T_BOX || l->type == T_ARC_BOX) {
252 		llx = urx = p->x;
253 		lly = ury = p->y;
254 		while (q != NULL) {
255 			p = q;
256 			if (p->x < llx) {
257 				llx = p->x;
258 			} else if (p->x > urx) {
259 				urx = p->x;
260 			}
261 			if (p->y < lly) {
262 				lly = p->y;
263 			} else if (p->y > ury) {
264 				ury = p->y;
265 			}
266 			q = q->next;
267 		}
268 		fprintf(tfp, "box height %.3f width %.3f", (ury-lly)/ppi,
269 			(urx-llx)/ppi);
270 		switch(l->style) {
271 		case SOLID_LINE:
272 			break;
273 		case DASH_LINE:
274 			fprintf(tfp, " dashed");
275 			break;
276 		case DOTTED_LINE:
277 			fprintf(tfp, " dotted");
278 			break;
279 		default:
280 			put_msg("Program error! No other line styles allowed.\n");
281 			return;
282 		}
283 		if (l->thickness == 0)
284 			fprintf(tfp, " invis");
285 		fprintf(tfp, " radius %.3f", l->radius/ppi);
286 		set_fill(l->fill_style);
287 		fprintf(tfp, " with .nw at %.3f,%.3f", llx/ppi, convy(lly/ppi));
288 		newline();
289 		return;
290 	}
291 
292 	if (l->style == DASH_LINE && l->style_val > 0.0)
293 	    fprintf(tfp, "line dashed");
294 	else if (l->style == DOTTED_LINE && l->style_val > 0.0)
295 	    fprintf(tfp, "line dotted");
296 	else
297 	    fprintf(tfp, "line");
298 
299 	/* Place arrowheads or lack there of on the line*/
300 	if ((l->for_arrow) && (l->back_arrow))
301 	    fprintf(tfp, " <-> from");
302 	else if (l->back_arrow)
303 	    fprintf(tfp, " <- from");
304 	else if (l->for_arrow)
305 	    fprintf(tfp, " -> from");
306         else
307 	    fprintf(tfp, " from ");
308 
309 	fprintf(tfp, " %.3f,%.3f to", p->x/ppi, convy(p->y/ppi));
310 	while (q->next != NULL) {
311 	    p = q;
312 	    q = q->next;
313 	    fprintf(tfp, " %.3f,%.3f to", p->x/ppi, convy(p->y/ppi));
314 	    }
315 	fprintf(tfp, " %.3f,%.3f", q->x/ppi, convy(q->y/ppi));
316 	if (l->thickness == 0)
317 		fprintf(tfp, " invis");
318 	if (l->type == T_POLYGON)
319 		set_fill(l->fill_style);
320 	newline();
321 	}
322 
323 #else
gentpic_line(l)324 void gentpic_line(l)
325 F_line	*l;
326 {
327 	F_point		*p, *q;
328 	int		radius = l->radius;
329 	char		attr[80];
330 
331 	attr[0] = '\0';
332 	set_linewidth(l->thickness);
333 	set_style(l->style, l->style_val);
334 	set_texture(l->fill_style);
335 	p = l->points;
336 	q = p->next;
337 	if (q == NULL) { /* A single point line */
338 	    fprintf(tfp, "line from %.3f,%.3f to %.3f,%.3f",
339 			p->x/ppi, convy(p->y/ppi), p->x/ppi, convy(p->y/ppi));
340 	    newline();
341 	    return;
342 	    }
343 
344 	if (l->style == DASH_LINE && l->style_val > 0.0)
345 		strcat(attr, "dashed");
346 	else if (l->style == DOTTED_LINE && l->style_val > 0.0)
347 		strcat(attr, "dotted");
348 	if (l->thickness == 0)
349 		strcat(attr, " invis");
350 
351 	if (radius > 0) {	/* T_ARC_BOX */
352                 register int xmin,xmax,ymin,ymax;
353 
354                 xmin = xmax = p->x;
355                 ymin = ymax = p->y;
356                 while (p->next != NULL) { /* find lower left and upper right corners */
357                         p=p->next;
358                         if (xmin > p->x)
359                                 xmin = p->x;
360                         else if (xmax < p->x)
361                                 xmax = p->x;
362                         if (ymin > p->y)
363                                 ymin = p->y;
364                         else if (ymax < p->y)
365                                 ymax = p->y;
366 		}
367                 fprintf(tfp, "line %s from  %.3f,%.3f to %.3f, %.3f\n", attr,
368 			(xmin+radius)/ppi, convy(ymin/ppi),
369 			(xmax-radius)/ppi, convy(ymin/ppi));
370                 fprintf(tfp, "arc cw %s from %.3f, %.3f to %.3f,%.3f radius %.3f\n",
371 			attr, (xmax-radius)/ppi, convy(ymin/ppi),
372 			(xmax/ppi), convy((ymin+radius)/ppi), radius/ppi);
373                 fprintf(tfp, "line %s from  %.3f,%.3f to %.3f, %.3f\n", attr,
374 			xmax/ppi, convy((ymin+radius)/ppi),
375 			xmax/ppi, convy((ymax-radius)/ppi));
376                 fprintf(tfp, "arc cw %s from %.3f, %.3f to %.3f,%.3f radius %.3f\n",
377 			attr, xmax/ppi, convy((ymax-radius)/ppi),
378 			(xmax-radius)/ppi, convy(ymax/ppi), radius/ppi);
379                 fprintf(tfp, "line %s from  %.3f,%.3f to %.3f, %.3f\n", attr,
380 			(xmax-radius)/ppi, convy(ymax/ppi),
381 			(xmin+radius)/ppi, convy(ymax/ppi));
382                 fprintf(tfp, "arc cw %s from %.3f, %.3f to %.3f,%.3f radius %.3f\n",
383 			attr, (xmin+radius)/ppi, convy(ymax/ppi),
384 			xmin/ppi, convy((ymax-radius)/ppi), radius/ppi);
385                 fprintf(tfp, "line %s from  %.3f,%.3f to %.3f, %.3f\n", attr,
386 			xmin/ppi, convy((ymax-radius)/ppi),
387 			xmin/ppi, convy((ymin+radius)/ppi));
388                 fprintf(tfp, "arc cw %s from %.3f, %.3f to %.3f,%.3f radius %.3f",
389 			attr, xmin/ppi, convy((ymin+radius)/ppi),
390 			(xmin+radius)/ppi, convy(ymin/ppi), radius/ppi);
391 	} else {
392 		/* Place arrowheads or lack there of on the line*/
393 		fprintf(tfp, "line %s", attr);
394 		if ((l->for_arrow) && (l->back_arrow))
395 			fprintf(tfp, " <-> from");
396 		else if (l->back_arrow)
397 			fprintf(tfp, " <- from");
398 		else if (l->for_arrow)
399 			fprintf(tfp, " -> from");
400 		else
401 			fprintf(tfp, " from ");
402 
403 		fprintf(tfp, " %.3f,%.3f to", p->x/ppi, convy(p->y/ppi));
404 		while (q->next != NULL) {
405 			p = q;
406 			q = q->next;
407 			fprintf(tfp, " %.3f,%.3f to", p->x/ppi, convy(p->y/ppi));
408 		}
409 		fprintf(tfp, " %.3f,%.3f", q->x/ppi, convy(q->y/ppi));
410 	}
411 	if (l->type != T_POLYLINE)
412 		set_fill(l->fill_style);
413 	newline();
414 	}
415 #endif
416 
gentpic_spline(s)417 void gentpic_spline(s)
418 F_spline	*s;
419 {
420 	if (int_spline(s))
421 	    gentpic_itp_spline(s);
422 	else
423 	    gentpic_ctl_spline(s);
424 	}
425 
gentpic_ctl_spline(s)426 void gentpic_ctl_spline(s)
427 F_spline	*s;
428 {
429 	if (closed_spline(s))
430 	    gentpic_closed_spline(s);
431 	else
432 	    gentpic_open_spline(s);
433 	}
434 
gentpic_open_spline(s)435 void gentpic_open_spline(s)
436 F_spline	*s;
437 {
438 	double		x1, y1, x2, y2;
439 	F_point		*p, *q;
440 
441 	p = s->points;
442 	x1 = p->x/ppi; y1 = convy(p->y/ppi);
443 	p = p->next;
444 	x2 = p->x/ppi; y2 = convy(p->y/ppi);
445 
446 	set_style(s->style, s->style_val);
447 	set_linewidth(s->thickness);
448 
449 	if (p->next == NULL) {
450 	    fprintf(tfp, "line");
451 	    if (s->style == DASH_LINE && s->style_val > 0.0)
452 		    fprintf(tfp, " dashed");
453 	    else if (s->style == DOTTED_LINE && s->style_val > 0.0)
454 		    fprintf(tfp, " dotted");
455 
456 
457            /* Attach arrowhead as required */
458 	    if ((s->for_arrow) && (s->back_arrow))
459 	       fprintf(tfp, " <->");
460 	    else if (s->back_arrow)
461 	       fprintf(tfp, " <-");
462 	    else if (s->for_arrow)
463 	       fprintf(tfp, " ->");
464 
465 	    fprintf(tfp, " from %.3f,%.3f to %.3f,%.3f", x1, y1, x2, y2);
466 	    newline();
467 	    return;
468 	    }
469 
470 	fprintf(tfp, "spline");
471 	if (s->style == DASH_LINE && s->style_val > 0.0)
472 	    fprintf(tfp, " dashed");
473 	else if (s->style == DOTTED_LINE && s->style_val > 0.0)
474 	    fprintf(tfp, " dotted");
475 
476 
477            /* Attach arrowhead as required */
478 	    if ((s->for_arrow) && (s->back_arrow))
479 	       fprintf(tfp, " <->");
480 	    else if (s->back_arrow)
481 	       fprintf(tfp, " <-");
482 	    else if (s->for_arrow)
483 	       fprintf(tfp, " ->");
484 
485 	fprintf(tfp, " from %.3f,%.3f to %.3f,%.3f", x1, y1, x2, y2);
486 
487 	for (q = p->next; q->next != NULL; p = q, q = q->next)
488 	    fprintf(tfp, " to %.3f,%.3f", q->x/ppi, convy(q->y/ppi));
489 	fprintf(tfp, " to %.3f,%.3f", (x2=q->x/ppi), (y2=convy(q->y/ppi)));
490 
491 	newline();
492 	}
493 
gentpic_ellipse(e)494 void gentpic_ellipse(e)
495 F_ellipse	*e;
496 {
497 	set_linewidth(e->thickness);
498 	set_texture(e->fill_style);
499 	set_style(e->style, e->style_val);
500 
501 	fprintf(tfp, "ellipse");
502 
503 	if (e->style == DASH_LINE && e->style_val > 0.0)
504 		fprintf(tfp, " dashed");
505 	else if (e->style == DOTTED_LINE && e->style_val > 0.0)
506 		fprintf(tfp, " dotted");
507 
508 	fprintf(tfp, " at %.3f,%.3f wid %.3f ht %.3f",
509 		e->center.x/ppi, convy(e->center.y/ppi),
510 		2 * e->radiuses.x/ppi, 2 * e->radiuses.y/ppi);
511 	if (e->thickness == 0)
512 		fprintf(tfp, " invis");
513 	set_fill(e->fill_style);
514 	newline();
515 	}
516 
517 /*
518 Text is displayed on the screen with the base line starting at
519 (base_x, base_y); some characters extend below this line.
520 Pic displays the center of the height of text at the given
521 coordinate. HT_OFFSET is used to compensate all the above factors
522 so text position in fig should be at the same position on
523 the screen as on the hard copy.
524 
525 THIS IS A HACK. tpic should be modified to put text with its
526 baseline at the given coordinates as does fig -- Baron.
527 */
528 #define			HT_OFFSET	(0.25 / 72.0)
529 
gentpic_text(t)530 void gentpic_text(t)
531 F_text	*t;
532 {
533 	float	y;
534         char	*tpos;
535 	int	virtual_font = 0;
536 
537 	/*
538 	 * tpic is informed of the baseline spacing here. Not particularly
539 	 * useful in this version of the driver.
540 	 */
541 	set_baseline((int)t->size);
542 
543 	unpsfont(t);
544 
545 	if (t->font > MAX_FONT || vfont)
546 		virtual_font = 1;	/* must be a virtual font */
547 
548 	if (virtual_font)
549 		/*
550 		 * NOTE. Virtual fonts are defined dynamically using
551 		 * TeX's font definition machinery.
552 		 */
553 		fprintf(tfp, "\"\\font\\fig%s=%s at %dpt \\fig%s ",
554 			TEXFONT(t->font), TEXFONT(t->font), (int)t->size,
555 			TEXFONT(t->font));
556 	else
557 #ifdef FST
558 		fprintf(tfp, "\"\\%spt\\%s ", TEXFONTMAG(t), TEXFONT(t->font));
559 #else
560 		fprintf(tfp, "\"\\%s%s ", TEXFONTMAG(t), TEXFONT(t->font));
561 #endif
562 
563         switch (t->type) {
564         case T_LEFT_JUSTIFIED:
565         case DEFAULT:
566             tpos = "ljust";
567             break;
568         case T_CENTER_JUSTIFIED:
569             tpos = "";
570             break;
571         case T_RIGHT_JUSTIFIED:
572             tpos = "rjust";
573             break;
574         default:
575             fprintf(stderr, "unknown text position type\n");
576             exit(1);
577         }
578 	y = convy(t->base_y/ppi) + (TEXFONTMAGINT(t)
579 		* HT_OFFSET);
580 
581 	fprintf(tfp, "%s\" at %.3f,%.3f %s",
582 		t->cstring, t->base_x/ppi, y, tpos);
583 	newline();
584 }
585 
gentpic_arc(a)586 void gentpic_arc(a)
587 F_arc	*a;
588 {
589 	double		cx, cy, sx, sy, ex, ey;
590 
591 	cx = a->center.x/ppi; cy = convy(a->center.y/ppi);
592 	sx = a->point[0].x/ppi; sy = convy(a->point[0].y/ppi);
593 	ex = a->point[2].x/ppi; ey = convy(a->point[2].y/ppi);
594 
595 	set_texture(a->fill_style);
596 	set_linewidth(a->thickness);
597 	set_style(a->style, a->style_val);
598 
599 	fprintf(tfp, "arc");
600 
601 	if (a->style == DASH_LINE && a->style_val > 0.0)
602 		fprintf(tfp, " dashed");
603 	else if (a->style == DOTTED_LINE && a->style_val > 0.0)
604 		fprintf(tfp, " dotted");
605 
606 	/* Attach arrowhead as required */
607 	if ((a->type == T_OPEN_ARC) && (a->thickness != 0) && (a->back_arrow || a->for_arrow)) {
608 	    if ((a->for_arrow) && (a->back_arrow))
609 		fprintf(tfp, " <->");
610 	    else if (a->back_arrow)
611 		fprintf(tfp, " <-");
612 	    else if (a->for_arrow)
613 		fprintf(tfp, " ->");
614 	}
615 
616 
617 	if (a->direction)
618 	    fprintf(tfp, " at %.3f,%.3f from %.3f,%.3f to %.3f,%.3f",
619 			cx, cy, sx, sy, ex, ey);
620 	else
621 	    fprintf(tfp, " at %.3f,%.3f from %.3f,%.3f to %.3f,%.3f cw",
622 			cx, cy, sx, sy, ex, ey);
623 	if (a->thickness == 0)
624 		fprintf(tfp, " invis");
625 	set_fill(a->fill_style);
626 	newline();
627 
628 	}
629 
630 #if 0 /* function arc_tangent() is unused */
631 static void arc_tangent(x1, y1, x2, y2, direction, x, y)
632 double	x1, y1, x2, y2, *x, *y;
633 int	direction;
634 {
635 	if (direction) { /* counter clockwise  */
636 	    *x = x2 + (y2 - y1);
637 	    *y = y2 - (x2 - x1);
638 	    }
639 	else {
640 	    *x = x2 - (y2 - y1);
641 	    *y = y2 + (x2 - x1);
642 	    }
643 }
644 #endif /* function arc_tangent() is unused */
645 
646 #define		THRESHOLD	.05	/* inch */
647 
quadratic_spline(a1,b1,a2,b2,a3,b3,a4,b4)648 static void quadratic_spline(a1, b1, a2, b2, a3, b3, a4, b4)
649 double	a1, b1, a2, b2, a3, b3, a4, b4;
650 {
651 	double	x1, y1, x4, y4;
652 	double	xmid, ymid;
653 
654 	x1 = a1; y1 = b1;
655 	x4 = a4; y4 = b4;
656 
657 	xmid = (a2 + a3) / 2;
658 	ymid = (b2 + b3) / 2;
659 	if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD) {
660 	    fprintf(tfp, "\tto %.3f,%.3f\\\n", xmid, ymid);
661 	    }
662 	else {
663 	    quadratic_spline(x1, y1, ((x1+a2)/2), ((y1+b2)/2),
664 			((3*a2+a3)/4), ((3*b2+b3)/4), xmid, ymid);
665 	    }
666 
667 	if (fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
668 	    fprintf(tfp, "\tto %.3f,%.3f\\\n", x4, y4);
669 	    }
670 	else {
671 	    quadratic_spline(xmid, ymid, ((a2+3*a3)/4), ((b2+3*b3)/4),
672 			((a3+x4)/2), ((b3+y4)/2), x4, y4);
673 	    }
674 }
675 
gentpic_closed_spline(s)676 void gentpic_closed_spline(s)
677 F_spline	*s;
678 {
679 	F_point	*p;
680 	double	cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
681 	double	x1, y1, x2, y2;
682 
683 	p = s->points;
684 	x1 = p->x/ppi;  y1 = convy(p->y/ppi);
685 	p = p->next;
686 	x2 = p->x/ppi;  y2 = convy(p->y/ppi);
687 	cx1 = (x1 + x2) / 2;      cy1 = (y1 + y2) / 2;
688 	cx2 = (x1 + 3 * x2) / 4;  cy2 = (y1 + 3 * y2) / 4;
689 
690 	set_linewidth(s->thickness);
691 	set_texture(s->fill_style); /* probably won't work! */
692 	set_style(s->style, s->style_val);
693 
694 	for (p = p->next; p != NULL; p = p->next) {
695 	    fprintf(tfp, "line from %.3f,%.3f ", cx1, cy1);
696 	    x1 = x2;  y1 = y2;
697 	    x2 = p->x/ppi;  y2 = convy(p->y/ppi);
698 	    cx3 = (3 * x1 + x2) / 4;  cy3 = (3 * y1 + y2) / 4;
699 	    cx4 = (x1 + x2) / 2;      cy4 = (y1 + y2) / 2;
700 	    quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
701 	    newline();
702 	    /* fprintf(tfp, "\n"); */
703 	    cx1 = cx4;  cy1 = cy4;
704 	    cx2 = (x1 + 3 * x2) / 4;  cy2 = (y1 + 3 * y2) / 4;
705 	    }
706 	x1 = x2;  y1 = y2;
707 	p = s->points->next;
708 	x2 = p->x/ppi;  y2 = convy(p->y/ppi);
709 	cx3 = (3 * x1 + x2) / 4;  cy3 = (3 * y1 + y2) / 4;
710 	cx4 = (x1 + x2) / 2;      cy4 = (y1 + y2) / 2;
711 	fprintf(tfp, "line from %.3f,%.3f ", cx1, cy1);
712 	quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
713 	if (s->thickness == 0)
714 		fprintf(tfp, " invis");
715 	set_fill(s->fill_style);
716 	newline();
717 	/* fprintf(tfp, "\n"); */
718 	}
719 
gentpic_itp_spline(s)720 void gentpic_itp_spline(s)
721 F_spline	*s;
722 {
723 	F_point		*p1, *p2, *pfirst;
724 	F_control	*cp1, *cp2;
725 	double		x1, x2, y1, y2;
726 
727 	set_style(s->style, s->style_val);
728 	set_texture(s->fill_style); /* probably won't work! */
729 	set_linewidth(s->thickness);
730 
731 	p1 = s->points;
732 	cp1 = s->controls;
733 	x2 = p1->x/ppi; y2 = convy(p1->y/ppi);
734 
735          pfirst = p1->next;/*save first to test in loop*/
736 	for (p2 = p1->next, cp2 = cp1->next; p2 != NULL;
737 		p1 = p2, cp1 = cp2, p2 = p2->next, cp2 = cp2->next) {
738 
739 	    fprintf(tfp, "line ");
740 
741            /* Attach arrowhead as required */
742 
743 	    if ((s->back_arrow) && (p2 == pfirst))
744 	       fprintf(tfp, " <- ");
745 	    else if ((s->for_arrow) && (p2->next == NULL))
746 	       fprintf(tfp, " -> ");
747 
748 	    fprintf(tfp, " from %.3f,%.3f ", x2, y2);
749 
750 	    x1 = x2; y1 = y2;
751 	    x2 = p2->x/ppi; y2 = convy(p2->y/ppi);
752 	    bezier_spline(x1, y1, (double)cp1->rx/ppi, convy(cp1->ry/ppi),
753 		(double)cp2->lx/ppi, convy(cp2->ly/ppi), x2, y2);
754 	    /* fprintf(tfp, "\n"); */
755 	    newline();
756 	    }
757 
758 	}
759 
bezier_spline(a0,b0,a1,b1,a2,b2,a3,b3)760 static void bezier_spline(a0, b0, a1, b1, a2, b2, a3, b3)
761 double	a0, b0, a1, b1, a2, b2, a3, b3;
762 {
763 	double	x0, y0, x3, y3;
764 	double	sx1, sy1, sx2, sy2, tx, ty, tx1, ty1, tx2, ty2, xmid, ymid;
765 
766 	x0 = a0; y0 = b0;
767 	x3 = a3; y3 = b3;
768 	if (fabs(x0 - x3) < THRESHOLD && fabs(y0 - y3) < THRESHOLD) {
769 	    fprintf(tfp, "\tto %.3f,%.3f\\\n", x3, y3);
770 	    }
771 	else {
772 	    tx = (a1 + a2) / 2;		ty = (b1 + b2) / 2;
773 	    sx1 = (x0 + a1) / 2;	sy1 = (y0 + b1) / 2;
774 	    sx2 = (sx1 + tx) / 2;	sy2 = (sy1 + ty) / 2;
775 	    tx2 = (a2 + x3) / 2;	ty2 = (b2 + y3) / 2;
776 	    tx1 = (tx2 + tx) / 2;	ty1 = (ty2 + ty) / 2;
777 	    xmid = (sx2 + tx1) / 2;	ymid = (sy2 + ty1) / 2;
778 
779 	    bezier_spline(x0, y0, sx1, sy1, sx2, sy2, xmid, ymid);
780 	    bezier_spline(xmid, ymid, tx1, ty1, tx2, ty2, x3, y3);
781 	    }
782 	}
783 
784 static void
newline()785 newline()
786 {
787 	/*
788 	 * A vestige from another version of this driver.
789 	 */
790 	fprintf(tfp, "\n");
791 }
792 
793 struct driver dev_tpic = {
794      	gentpic_option,
795 	gentpic_start,
796 	gendev_null,
797 	gentpic_arc,
798 	gentpic_ellipse,
799 	gentpic_line,
800 	gentpic_spline,
801 	gentpic_text,
802 	gentpic_end,
803 	INCLUDE_TEXT
804 };
805 
806