1 /*
2 * TransFig: Facility for Translating Fig code
3 * Copyright (c) 1991 by Micah Beck
4 * Parts Copyright (c) 1985-1988 by Supoj Sutanthavibul
5 * Parts Copyright (c) 1989-2002 by Brian V. Smith
6 *
7 * Any party obtaining a copy of these files is granted, free of charge, a
8 * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
9 * nonexclusive right and license to deal in this software and
10 * documentation files (the "Software"), including without limitation the
11 * rights to use, copy, modify, merge, publish and/or distribute copies of
12 * the Software, and to permit persons who receive copies from any such
13 * party to do so, with the only requirement being that this copyright
14 * notice remain intact.
15 *
16 */
17
18 /*
19 * gentextyl.c : TeXtyl driver for fig2dev
20 *
21 * Author: Gary Beihl, MCC 8/90
22 * (beihl@mcc.com)
23 *
24 * Based on the pictex driver by Micah Beck
25 *
26 */
27
28 #include "fig2dev.h"
29 #include "object.h"
30 #include "texfonts.h"
31
32 static void putline();
33
34 #define rint(a) floor((a)+0.5) /* close enough? */
35
36 static void gentextyl_ctl_spline(), gentextyl_itp_spline();
37 static void bezier_spline();
38 static void draw_arrow_head();
39 static void set_style();
40 static void rtop();
41 static void set_linewidth();
42 static void set_style();
43
44 static int line_style = 0; /* Textyl solid line style */
45 static int linethick = 2; /* Range is 1-12 `pixels' */
46
47
48 static void
gentextyl_option(opt,optarg)49 gentextyl_option(opt, optarg)
50 char opt, *optarg;
51 {
52 int i;
53
54 switch (opt) {
55 case 'a':
56 /* capfonts = 1; */
57 break;
58
59 case 'f': /* set default text font */
60 for ( i = 1; i <= MAX_FONT; i++ )
61 if ( !strcmp(optarg, texfontnames[i]) ) break;
62
63 if ( i > MAX_FONT)
64 {
65 fprintf(stderr,
66 "warning: non-standard font name %s ignored\n", optarg);
67 }
68 else
69 {
70 texfontnames[0] = texfontnames[i];
71 #ifdef NFSS
72 texfontfamily[0] = texfontfamily[i];
73 texfontseries[0] = texfontseries[i];
74 texfontshape[0] = texfontshape[i];
75 #endif
76 }
77 break;
78
79 case 'l': /* set line thickness */
80 linethick = atoi(optarg);
81 if (linethick < 1 || linethick > 12) {
82 put_msg(Err_badarg, opt, "textyl");
83 exit(1);
84 }
85 break;
86
87 case 'p':
88 case 's':
89 case 'm':
90 case 'L':
91 break;
92
93 default:
94 put_msg(Err_badarg, opt, "textyl");
95 exit(1);
96 }
97 }
98
99 #define TOP (10.5) /* top of page is 10.5 inch */
100 #define SCALE (65536.0*72.27)
101 #define measure 'S'
102
103 static int
convy(a)104 convy(a)
105 double a;
106 {
107 return (int)(((ury - a) * SCALE) / ppi);
108 }
109
110 static int
convx(a)111 convx(a)
112 double a; {
113 float f;
114 f = a * SCALE;
115 return (int)(f / ppi);
116 }
117
118 void
gentextyl_start(objects)119 gentextyl_start(objects)
120 F_compound *objects;
121 {
122
123 texfontsizes[0] = texfontsizes[1] =
124 texfontsizes[(font_size != 0.0? (int) font_size : DEFAULT_FONT_SIZE)+1];
125
126 /* print any whole-figure comments prefixed with "%" */
127 if (objects->comments) {
128 fprintf(tfp,"%%\n");
129 print_comments("% ",objects->comments, "");
130 fprintf(tfp,"%%\n");
131 }
132 /* Textyl start */
133 fprintf(tfp, "\\begintyl{%fsp}\n",ury/ppi*SCALE);
134 }
135
136 int
gentextyl_end()137 gentextyl_end()
138 {
139 fprintf(tfp,"\\endtyl\n");
140
141 /* all ok */
142 return 0;
143 }
144
145
146 static void
set_linewidth(w)147 set_linewidth(w)
148 int w;
149 {
150 /* Nop */
151 }
152
153 void
gentextyl_line(l)154 gentextyl_line(l)
155 F_line *l;
156 {
157 F_point *p, *q;
158
159 /* print any comments prefixed with "%" */
160 print_comments("% ",l->comments, "");
161
162 fprintf(tfp, "%%\n%% Fig POLYLINE object\n%%\n");
163
164 set_linewidth(l->thickness);
165 set_style(l->style, l->style_val);
166
167 p = l->points;
168 q = p->next;
169
170
171 if (q == NULL) { /* A single point line */
172 fprintf(tfp, "\\special{tyl line %c %d L %d %u %u; %u %u}\n",
173 measure,linethick,line_style,
174 convx((double)p->x), convy((double)p->y),
175 convx((double)p->x), convy((double)p->y));
176 return;
177 }
178 if (l->back_arrow)
179 draw_arrow_head((double)q->x, (double)q->y, (double)p->x,
180 (double)p->y, l->back_arrow->ht, l->back_arrow->wid);
181 set_style(l->style, l->style_val);
182
183 while (q->next != NULL) {
184
185 putline(p->x, p->y, q->x, q->y);
186 p = q;
187 q = q->next;
188 }
189
190 putline(p->x, p->y, q->x, q->y);
191 if (l->for_arrow)
192 draw_arrow_head((double)p->x, (double)p->y, (double)q->x,
193 (double)q->y, l->for_arrow->ht, l->for_arrow->wid);
194
195 if (l->fill_style && (int)l->fill_style != DEFAULT)
196 fprintf(stderr, "Line area fill not implemented\n");
197 }
198
199 /*
200 * set_style - issue style commands as appropriate
201 */
202 static void
set_style(style,dash_len)203 set_style(style, dash_len)
204 int style;
205 double dash_len;
206 {
207
208 switch (style) {
209 case SOLID_LINE:
210 line_style = 0;
211 break;
212
213 case DASH_LINE:
214 line_style = 2;
215 break;
216
217 case DOTTED_LINE:
218 line_style = 1;
219 break;
220 }
221 }
222
223 /*
224 * putline
225 */
226 static void
putline(start_x,start_y,end_x,end_y)227 putline (start_x, start_y, end_x, end_y)
228 int start_x, start_y, end_x, end_y;
229 {
230
231 fprintf(tfp, "\\special{tyl line %c %d L %d %u %u; %u %u}\n",
232 measure, linethick,line_style,
233 convx((double)start_x), convy((double)start_y),
234 convx((double)end_x), convy((double)end_y));
235
236 }
237
238
239 void
gentextyl_spline(s)240 gentextyl_spline(s)
241 F_spline *s;
242 {
243 /* print any comments prefixed with "%" */
244 print_comments("% ",s->comments, "");
245
246 set_linewidth(s->thickness);
247 set_style(s->style, s->style_val);
248
249 if (int_spline(s))
250 gentextyl_itp_spline(s);
251 else
252 gentextyl_ctl_spline(s);
253
254 if (s->fill_style && (int)s->fill_style != DEFAULT)
255 fprintf(stderr, "Spline area fill not implemented\n");
256 }
257
258 void
gentextyl_ellipse(e)259 gentextyl_ellipse(e)
260 F_ellipse *e;
261 {
262 int sx, sy;
263 int radius;
264
265 /* print any comments prefixed with "%" */
266 print_comments("% ",e->comments, "");
267
268 fprintf(tfp, "%%\n%% Fig ELLIPSE\n%%\n");
269
270 set_linewidth(e->thickness);
271 set_style(e->style, e->style_val);
272
273 if (e->radiuses.x == e->radiuses.y) {
274 fprintf(tfp, "\\special{tyl arc %c %d L 0 %u @ %u,%u 0 360}\n",
275 measure,linethick,convx((double)e->radiuses.x),
276 convx((double)e->center.x),convy((double)e->center.y));
277 }
278 else {
279 if (e->radiuses.x > e->radiuses.y) {
280 sy = 100;
281 sx = ((float)e->radiuses.x/(float)e->radiuses.y) * 100.0;
282 radius = e->radiuses.y;
283 }
284 else {
285 sx = 100;
286 sy = ((float)e->radiuses.y/(float)e->radiuses.x) * 100.0;
287 radius = e->radiuses.x;
288 }
289 fprintf(tfp,
290 "\\special{tyl arc %c T %u %u 0 0 0 %d L 0 %u @ %u,%u 0 360}\n",
291 measure,sx,sy,linethick,convx((double)radius),
292 convx((double)e->center.x),convy((double)e->center.y));
293 if (e->fill_style && (int)e->fill_style != DEFAULT)
294 fprintf(stderr, "Ellipse area fill not implemented\n");
295 }
296 }
297
298 #define HT_OFFSET (0.2 / 72.0)
299
300 void
gentextyl_text(t)301 gentextyl_text(t)
302 F_text *t;
303 {
304 double x, y;
305
306 /* print any comments prefixed with "%" */
307 print_comments("% ",t->comments, "");
308
309 fprintf(tfp, "%%\n%% Fig TEXT object\n%%\n");
310
311 x = t->base_x;
312 y = t->base_y;
313
314 switch (t->type) {
315
316 case T_LEFT_JUSTIFIED:
317 case DEFAULT:
318 break;
319 default:
320 fprintf(stderr, "Warning: Text incorrectly positioned\n");
321 break;
322 }
323
324 fprintf(tfp,"\\special{tyl label %c 1 %u %u \"%s\"}\n",
325 measure,convx(x),convy(y),t->cstring);
326
327 }
328
329 void
gentextyl_arc(a)330 gentextyl_arc(a)
331 F_arc *a;
332 {
333 double x, y;
334 double cx, cy, sx, sy, ex, ey;
335 double dx1, dy1, dx2, dy2, r1, r2, th1, th2;
336
337 /* print any comments prefixed with "%" */
338 print_comments("% ",a->comments, "");
339
340 set_linewidth(a->thickness);
341 set_style(a->style, a->style_val);
342
343 cx = a->center.x; cy = a->center.y;
344 sx = a->point[0].x; sy = a->point[0].y;
345 ex = a->point[2].x; ey = a->point[2].y;
346
347 if ((a->type == T_OPEN_ARC) && (a->thickness != 0) && (a->back_arrow || a->for_arrow)) {
348 if (a->for_arrow) {
349 arc_tangent(cx, cy, ex, ey, !a->direction, &x, &y);
350 draw_arrow_head(x, y, ex, ey,
351 a->for_arrow->ht, a->for_arrow->wid);
352 }
353 if (a->back_arrow) {
354 arc_tangent(cx, cy, sx, sy, a->direction, &x, &y);
355 draw_arrow_head(x, y, sx, sy,
356 a->back_arrow->ht, a->back_arrow->wid);
357 }
358 }
359
360
361 cy = ury - a->center.y;
362 sy = ury - a->point[0].y;
363 ey = ury - a->point[2].y;
364
365 dx1 = sx - cx;
366 dy1 = sy - cy;
367 dx2 = ex - cx;
368 dy2 = ey - cy;
369
370 cy = a->center.y;
371 sy = a->point[0].y;
372 ey = a->point[2].y;
373
374 rtop(dx1, dy1, &r1, &th1);
375 rtop(dx2, dy2, &r2, &th2);
376
377 set_linewidth(a->thickness);
378
379 if (a->direction) { /* Counterclockwise */
380 fprintf(tfp,"\\special{tyl arc %c %d L 0 %u @ %u,%u %d %d}\n",
381 measure,linethick,convx(r1),convx(cx),convy(cy),
382 (int)(180/M_PI * th1), (int)(180/M_PI * th2));
383 }
384 else {
385 fprintf(tfp,"\\special{tyl arc %c %d L 0 %u @ %u,%u %d %d}\n",
386 measure,linethick,convx(r1),convx(cx),convy(cy),
387 (int)(180/M_PI * th2), (int)(180/M_PI * th1));
388 }
389
390 if (a->fill_style && (int)a->fill_style != DEFAULT)
391 fprintf(stderr, "Arc area fill not implemented\n");
392 }
393
394
395
396 /*
397 * rtop - rectangular to polar conversion
398 */
399 static void
rtop(x,y,r,th)400 rtop(x, y, r, th)
401 double x, y, *r, *th;
402 {
403 *r = sqrt(x*x+y*y);
404 *th = acos(x/(*r));
405
406 if (y < 0) *th = 2*M_PI - *th;
407 }
408
409 /* draw arrow heading from (x1, y1) to (x2, y2) */
410
411 static void
draw_arrow_head(x1,y1,x2,y2,arrowht,arrowwid)412 draw_arrow_head(x1, y1, x2, y2, arrowht, arrowwid)
413 double x1, y1, x2, y2;
414 double arrowht, arrowwid;
415 {
416 double x, y, xb, yb, dx, dy, l, sina, cosa;
417 double xc, yc, xd, yd;
418
419 dx = x2 - x1; dy = y1 - y2;
420 l = sqrt(dx*dx+dy*dy);
421 if (l == 0) {
422 return;
423 }
424 else {
425 sina = dy / l; cosa = dx / l;
426 }
427 xb = x2*cosa - y2*sina;
428 yb = x2*sina + y2*cosa;
429 x = xb - arrowht;
430 y = yb - arrowwid / 2;
431 xc = x*cosa + y*sina;
432 yc = -x*sina + y*cosa;
433 y = yb + arrowwid / 2;
434 xd = x*cosa + y*sina;
435 yd = -x*sina + y*cosa;
436
437 fprintf(tfp, "%%\n%% arrow head\n%%\n");
438
439 fprintf(tfp, "\\special{tyl line %c %d %u %u; %u %u}\n",measure,linethick,
440 convx(xc), convy(yc), convx(x2), convy(y2));
441 fprintf(tfp, "\\special{tyl line %c %d %u %u; %u %u}\n",measure,linethick,
442 convx(x2), convy(y2), convx(xd), convy(yd));
443
444 }
445
446 #define THRESHOLD (10.0)
447 double last_x, last_y;
448
449 static void
quadratic_spline(a1,b1,a2,b2,a3,b3,a4,b4)450 quadratic_spline(a1, b1, a2, b2, a3, b3, a4, b4)
451 double a1, b1, a2, b2, a3, b3, a4, b4;
452 {
453 double x1, y1, x4, y4;
454 double xmid, ymid;
455
456 x1 = a1; y1 = b1;
457 x4 = a4; y4 = b4;
458 xmid = (a2 + a3) / 2;
459 ymid = (b2 + b3) / 2;
460 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD) {
461 fprintf(tfp, "\\special{tyl line %c %d %u %u; %u %u}\n",
462 measure, linethick,convx(last_x),convy(last_y),
463 convx(xmid), convy(ymid));
464 last_x = xmid; last_y = ymid;
465 }
466
467 else {
468 quadratic_spline(x1, y1, ((x1+a2)/2), ((y1+b2)/2),
469 ((3*a2+a3)/4), ((3*b2+b3)/4), xmid, ymid);
470 }
471
472 if (fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
473 fprintf(tfp, "\\special{tyl line %c %d %u %u; %u %u}\n",
474 measure, linethick,convx(last_x),convy(last_y),convx(x4), convy(y4));
475 last_x = x4; last_y = y4;
476 }
477
478 else {
479 quadratic_spline(xmid, ymid, ((a2+3*a3)/4), ((b2+3*b3)/4),
480 ((a3+x4)/2), ((b3+y4)/2), x4, y4);
481 }
482 }
483
484 static void
gentextyl_ctl_spline(s)485 gentextyl_ctl_spline(s)
486 F_spline *s;
487 {
488 F_point *p;
489 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
490 double x1, y1, x2, y2;
491
492 fprintf(tfp, "%%\n%% Fig CONTROL PT SPLINE\n%%\n");
493
494 p = s->points;
495 x1 = p->x; y1 = p->y;
496 p = p->next;
497 x2 = p->x; y2 = p->y;
498 cx1 = (x1 + x2) / 2; cy1 = (y1 + y2) / 2;
499 cx2 = (x1 + 3 * x2) / 4; cy2 = (y1 + 3 * y2) / 4;
500
501 if (closed_spline(s)) {
502 fprintf(tfp, "%% closed spline\n%%\n");
503 last_x = cx1; last_y = cy1;
504 }
505 else {
506 fprintf(tfp, "%% open spline\n%%\n");
507 if (s->back_arrow)
508 draw_arrow_head(cx1, cy1, x1, y1,
509 s->back_arrow->ht, s->back_arrow->wid);
510 fprintf(tfp, "\\special{tyl line %c %d %u %u;%u %u}\n",
511 measure,linethick,
512 convx(x1),convy(y1),convx(cx1),convy(cy1));
513 last_x = cx1; last_y = cy1;
514 }
515
516 for (p = p->next; p != NULL; p = p->next) {
517 x1 = x2; y1 = y2;
518 x2 = p->x; y2 = p->y;
519 cx3 = (3 * x1 + x2) / 4; cy3 = (3 * y1 + y2) / 4;
520 cx4 = (x1 + x2) / 2; cy4 = (y1 + y2) / 2;
521 quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
522 cx1 = cx4; cy1 = cy4;
523 cx2 = (x1 + 3 * x2) / 4; cy2 = (y1 + 3 * y2) / 4;
524 }
525 x1 = x2; y1 = y2;
526 p = s->points->next;
527 x2 = p->x; y2 = p->y;
528 cx3 = (3 * x1 + x2) / 4; cy3 = (3 * y1 + y2) / 4;
529 cx4 = (x1 + x2) / 2; cy4 = (y1 + y2) / 2;
530 if (closed_spline(s)) {
531 quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
532 }
533 else {
534 fprintf(tfp,"\\special{tyl line %c %d %u %u;%u %u}\n",
535 measure,linethick,
536 convx(cx1),convy(cy1),convx(x1),convy(y1));
537 if (s->for_arrow)
538 draw_arrow_head(cx1, cy1, x1, y1,
539 s->for_arrow->ht, s->for_arrow->wid);
540 }
541
542 }
543
544 static void
gentextyl_itp_spline(s)545 gentextyl_itp_spline(s)
546 F_spline *s;
547 {
548 F_point *p1, *p2;
549 F_control *cp1, *cp2;
550 double x1, x2, y1, y2;
551
552
553 p1 = s->points;
554 cp1 = s->controls;
555 x2 = p1->x; y2 = p1->y;
556
557 if (s->back_arrow)
558 draw_arrow_head(cp1->rx, cp1->ry, x2, y2,
559 s->back_arrow->ht, s->back_arrow->wid);
560
561 last_x = x2; last_y = y2;
562
563 fprintf(tfp, "%%\n%% Fig INTERPOLATED SPLINE\n%%\n");
564 for (p2 = p1->next, cp2 = s->controls->next;
565 p2 != NULL;
566 cp1 = cp2, p2 = p2->next, cp2 = cp2->next) {
567 x1 = x2; y1 = y2; x2 = p2->x; y2 = p2->y;
568 bezier_spline(x1,y1,cp1->rx,cp1->ry,
569 cp2->lx,cp2->ly,x2,y2);
570 }
571
572 if (s->for_arrow)
573 draw_arrow_head(cp1->lx, cp1->ly, x2, y2,
574 s->for_arrow->ht, s->for_arrow->wid);
575 }
576
577 static void
bezier_spline(a0,b0,a1,b1,a2,b2,a3,b3)578 bezier_spline(a0, b0, a1, b1, a2, b2, a3, b3)
579 double a0, b0, a1, b1, a2, b2, a3, b3;
580 {
581 double x0, y0, x3, y3;
582 double sx1, sy1, sx2, sy2, tx, ty, tx1, ty1, tx2, ty2, xmid, ymid;
583
584 x0 = a0; y0 = b0;
585 x3 = a3; y3 = b3;
586 if (fabs(x0 - x3) < THRESHOLD && fabs(y0 - y3) < THRESHOLD) {
587 fprintf(tfp,"\\special{tyl line %c %d %u %u ; %u %u}\n",measure,linethick,
588 convx(last_x),convy(last_y),convx(x3),convy(y3));
589 last_x = x3; last_y = y3;
590 }
591
592 else {
593 tx = (a1 + a2) / 2; ty = (b1 + b2) / 2;
594 sx1 = (x0 + a1) / 2; sy1 = (y0 + b1) / 2;
595 sx2 = (sx1 + tx) / 2; sy2 = (sy1 + ty) / 2;
596 tx2 = (a2 + x3) / 2; ty2 = (b2 + y3) / 2;
597 tx1 = (tx2 + tx) / 2; ty1 = (ty2 + ty) / 2;
598 xmid = (sx2 + tx1) / 2; ymid = (sy2 + ty1) / 2;
599
600 bezier_spline(x0, y0, sx1, sy1, sx2, sy2, xmid, ymid);
601 bezier_spline(xmid, ymid, tx1, ty1, tx2, ty2, x3, y3);
602 }
603 }
604
605 struct driver dev_textyl = {
606 gentextyl_option,
607 gentextyl_start,
608 gendev_null,
609 gentextyl_arc,
610 gentextyl_ellipse,
611 gentextyl_line,
612 gentextyl_spline,
613 gentextyl_text,
614 gentextyl_end,
615 EXCLUDE_TEXT
616 };
617
618