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