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 * genpic : PIC 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 *
28 * Modified: Stuart Kemp & Dave Bonnell, July, 1991
29 * James Cook University,
30 * Australia
31 * Changes:
32 * Added T_ARC_BOX to genpic_line()
33 * Added 'thickness' attribute all over
34 * Added 'fill' attribute to ellipse
35 * Cleaned up the code
36 */
37
38 #include "fig2dev.h"
39 #include "object.h"
40 #include "picfonts.h"
41 #include "picpsfonts.h"
42
43 static void genpic_ctl_spline(), genpic_itp_spline();
44 static void genpic_open_spline(), genpic_closed_spline();
45
46 #define TOP 10.5 /* top of page is 10.5 inch */
47 static int LineThickness = 0;
48 static int OptArcBox = 0; /* Conditional use */
49 static int OptLineThick = 0;
50 static int OptEllipseFill = 0;
51 static int OptNoUnps = 0; /* prohibit unpsfont() */
52
53 void
genpic_option(opt,optarg)54 genpic_option(opt, optarg)
55 char opt, *optarg;
56 {
57 switch (opt) {
58
59 case 'f': /* set default text font */
60 { int i;
61
62 for ( i = 1; i <= MAX_FONT; i++ )
63 if ( !strcmp(optarg, picfontnames[i]) ) break;
64
65 if ( i > MAX_FONT)
66 fprintf(stderr,
67 "warning: non-standard font name %s\n", optarg);
68 }
69
70 picfontnames[0] = picfontnames[1] = optarg;
71 break;
72
73 case 's':
74 case 'm':
75 case 'L':
76 break;
77
78 case 'p':
79 if (strcmp(optarg, "all") == 0)
80 OptArcBox = OptLineThick = OptEllipseFill = 1;
81 else
82 if (strcmp(optarg, "arc") == 0)
83 OptArcBox = 1;
84 else
85 if (strcmp(optarg, "line") == 0)
86 OptLineThick = 1;
87 else
88 if (strcmp(optarg, "fill") == 0)
89 OptEllipseFill = 1;
90 else
91 if (strcmp(optarg, "psfont") == 0)
92 OptNoUnps = 1;
93 else
94 if (strcmp(optarg, "allps") == 0)
95 OptArcBox =
96 OptLineThick =
97 OptEllipseFill =
98 OptNoUnps = 1;
99 else
100 { fprintf(stderr, "Invalid option: %s\n", optarg);
101 exit(1);
102 }
103 break;
104 default:
105 put_msg(Err_badarg, opt, "pic");
106 exit(1);
107 }
108 }
109
110 static
convy(a)111 double convy(a)
112 double a;
113 {
114 return((double) TOP-a);
115 }
116
117 void
genpic_start(objects)118 genpic_start(objects)
119 F_compound *objects;
120 {
121 ppi = ppi/mag;
122
123 /* print any whole-figure comments prefixed with '.\" ' */
124 if (objects->comments) {
125 fprintf(tfp,".\\\"\n");
126 print_comments(".\\\" ",objects->comments, "");
127 fprintf(tfp,".\\\"\n");
128 }
129
130 fprintf(tfp, ".PS\n.ps %d\n", /* PIC preamble */
131 (int)(font_size != 0.0? (int) font_size : DEFAULT_FONT_SIZE));
132 }
133
134 int
genpic_end()135 genpic_end()
136 {
137 fprintf(tfp, ".PE\n"); /* PIC ending */
138
139 /* all ok */
140 return 0;
141 }
142
143 /*
144 The line thickness is, unfortunately, multiple of pixel.
145 One pixel thickness is a little too thick on the hard copy
146 so I scale it with 0.7; i.e., it's a kludge. The best way is
147 to allow thickness in fraction of pixel.
148
149 Note that the current version of psdit (a ditroff to postcript filter)
150 won't take the legitimate line thickness command.
151 */
152
153 static void
set_linewidth(w)154 set_linewidth(w)
155 int w;
156 {
157 LineThickness = w*80/ppi;
158 }
159
160 static void
AddThickness()161 AddThickness()
162 {
163 if (OptLineThick && LineThickness)
164 fprintf(tfp, " thickness %d", LineThickness);
165 }
166
167 static void
set_style(s,v)168 set_style(s, v)
169 int s;
170 double v;
171 {
172 static float style_val = -1;
173
174 if (s == DASH_LINE || s == DOTTED_LINE) {
175 if (v == style_val) return;
176 if (v == 0.0) return;
177 style_val = v;
178 fprintf(tfp, "dashwid = %.3f\n", (float)(style_val/80.0));
179 }
180 }
181
182 /*
183 * Makes use of the PIC 'box' command
184 *
185 * Returns 0 if command failed, else non-zero.
186 *
187 */
188
189 static int
genpic_box(l)190 genpic_box(l)
191 F_line *l;
192 {
193 int count, minx, miny, maxx, maxy;
194 int Valid; /* Valid box */
195 double width, height;
196 F_point *p, *q;
197
198 p = l->points;
199 q = p->next;
200 count = 1; /* Just a sanity check */
201 minx = maxx = p->x;
202 miny = maxy = p->y;
203
204 /* Find the boundaries */
205 while (q != NULL)
206 { count++;
207 if (q->x < minx) minx = q->x;
208 else
209 if (q->x > maxx) maxx = q->x;
210
211 if (q->y < miny) miny = q->y;
212 else
213 if (q->y > maxy) maxy = q->y;
214
215 q = q->next;
216 }
217
218 if ((Valid = (count == 5))) /* Valid box? */
219 { fprintf(tfp, "box");
220 if (l->thickness == 0)
221 fprintf(tfp, " invis");
222 else
223 if (l->style_val > 0.0) {
224 if (l->style == DASH_LINE)
225 fprintf(tfp, " dashed");
226 else if (l->style == DOTTED_LINE)
227 fprintf(tfp, " dotted");
228 }
229
230 /* Should have a #define somewhere for the # of fill patterns */
231 if (l->fill_style != UNFILLED)
232 fprintf(tfp, " fill %.3f", ((double) l->fill_style ) / (double) BLACK_FILL);
233
234 fprintf(tfp, " with .sw at (%.3f,%.3f) ",
235 minx / ppi, convy(maxy / ppi));
236
237 width = (maxx - minx) / ppi;
238 if (width < 0.0) width = -width;
239 height = convy(maxy / ppi) - convy(miny / ppi);
240 if (height < 0.0) height = -height;
241
242 fprintf(tfp, "width %.3f height %.3f", width, height);
243
244 if (OptArcBox && l->type == T_ARC_BOX)
245 fprintf(tfp, " rad %.3f", l->radius/ppi);
246
247 AddThickness();
248
249 fprintf(tfp, "\n");
250 }
251
252 return(Valid);
253 }
254
255 void
genpic_line(l)256 genpic_line(l)
257 F_line *l;
258 {
259 F_point *p, *q;
260
261 /* print any comments */
262 print_comments(".\\\" ",l->comments, "");
263
264 if (l->type == T_ARC_BOX && !OptArcBox)
265 { fprintf(stderr, "Arc box not implemented; substituting box.\n");
266 l->type = T_BOX;
267 }
268
269 set_linewidth(l->thickness);
270 set_style(l->style, l->style_val);
271 p = l->points;
272 q = p->next;
273 if (q == NULL) /* A single point line */
274 { fprintf(tfp, "line from %.3f,%.3f to %.3f,%.3f",
275 p->x/ppi, convy(p->y/ppi), p->x/ppi, convy(p->y/ppi));
276 AddThickness();
277 fprintf(tfp, "\n");
278 return;
279 }
280
281 if (l->type == T_BOX || l->type == T_ARC_BOX)
282 { if (genpic_box(l)) return;
283 fprintf(stderr, "Invalid T_BOX or T_ARC_BOX in fig file\n");
284 fprintf(stderr, " Using 'line' instead\n");
285 }
286
287 fprintf(tfp, "line");
288
289 if (l->style_val > 0.0)
290 { if (l->style == DASH_LINE)
291 fprintf(tfp, " dashed");
292 else
293 if (l->style == DOTTED_LINE)
294 fprintf(tfp, " dotted");
295 }
296
297 /* Place arrowheads or lack there of on the line*/
298 if ((l->for_arrow) && (l->back_arrow))
299 fprintf(tfp, " <->");
300 else if (l->back_arrow)
301 fprintf(tfp, " <-");
302 else if (l->for_arrow)
303 fprintf(tfp, " ->");
304
305 fprintf(tfp, " from %.3f,%.3f", p->x/ppi, convy(p->y/ppi));
306 do
307 { fprintf(tfp, " to %.3f,%.3f", q->x/ppi, convy(q->y/ppi));
308 q = q->next;
309 } while (q != NULL);
310
311 AddThickness();
312
313 fprintf(tfp, "\n");
314 }
315
316 void
genpic_spline(s)317 genpic_spline(s)
318 F_spline *s;
319 {
320 /* print any comments */
321 print_comments(".\\\" ",s->comments, "");
322
323 if (int_spline(s))
324 genpic_itp_spline(s);
325 else
326 genpic_ctl_spline(s);
327 }
328
329 static void
genpic_ctl_spline(s)330 genpic_ctl_spline(s)
331 F_spline *s;
332 {
333 if (closed_spline(s))
334 genpic_closed_spline(s);
335 else
336 genpic_open_spline(s);
337 }
338
339 static void
genpic_open_spline(s)340 genpic_open_spline(s)
341 F_spline *s;
342 {
343 double x1, y1, x2, y2;
344 F_point *p, *q;
345
346 p = s->points;
347 x1 = p->x/ppi; y1 = convy(p->y/ppi);
348 p = p->next;
349 x2 = p->x/ppi; y2 = convy(p->y/ppi);
350
351
352 /* Pic's spline supports only solid line style */
353 /* set_linewidth(s->thickness); */
354
355 if (p->next == NULL) {
356 fprintf(tfp, "line");
357
358 /* Attach arrowhead as required */
359 if ((s->for_arrow) && (s->back_arrow))
360 fprintf(tfp, " <->");
361 else if (s->back_arrow)
362 fprintf(tfp, " <-");
363 else if (s->for_arrow)
364 fprintf(tfp, " ->");
365
366 fprintf(tfp, " from %.3f,%.3f to %.3f,%.3f", x1, y1, x2, y2);
367
368 AddThickness();
369
370 fprintf(tfp, "\n");
371
372 return;
373 }
374
375 fprintf(tfp, "spline");
376
377 /* Attach arrowhead as required */
378 if ((s->for_arrow) && (s->back_arrow))
379 fprintf(tfp, " <->");
380 else if (s->back_arrow)
381 fprintf(tfp, " <-");
382 else if (s->for_arrow)
383 fprintf(tfp, " ->");
384
385 fprintf(tfp, " from %.3f,%.3f to %.3f,%.3f", x1, y1, x2, y2);
386
387 for (q = p->next; q->next != NULL; p = q, q = q->next)
388 fprintf(tfp, " to %.3f,%.3f", q->x/ppi, convy(q->y/ppi));
389 fprintf(tfp, " to %.3f,%.3f", q->x/ppi, convy(q->y/ppi));
390
391 AddThickness();
392
393 fprintf(tfp, "\n");
394 }
395
396 void
genpic_ellipse(e)397 genpic_ellipse(e)
398 F_ellipse *e;
399 {
400 /* print any comments */
401 print_comments(".\\\" ",e->comments, "");
402
403 set_linewidth(e->thickness);
404 if (e->type == 3 || e->type == 4)
405 fprintf(tfp, "circle at %.3f,%.3f rad %.3f",
406 e->center.x/ppi, convy(e->center.y/ppi),
407 e->radiuses.x/ppi);
408 else
409 fprintf(tfp, "ellipse at %.3f,%.3f wid %.3f ht %.3f",
410 e->center.x/ppi, convy(e->center.y/ppi),
411 2 * e->radiuses.x/ppi, 2 * e->radiuses.y/ppi);
412
413 if ( OptEllipseFill && e->fill_style != UNFILLED)
414 fprintf(tfp, " fill %.3f", (double)e->fill_style / (double) BLACK_FILL);
415
416 AddThickness();
417
418 fprintf(tfp, "\n");
419 }
420
421 /*
422 Text is display on the screen with the base line starting at
423 (base_x, base_y); some characters extend below this line.
424 Pic displays the center of the height of text at the given
425 coordinate. HT_OFFSET is use to compensate all the above factors
426 so text position in fig 1.4 should be at the same position on
427 the screen as on the hard copy.
428 */
429 #define HT_OFFSET (0.2 / 72.0)
430
431 void
genpic_text(t)432 genpic_text(t)
433 F_text *t;
434 {
435 float y;
436 int size;
437 char *tpos;
438
439 /* print any comments */
440 print_comments(".\\\" ",t->comments, "");
441
442
443 size = PICFONTMAG(t);
444 if (!OptNoUnps) {
445 unpsfont(t);
446 fprintf(tfp, "\"\\s%d\\f%s", size, PICFONT(t->font));
447 } else {
448 fprintf(tfp, ".ps\n.ps %d\n", size );
449 fprintf(tfp, ".ft\n.ft %s\n", PICPSFONT(t) );
450 }
451
452 switch (t->type) {
453 case T_LEFT_JUSTIFIED:
454 case DEFAULT:
455 tpos = "ljust";
456 break;
457 case T_CENTER_JUSTIFIED:
458 tpos = "";
459 break;
460 case T_RIGHT_JUSTIFIED:
461 tpos = "rjust";
462 break;
463 default:
464 fprintf(stderr, "unknown text position type\n");
465 exit(1);
466 }
467 y = convy(t->base_y/ppi) + size * HT_OFFSET;
468 if (!OptNoUnps)
469 fprintf(tfp, "%s\\fP\" at %.3f,%.3f %s\n",
470 t->cstring, t->base_x/ppi, y, tpos);
471 else
472 fprintf(tfp, "\"%s\" at %.3f,%.3f %s\n.ft \n.ps \n",
473 t->cstring, t->base_x/ppi, y, tpos);
474 }
475
476 void
genpic_arc(a)477 genpic_arc(a)
478 F_arc *a;
479 {
480 double cx, cy, sx, sy, ex, ey;
481
482 /* print any comments */
483 print_comments(".\\\" ",a->comments, "");
484
485 cx = a->center.x/ppi; cy = convy(a->center.y/ppi);
486 sx = a->point[0].x/ppi; sy = convy(a->point[0].y/ppi);
487 ex = a->point[2].x/ppi; ey = convy(a->point[2].y/ppi);
488
489 set_linewidth(a->thickness);
490
491 fprintf(tfp, "arc ");
492
493 if (a->style_val > 0.0) {
494 if (a->style == DASH_LINE)
495 fprintf(tfp, " dashed");
496 else if (a->style == DOTTED_LINE)
497 fprintf(tfp, " dotted");
498 }
499
500 /* Attach arrowhead as required */
501 if ((a->type == T_OPEN_ARC) && (a->thickness != 0) && (a->back_arrow || a->for_arrow)) {
502 if ((a->for_arrow) && (a->back_arrow))
503 fprintf(tfp, " <->");
504 else if (a->back_arrow)
505 fprintf(tfp, " <-");
506 else if (a->for_arrow)
507 fprintf(tfp, " ->");
508 }
509
510
511 fprintf(tfp, " at %.3f,%.3f from %.3f,%.3f to %.3f,%.3f",
512 cx, cy, sx, sy, ex, ey);
513
514 if (!a->direction)
515 fprintf(tfp, " cw");
516
517 if (a->fill_style != UNFILLED)
518 fprintf(stderr, "PIC does not support filled arcs ... ignoring 'fill' directive\n");
519
520 AddThickness();
521 fprintf(tfp, "\n");
522 }
523
524 #define THRESHOLD .05 /* inch */
525
526 static void
quadratic_spline(a1,b1,a2,b2,a3,b3,a4,b4)527 quadratic_spline(a1, b1, a2, b2, a3, b3, a4, b4)
528 double a1, b1, a2, b2, a3, b3, a4, b4;
529 {
530 double x1, y1, x4, y4;
531 double xmid, ymid;
532
533 x1 = a1; y1 = b1;
534 x4 = a4; y4 = b4;
535
536 xmid = (a2 + a3) / 2;
537 ymid = (b2 + b3) / 2;
538 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD)
539 { fprintf(tfp, " to %.3f,%.3f", xmid, ymid);
540 }
541 else {
542 quadratic_spline(x1, y1, ((x1+a2)/2), ((y1+b2)/2),
543 ((3*a2+a3)/4), ((3*b2+b3)/4), xmid, ymid);
544 }
545
546 if (fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD)
547 { fprintf(tfp, " to %.3f,%.3f", x4, y4);
548 }
549 else {
550 quadratic_spline(xmid, ymid, ((a2+3*a3)/4), ((b2+3*b3)/4),
551 ((a3+x4)/2), ((b3+y4)/2), x4, y4);
552 }
553 }
554
555 void
genpic_closed_spline(s)556 genpic_closed_spline(s)
557 F_spline *s;
558 {
559 F_point *p;
560 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
561 double x1, y1, x2, y2;
562
563 p = s->points;
564 x1 = p->x/ppi; y1 = convy(p->y/ppi);
565 p = p->next;
566 x2 = p->x/ppi; y2 = convy(p->y/ppi);
567 cx1 = (x1 + x2) / 2; cy1 = (y1 + y2) / 2;
568 cx2 = (x1 + 3 * x2) / 4; cy2 = (y1 + 3 * y2) / 4;
569
570 for (p = p->next; p != NULL; p = p->next) {
571 fprintf(tfp, "line from %.3f,%.3f ", cx1, cy1);
572 x1 = x2; y1 = y2;
573 x2 = p->x/ppi; y2 = convy(p->y/ppi);
574 cx3 = (3 * x1 + x2) / 4; cy3 = (3 * y1 + y2) / 4;
575 cx4 = (x1 + x2) / 2; cy4 = (y1 + y2) / 2;
576 quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
577 AddThickness();
578 fprintf(tfp, "\n");
579 cx1 = cx4; cy1 = cy4;
580 cx2 = (x1 + 3 * x2) / 4; cy2 = (y1 + 3 * y2) / 4;
581 }
582 x1 = x2; y1 = y2;
583 p = s->points->next;
584 x2 = p->x/ppi; y2 = convy(p->y/ppi);
585 cx3 = (3 * x1 + x2) / 4; cy3 = (3 * y1 + y2) / 4;
586 cx4 = (x1 + x2) / 2; cy4 = (y1 + y2) / 2;
587 fprintf(tfp, "line from %.3f,%.3f ", cx1, cy1);
588 quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
589 AddThickness();
590 fprintf(tfp, "\n");
591 }
592
593 static void
bezier_spline(a0,b0,a1,b1,a2,b2,a3,b3)594 bezier_spline(a0, b0, a1, b1, a2, b2, a3, b3)
595 double a0, b0, a1, b1, a2, b2, a3, b3;
596 {
597 double x0, y0, x3, y3;
598 double sx1, sy1, sx2, sy2, tx, ty, tx1, ty1, tx2, ty2, xmid, ymid;
599
600 x0 = a0; y0 = b0;
601 x3 = a3; y3 = b3;
602 if (fabs(x0 - x3) < THRESHOLD && fabs(y0 - y3) < THRESHOLD)
603 { fprintf(tfp, " to %.3f,%.3f", x3, y3);
604 }
605 else {
606 tx = (a1 + a2) / 2; ty = (b1 + b2) / 2;
607 sx1 = (x0 + a1) / 2; sy1 = (y0 + b1) / 2;
608 sx2 = (sx1 + tx) / 2; sy2 = (sy1 + ty) / 2;
609 tx2 = (a2 + x3) / 2; ty2 = (b2 + y3) / 2;
610 tx1 = (tx2 + tx) / 2; ty1 = (ty2 + ty) / 2;
611 xmid = (sx2 + tx1) / 2; ymid = (sy2 + ty1) / 2;
612
613 bezier_spline(x0, y0, sx1, sy1, sx2, sy2, xmid, ymid);
614 bezier_spline(xmid, ymid, tx1, ty1, tx2, ty2, x3, y3);
615 }
616 }
617
618 void
genpic_itp_spline(s)619 genpic_itp_spline(s)
620 F_spline *s;
621 {
622 F_point *p1, *p2, *pfirst;
623 F_control *cp1, *cp2;
624 double x1, x2, y1, y2;
625
626 p1 = s->points;
627 cp1 = s->controls;
628 cp2 = cp1->next;
629 x2 = p1->x/ppi; y2 = convy(p1->y/ppi);
630
631 pfirst = p1->next;/*save first to test in loop*/
632 for (p2 = p1->next, cp2 = cp1->next; p2 != NULL;
633 p1 = p2, cp1 = cp2, p2 = p2->next, cp2 = cp2->next) {
634
635 fprintf(tfp, "line ");
636
637 /* Attach arrowhead as required */
638
639 if ((s->back_arrow) && (p2 == pfirst))
640 fprintf(tfp, " <- ");
641 else if ((s->for_arrow) && (p2->next == NULL))
642 fprintf(tfp, " -> ");
643
644 fprintf(tfp, " from %.3f,%.3f", x2, y2);
645
646 x1 = x2; y1 = y2;
647 x2 = p2->x/ppi; y2 = convy(p2->y/ppi);
648 bezier_spline(x1, y1, (double)cp1->rx/ppi, convy(cp1->ry/ppi),
649 (double)cp2->lx/ppi, convy(cp2->ly/ppi), x2, y2);
650 AddThickness();
651 fprintf(tfp, "\n");
652 }
653
654 }
655
656 struct driver dev_pic = {
657 genpic_option,
658 genpic_start,
659 gendev_null,
660 genpic_arc,
661 genpic_ellipse,
662 genpic_line,
663 genpic_spline,
664 genpic_text,
665 genpic_end,
666 INCLUDE_TEXT
667 };
668