1 /*
2 * TransFig: Facility for Translating Fig code
3 * Copyright (c) 1998 by Mike Markowski
4 * Copyright (c) 1991 by Micah Beck
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 * genptk : Perl/Tk driver for fig2dev
21 *
22 * Author: Slaven Rezic (rezic@onlineoffice.de) 8/2000
23 * based on code by Mike Markowski (mm@udel.edu), U of Delaware, 4/98
24 */
25
26 #include "fig2dev.h"
27 #include "object.h"
28 #include "readxbm.h"
29
30 #define X(x) ((double)(x)/ppi)
31 #define Y(y) ((double)(y)/ppi)
32
33 #define NONE (0xffffff + 1)
34
35 static void
36 drawBitmap(F_line *),
37 drawShape(void (*)(), void *, int, int, int, int),
38 niceLine(char *),
39 ptkArc(void *, unsigned int, unsigned int, unsigned int, int),
40 ptkEllipse(void *, unsigned int, unsigned int, unsigned int, int),
41 ptkLine(void *, unsigned int, unsigned int, unsigned int, int),
42 ptkPolygon(void *, unsigned int, unsigned int, unsigned int, int);
43
44 static unsigned int
45 rgbColorVal(int);
46
47 static char *
48 stippleFilename(int);
49
50 static char *canvas = "$c";
51 static char *xbmPathVar = "$xbmPath";
52 static char *xbmPathName = BITMAPDIR;
53
54 static char pngRequired = 0;
55 static char jpegRequired = 0;
56 static char tiffRequired = 0;
57
58 #define TOP 8.5 /* inches */
59 static int full_page = False;
60
61 /*
62 * g e n p T k O p t i o n ( )
63 */
64
65 void
genptk_option(opt,optarg)66 genptk_option(opt, optarg)
67 char opt, *optarg;
68 {
69 switch (opt) {
70 case 'l': /* landscape mode */
71 landscape = True; /* override the figure file setting */
72 orientspec = True; /* user-specified */
73 break;
74
75 case 'p': /* portrait mode */
76 landscape = False; /* override the figure file setting */
77 orientspec = True; /* user-specified */
78 break;
79
80 case 'P': /* use full page instead of bounding box */
81 full_page = True;
82 break;
83
84 case 'z': /* papersize */
85 (void) strcpy (papersize, optarg);
86 paperspec = True; /* user-specified */
87 break;
88
89 case 'f': /* ignore magnification, font sizes and lang here */
90 case 'm':
91 case 's':
92 case 'L':
93 break;
94
95 default:
96 put_msg(Err_badarg, opt, "tk");
97 exit(1);
98 }
99
100 }
101
102 /*
103 * g e n p T k S t a r t ( )
104 *
105 * Any initialization garbage is taken care of here.
106 */
107
108 void
genptk_start(F_compound * objects)109 genptk_start(F_compound *objects)
110 {
111 char stfp[1024];
112 float wid, ht, swap;
113 struct paperdef *pd;
114
115 ppi = ppi / mag;
116
117 /* print any whole-figure comments prefixed with "#" */
118 if (objects->comments) {
119 fprintf(tfp,"#\n");
120 print_comments("# ",objects->comments, "");
121 fprintf(tfp,"#\n");
122 }
123
124 if ( !full_page ) {
125 /* get width and height in fig units */
126 wid = urx - llx;
127 ht = ury - lly;
128
129 /* add 1% border around */
130 llx -= round(wid/100.0);
131 lly -= round(ht/100.0);
132 urx += round(wid/100.0);
133 ury += round(ht/100.0);
134
135 /* recalculate new width and height in inches */
136 wid = 1.0*(urx - llx)/ppi;
137 ht = 1.0*(ury - lly)/ppi;
138
139 } else {
140 /* full page, get the papersize as the width and height for the canvas */
141 for (pd = paperdef; pd->name != NULL; pd++)
142 if (strcasecmp (papersize, pd->name) == 0) {
143 /* width/height are in dpi, convert to inches */
144 wid = pd->width/80.0;
145 ht = pd->height/80.0;
146 strcpy(papersize,pd->name); /* use the "nice" form */
147 break;
148 }
149
150 if (wid < 0 || ht < 0) {
151 (void) fprintf (stderr, "Unknown paper size `%s'\n", papersize);
152 exit (1);
153 }
154
155 sprintf(stfp, "# Page size specified: %s\n",papersize);
156 niceLine(stfp);
157
158 /* swap for landscape */
159 if ( landscape) {
160 sprintf(stfp, "# Landscape orientation\n");
161 niceLine(stfp);
162 swap = wid;
163 wid = ht;
164 ht = swap;
165 } else {
166 sprintf(stfp, "# Portrait orientation\n");
167 niceLine(stfp);
168 }
169 }
170
171 sprintf(stfp, "sub {\n");
172 niceLine(stfp);
173 sprintf(stfp, "my $top = shift;\n");
174 niceLine(stfp);
175 sprintf(stfp, "my %%img;\n");
176 niceLine(stfp);
177 sprintf(stfp, "my $c = $top->Canvas(qw/-width %.2fi -height %.2fi -bg ivory/);\n", wid, ht);
178 niceLine(stfp);
179 sprintf(stfp, "#$c->configure(qw/-xscrollincrement 1p -yscrollincrement 1p/);\n");
180 niceLine(stfp);
181 if ( !full_page ) {
182 sprintf(stfp, "$c->configure(-scrollregion => ['%.2fi','%.2fi','%.2fi','%.2fi']);\n",
183 MIN(X(urx),X(llx)), MIN(Y(ury),Y(lly)),MAX(X(urx),X(llx)), MAX(Y(ury),Y(lly)));
184 niceLine(stfp);
185 sprintf(stfp, "# Shift canvas by lower of bounding box\n");
186 niceLine(stfp);
187 sprintf(stfp, "#$c->xview(qw/scroll %d u/);\n",round(llx/16.45*mag));
188 niceLine(stfp);
189 sprintf(stfp, "#$c->yview(qw/scroll %d u/);\n",round(lly/16.45*mag));
190 niceLine(stfp);
191 }
192
193 sprintf(stfp, "$c->pack(-expand => 1, -fill => 'both');\n");
194 niceLine(stfp);
195 sprintf(stfp, "# If your fill-pattern bitmaps will be elsewhere,\n");
196 niceLine(stfp);
197 sprintf(stfp, "# change the next line appropriately, and all will\n");
198 niceLine(stfp);
199 sprintf(stfp, "# work well without further modification.\n\n");
200 niceLine(stfp);
201 sprintf(stfp, "my %s = '%s';\n\n", xbmPathVar, xbmPathName);
202 niceLine(stfp);
203 sprintf(stfp, "# The xfig objects begin here.\n");
204 niceLine(stfp);
205 }
206
207 /*
208 * g e n p T k E n d ( )
209 *
210 * Last call!...
211 */
212
213 int
genptk_end()214 genptk_end()
215 {
216 char stfp[64];
217
218 sprintf(stfp, "%s->focus;\n", canvas);
219 sprintf(stfp, "\n}\n");
220 niceLine(stfp);
221
222 /* all ok */
223 return 0;
224 }
225
226 /*
227 * g e n p T k A r c ( )
228 *
229 * The Fig arc is one of the few objects that is only a subset of its
230 * equivalent Tk canvas object, since a Tk arc can be oval. But that
231 * has no bearing on the code written here, so this is a pretty
232 * useless comment...
233 */
234
235 void
genptk_arc(F_arc * a)236 genptk_arc(F_arc *a)
237 {
238 /* print any comments prefixed with "#" */
239 print_comments("# ",a->comments, "");
240
241 if (a->style > 0)
242 fprintf(stderr, "genptk_arc: only solid lines are supported by Tk.\n");
243 if (a->type == T_OPEN_ARC && (a->for_arrow || a->back_arrow))
244 fprintf(stderr, "genptk_arc: arc arrows not supported by Tk.\n");
245 drawShape(ptkArc, (void *) a, a->thickness,
246 a->pen_color, a->fill_color, a->fill_style);
247 }
248
249 /*
250 * g e n p T k E l l i p s e ( )
251 */
252
253 void
genptk_ellipse(F_ellipse * e)254 genptk_ellipse(F_ellipse *e)
255 {
256 /* print any comments prefixed with "#" */
257 print_comments("# ",e->comments, "");
258
259 switch (e->type) {
260 case T_CIRCLE_BY_DIA:
261 case T_CIRCLE_BY_RAD:
262 case T_ELLIPSE_BY_DIA:
263 case T_ELLIPSE_BY_RAD:
264 if (e->style > 0)
265 fprintf(stderr, "genptk_ellipse: only solid lines "
266 "supported.\n");
267 drawShape(ptkEllipse, (void *) e, e->thickness,
268 e->pen_color, e->fill_color, e->fill_style);
269 break;
270 default:
271 /* Stole this line from Netscape 3.03... */
272 fprintf(stderr, "genptk_ellipse: Whatchew talkin' 'bout, "
273 "Willis?\n");
274 return;
275 break;
276 }
277 }
278
279 /*
280 * g e n p T k L i n e ( )
281 */
282
283 void
genptk_line(F_line * l)284 genptk_line(F_line *l)
285 {
286 /* print any comments prefixed with "#" */
287 print_comments("# ",l->comments, "");
288
289 switch (l->type) {
290 case T_ARC_BOX: /* Fall through to T_BOX... */
291 fprintf(stderr, "genptk_line: arc box not supported.\n");
292 case T_BOX:
293 case T_POLYLINE:
294 /* Take care of filled regions first. */
295 drawShape(ptkPolygon, (void *) l->points, 0,
296 l->pen_color, l->fill_color, l->fill_style);
297 /* Now draw line itself. */
298 drawShape(ptkLine, (void *) l, l->thickness, l->pen_color,
299 NONE, UNFILLED);
300 break;
301 case T_PIC_BOX:
302 drawBitmap(l);
303 break;
304 case T_POLYGON:
305 if (l->style > 0) {
306 fprintf(stderr, "genptk_line: only solid line "
307 "styles supported.\n");
308 }
309 drawShape(ptkPolygon, (void *) l->points, l->thickness,
310 l->pen_color, l->fill_color, l->fill_style);
311 break;
312 default:
313 fprintf(stderr, "genptk_line: Whatchew talkin' 'bout, Willis?\n");
314 break;
315 }
316 }
317
318 /*
319 * d r a w B i t m a p ( )
320 */
321
322 #define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
323
324 static void
drawBitmap(F_line * l)325 drawBitmap(F_line *l)
326 {
327 char stfp[1024];
328 double dx, dy;
329 F_pic *p;
330 unsigned char buf[16];
331 FILE *fd;
332 int filtype; /* file (0) or pipe (1) */
333 int stat;
334 FILE *open_picfile();
335 void close_picfile();
336 char xname[PATH_MAX];
337 char isphoto;
338
339 p = l->pic;
340
341 dx = l->points->next->next->x - l->points->x;
342 dy = l->points->next->next->y - l->points->y;
343 if (!(dx >= 0. && dy >= 0.))
344 fprintf(stderr, "drawBitmap: rotated bitmaps not supprted"
345 " by Tk.\n");
346
347 /* see if supported image format first */
348
349 if ((fd=open_picfile(p->file, &filtype, True, xname)) == NULL) {
350 fprintf(stderr,"drawBitmap: can't open bitmap file %s\n",p->file);
351 return;
352 }
353
354 /* read header */
355
356 stat = ReadOK(fd,buf,6);
357 close_picfile(fd,filtype);
358 if (!stat) {
359 fprintf(stderr,"drawBitmap: Bitmap file %s too short\n",p->file);
360 return;
361 }
362
363 isphoto = 0;
364 if ((strncmp((char *) buf,"GIF",3) == 0) ||
365 (*buf == 'P' && (*(buf+1) == '5' || *(buf+1) == '6')) /* PPM/PGM */ ||
366 (strncmp((char *) buf,"BM",2) == 0) /* Windows BMP */ ||
367 (strncmp((char *) buf,"/* XPM */",9) == 0) /* X11 Pixmap */ ) {
368 isphoto = 1;
369 } else if (strncmp((char *) buf+1,"PNG",3) == 0) {
370 isphoto = 1;
371 if (!pngRequired) {
372 sprintf(stfp, "require Tk::PNG;\n");
373 niceLine(stfp);
374 pngRequired++;
375 }
376 } else if (strncmp((char *) buf, "\377\330\377\340", 4) == 0) /* JPEG */ {
377 isphoto = 1;
378 if (!jpegRequired) {
379 sprintf(stfp, "require Tk::JPEG;\n");
380 niceLine(stfp);
381 jpegRequired++;
382 }
383 } else if ((strncmp((char *) buf,"MM\x00\x2a",4) == 0) /* TIFF BE */ ||
384 (strncmp((char *) buf,"II\x2a\x00",4) == 0) /* TIFF LE */ ) {
385 isphoto = 1;
386 if (!tiffRequired) {
387 sprintf(stfp, "require Tk::TIFF;\n");
388 niceLine(stfp);
389 tiffRequired++;
390 }
391 }
392
393 if (isphoto) {
394 /* GIF/PNG/TIFF/JPEG/PPM allright, create the image command */
395 /* first make a name without the .gif part */
396 char pname[PATH_MAX], *dot;
397 strcpy(pname,p->file);
398 if ((dot=strchr(pname,'.')))
399 *dot='\0';
400 /* image create */
401 sprintf(stfp, "$img{\"%s\"} = $top->Photo(-file => \"%s\");\n",pname, p->file);
402 niceLine(stfp);
403 /* now the canvas image */
404 sprintf(stfp, "%s->createImage(qw/%fi %fi -anchor nw -image/, $img{\"%s\"});",
405 canvas, X(l->points->x), Y(l->points->y), pname);
406 niceLine(stfp);
407 } else {
408 /* Try for an X Bitmap file format. */
409 rewind(fd);
410 if (ReadFromBitmapFile(fd, &dx, &dy, &p->bitmap)) {
411 sprintf(stfp, "%s->createBitmap(qw/%fi %fi -anchor nw",
412 canvas, X(l->points->x), Y(l->points->y));
413 niceLine(stfp);
414 sprintf(stfp, " -bitmap/, \"@%s\"", p->file);
415 niceLine(stfp);
416 if (l->pen_color != BLACK_COLOR && l->pen_color != DEFAULT) {
417 sprintf(stfp, ", -foreground => '#%6.6x'",
418 rgbColorVal(l->pen_color));
419 niceLine(stfp);
420 }
421 niceLine(stfp);
422 if (l->fill_color != UNFILLED) {
423 sprintf(stfp, ", -background => '#%6.6x'",
424 rgbColorVal(l->fill_color));
425 niceLine(stfp);
426 }
427 sprintf(stfp, ");\n");
428 niceLine(stfp);
429 } else
430 fprintf(stderr, "Only X bitmap, TIFF, JPEG, PPM and GIF picture objects "
431 "are supported in Tk canvases.\n");
432 }
433 }
434
435 /*
436 * g e n p T k T e x t ( )
437 */
438
439 /* define the latex fonts in terms of the postscript fonts */
440 #define latexFontDefault 0
441 #define latexFontRoman 1
442 #define latexFontBold 3
443 #define latexFontItalic 2
444 #define latexFontSansSerif 17
445 #define latexFontTypewriter 13
446
447 void
genptk_text(F_text * t)448 genptk_text(F_text * t)
449 {
450 char stfp[2048];
451 int i, j;
452
453 /* I'm sure I'm just too dense to have seen a better way of doing this... */
454 static struct {
455 char *prefix,
456 *suffix;
457 } fontNames[36] = {
458 {"-adobe-times-medium-r-normal--",
459 "-0-0-0-p-0-iso8859-1"},
460 {"-adobe-times-medium-r-normal--",
461 "-0-0-0-p-0-iso8859-1"},
462 {"-adobe-times-medium-i-normal--",
463 "-0-0-0-p-0-iso8859-1"},
464 {"-adobe-times-bold-r-normal--",
465 "-0-0-0-p-0-iso8859-1"},
466 {"-adobe-times-bold-i-normal--",
467 "-0-0-0-p-0-iso8859-1"},
468 {"-urw-itc avant garde-medium-r-normal-sans-",
469 "-0-0-0-p-0-iso8859-1"},
470 {"-urw-itc avant garde-medium-o-normal-sans-",
471 "-0-0-0-p-0-iso8859-1"},
472 {"-urw-itc avant garde-demi-r-normal-sans-",
473 "-0-0-0-p-0-iso8859-1"},
474 {"-urw-itc avant garde-demi-o-normal-sans-",
475 "-0-0-0-p-0-iso8859-1"},
476 {"-urw-itc bookman-light-r-normal--",
477 "-0-0-0-p-0-iso8859-1"},
478 {"-urw-itc bookman-light-i-normal--",
479 "-0-0-0-p-0-iso8859-1"},
480 {"-urw-itc bookman-demi-r-normal--",
481 "-0-0-0-p-0-iso8859-1"},
482 {"-urw-itc bookman-demi-i-normal--",
483 "-0-0-0-p-0-iso8859-1"},
484 {"-adobe-courier-medium-r-normal--",
485 "-0-0-0-m-0-iso8859-1"},
486 {"-adobe-courier-medium-o-normal--",
487 "-0-0-0-m-0-iso8859-1"},
488 {"-adobe-courier-bold-r-normal--",
489 "-0-0-0-m-0-iso8859-1"},
490 {"-adobe-courier-bold-o-normal--",
491 "-0-0-0-m-0-iso8859-1"},
492 {"-adobe-helvetica-medium-r-normal--",
493 "-0-0-0-p-0-iso8859-1"},
494 {"-adobe-helvetica-medium-o-normal--",
495 "-0-0-0-p-0-iso8859-1"},
496 {"-adobe-helvetica-bold-r-normal--",
497 "-0-0-0-p-0-iso8859-1"},
498 {"-adobe-helvetica-bold-o-normal--",
499 "-0-0-0-p-0-iso8859-1"},
500 {"-adobe-helvetica-medium-r-narrow--",
501 "-0-0-0-p-0-iso8859-1"},
502 {"-adobe-helvetica-medium-o-narrow--",
503 "-0-0-0-p-0-iso8859-1"},
504 {"-adobe-helvetica-bold-r-narrow--",
505 "-0-0-0-p-0-iso8859-1"},
506 {"-adobe-helvetica-bold-o-narrow--",
507 "-0-0-0-p-0-iso8859-1"},
508 {"-adobe-new century schoolbook-medium-r-normal--",
509 "-0-0-0-p-0-iso8859-1"},
510 {"-adobe-new century schoolbook-medium-i-normal--",
511 "-0-0-0-p-0-iso8859-1"},
512 {"-adobe-new century schoolbook-bold-r-normal--",
513 "-0-0-0-p-0-iso8859-1"},
514 {"-adobe-new century schoolbook-bold-i-normal--",
515 "-0-0-0-p-0-iso8859-1"},
516 {"-adobe-palatino-medium-r-normal--",
517 "-0-0-0-p-0-iso8859-1"},
518 {"-adobe-palatino-medium-i-normal--",
519 "-0-0-0-p-0-iso8859-1"},
520 {"-adobe-palatino-bold-r-normal--",
521 "-0-0-0-p-0-iso8859-1"},
522 {"-adobe-palatino-medium-i-normal--",
523 "-0-0-0-p-0-iso8859-1"},
524 {"--symbol-medium-r-normal--",
525 "-0-0-0-p-0-*-*"},
526 {"-*-itc zapf chancery-medium-i-normal--",
527 "-0-0-0-p-0-iso8859-1"},
528 {"-*-itc zapf dingbats-medium-r-normal--",
529 "-0-0-0-p-0-*-*"}
530 };
531
532 /* print any comments prefixed with "#" */
533 print_comments("# ",t->comments, "");
534
535 if (t->angle != 0.)
536 fprintf(stderr, "genptk_text: rotated text not "
537 "supported by Tk.\n");
538
539 sprintf(stfp, "%s->createText(qw/%fi %fi", canvas, X(t->base_x),
540 Y(t->base_y));
541 niceLine(stfp);
542 strcpy(stfp, " -text/, '");
543 j = strlen(stfp);
544 for (i = 0; i < strlen(t->cstring); i++) {
545 if (t->cstring[i] == '\'')
546 stfp[j++] = '\\';
547 stfp[j++] = t->cstring[i];
548 }
549 stfp[j++] = '\'';
550 stfp[j++] = ',';
551 stfp[j++] = '\0'; /* XXX ja? */
552 niceLine(stfp);
553 switch (t->type) {
554 case T_LEFT_JUSTIFIED:
555 case DEFAULT:
556 sprintf(stfp, ", -anchor => 'sw'");
557 break;
558 case T_CENTER_JUSTIFIED:
559 /* The Tk default. */
560 sprintf(stfp, ", -anchor => 's'");
561 break;
562 case T_RIGHT_JUSTIFIED:
563 sprintf(stfp, ", -anchor => 'se'");
564 break;
565 default:
566 fprintf(stderr, "genptk_text: Unknown text justification\n");
567 t->type = T_LEFT_JUSTIFIED;
568 break;
569 }
570 niceLine(stfp);
571
572 if (psfont_text(t)) {
573 sprintf(stfp, ", -font => \"%s%d%s\"", fontNames[t->font+1].prefix,
574 (int) t->size, fontNames[t->font+1].suffix);
575 niceLine(stfp);
576 } else { /* Rigid, special, and LaTeX fonts. */
577 int fnum;
578
579 switch (t->font) {
580 case 0: /* Default font. */
581 fnum = latexFontDefault;
582 break;
583 case 1: /* Roman. */
584 fnum = latexFontRoman;
585 break;
586 case 2: /* Bold. */
587 fnum = latexFontBold;
588 break;
589 case 3: /* Italic. */
590 fnum = latexFontItalic;
591 break;
592 case 4: /* Sans Serif. */
593 fnum = latexFontSansSerif;
594 break;
595 case 5: /* Typewriter. */
596 fnum = latexFontTypewriter;
597 break;
598 default:
599 fnum = latexFontDefault;
600 fprintf(stderr, "genptk_text: unknown LaTeX font.\n");
601 break;
602 }
603 sprintf(stfp, ", -font => \"%s%d%s\"", fontNames[fnum].prefix,
604 (int) t->size, fontNames[fnum].suffix);
605 niceLine(stfp);
606 }
607 if (t->color != BLACK_COLOR && t->color != DEFAULT) {
608 sprintf(stfp, ", -fill => '#%6.6x'", rgbColorVal(t->color));
609 niceLine(stfp);
610 }
611 sprintf(stfp, ");\n");
612 niceLine(stfp);
613 }
614
615 /*
616 * b e z i e r S p l i n e ( )
617 *
618 * We could use the "-smooth" option of Tk's "line" canvas object to
619 * get a Bezier spline. But just to be sure everything is identical,
620 * we'll do it ourselves. All spline routines were blatantly swiped
621 * from genibmgl.c with only non-mathematical mods.
622 */
623
624 #define THRESHOLD .05 /* inch */
625
626 static void
bezierSpline(double a0,double b0,double a1,double b1,double a2,double b2,double a3,double b3)627 bezierSpline(double a0, double b0, double a1, double b1, double a2, double b2,
628 double a3, double b3)
629 {
630 char stfp[64];
631 double x0, y0, x3, y3;
632 double sx1, sy1, sx2, sy2, tx, ty, tx1, ty1, tx2, ty2, xmid, ymid;
633
634 x0 = a0; y0 = b0;
635 x3 = a3; y3 = b3;
636 if (fabs(x0 - x3) < THRESHOLD && fabs(y0 - y3) < THRESHOLD) {
637 sprintf(stfp, ", '%.4fi', '%.4fi'", x3, y3);
638 niceLine(stfp);
639 } else {
640 tx = (a1 + a2 )/2.0; ty = (b1 + b2 )/2.0;
641 sx1 = (x0 + a1 )/2.0; sy1 = (y0 + b1 )/2.0;
642 sx2 = (sx1 + tx )/2.0; sy2 = (sy1 + ty )/2.0;
643 tx2 = (a2 + x3 )/2.0; ty2 = (b2 + y3 )/2.0;
644 tx1 = (tx2 + tx )/2.0; ty1 = (ty2 + ty )/2.0;
645 xmid = (sx2 + tx1)/2.0; ymid = (sy2 + ty1)/2.0;
646
647 bezierSpline(x0, y0, sx1, sy1, sx2, sy2, xmid, ymid);
648 bezierSpline(xmid, ymid, tx1, ty1, tx2, ty2, x3, y3);
649 }
650 }
651
652 /*
653 * g e n p T k I t p S p l i n e ( )
654 */
655
656 static void
genptk_itpSpline(F_spline * s)657 genptk_itpSpline(F_spline *s)
658 {
659 char dir[8], stfp[1024];
660 F_arrow *a;
661 F_point *p1, *p2;
662 F_control *cp1, *cp2;
663 double x1, x2, y1, y2;
664
665 p1 = s->points;
666 cp1 = s->controls;
667 x2 = p1->x/ppi; y2 = p1->y/ppi;
668
669 sprintf(stfp, "%s->createLine(qw/%.4fi %.4fi/", canvas, x2, y2);
670 niceLine(stfp);
671 for (p2 = p1->next, cp2 = cp1->next; p2 != NULL;
672 p1 = p2, cp1 = cp2, p2 = p2->next, cp2 = cp2->next) {
673
674 x1 = x2;
675 y1 = y2;
676 x2 = p2->x/ppi;
677 y2 = p2->y/ppi;
678 bezierSpline(x1, y1, (double)cp1->rx/ppi, cp1->ry/ppi,
679 (double)cp2->lx/ppi, cp2->ly/ppi, x2, y2);
680 }
681
682 a = NULL;
683 if (s->for_arrow && !s->back_arrow) {
684 a = s->for_arrow;
685 strcpy(dir, "last");
686 } else if (!s->for_arrow && s->back_arrow) {
687 a = s->back_arrow;
688 strcpy(dir, "first");
689 } else if (s->for_arrow && s->back_arrow) {
690 a = s->back_arrow;
691 strcpy(dir, "both");
692 }
693 if (a)
694 switch (a->type) {
695 case 0: /* Stick type. */
696 sprintf(stfp, ", -arrow => '%s', -arrowshape => [0, '%fi', '%fi']",
697 dir, X(a->ht), X(a->wid)/2.);
698 niceLine(stfp);
699 fprintf(stderr, "Warning: stick arrows do not "
700 "work well in Tk.\n");
701 break;
702 case 1: /* Closed triangle. */
703 sprintf(stfp, " -arrow => '%s', -arrowshape => ['%fi', '%fi', '%fi']",
704 dir, X(a->ht), X(a->ht), X(a->wid)/2.);
705 niceLine(stfp);
706 break;
707 case 2: /* Closed with indented butt. */
708 sprintf(stfp, " -arrow => '%s', -arrowshape => ['%fi', '%fi', '%fi']",
709 dir, 0.8 * X(a->ht), X(a->ht), X(a->wid)/2.);
710 niceLine(stfp);
711 break;
712 case 3: /* Closed with pointed butt. */
713 sprintf(stfp, " -arrow => '%s', -arrowshape => ['%fi', '%fi', '%fi']",
714 dir, 1.2 * X(a->ht), X(a->ht), X(a->wid)/2.);
715 niceLine(stfp);
716 break;
717 default:
718 fprintf(stderr, "tkLine: unknown arrow type.\n");
719 break;
720 }
721
722 switch (s->cap_style) {
723 case 0: /* Butt (Tk default). */
724 break;
725 case 1: /* Round. */
726 sprintf(stfp, ", -capstyle => 'round'");
727 niceLine(stfp);
728 break;
729 case 2: /* Projecting. */
730 sprintf(stfp, ", -capstyle => 'projecting'");
731 niceLine(stfp);
732 break;
733 default:
734 fprintf(stderr, "tkLine: unknown cap style.\n");
735 break;
736 }
737
738 if (s->thickness != 1) {
739 sprintf(stfp, ", -width => '%d'", s->thickness);
740 niceLine(stfp);
741 }
742 if (s->pen_color != BLACK_COLOR && s->pen_color != DEFAULT) {
743 sprintf(stfp, ", -fill => '#%6.6x'", s->pen_color);
744 niceLine(stfp);
745 }
746 sprintf(stfp, ");\n");
747 niceLine(stfp);
748 }
749
750 /*
751 * q u a d r a t i c S p l i n e ( )
752 */
753
754 static void
quadraticSpline(double a1,double b1,double a2,double b2,double a3,double b3,double a4,double b4)755 quadraticSpline(double a1, double b1, double a2, double b2, double a3,
756 double b3, double a4, double b4)
757 {
758 char stfp[64];
759 double x1, y1, x4, y4;
760 double xmid, ymid;
761
762 x1 = a1; y1 = b1;
763 x4 = a4; y4 = b4;
764 xmid = (a2 + a3)/2.0;
765 ymid = (b2 + b3)/2.0;
766 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD) {
767 sprintf(stfp, "'%.4fi', '%.4fi',\n", xmid, ymid);
768 niceLine(stfp);
769 } else {
770 quadraticSpline(x1, y1, ((x1+a2)/2.0), ((y1+b2)/2.0),
771 ((3.0*a2+a3)/4.0), ((3.0*b2+b3)/4.0), xmid, ymid);
772 }
773
774 if (fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
775 sprintf(stfp, "'%.4fi', '%.4fi', ", x4, y4);
776 niceLine(stfp);
777 } else {
778 quadraticSpline(xmid, ymid, ((a2+3.0*a3)/4.0),
779 ((b2+3.0*b3)/4.0), ((a3+x4)/2.0), ((b3+y4)/2.0),
780 x4, y4);
781 }
782 }
783
784 /*
785 * g e n p T k C t l S p l i n e ( )
786 */
787
788 static void
genptk_ctlSpline(F_spline * s)789 genptk_ctlSpline(F_spline *s)
790 {
791 char dir[8], stfp[1024];
792 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
793 double x1, y1, x2, y2;
794 F_arrow *a;
795 F_point *p;
796
797 p = s->points;
798 x1 = p->x/ppi;
799 y1 = p->y/ppi;
800 p = p->next;
801 x2 = p->x/ppi;
802 y2 = p->y/ppi;
803 cx1 = (x1 + x2)/2.0;
804 cy1 = (y1 + y2)/2.0;
805 cx2 = (x1 + 3.0*x2)/4.0;
806 cy2 = (y1 + 3.0*y2)/4.0;
807
808 if (closed_spline(s)) {
809 sprintf(stfp, "%s->createPolygon(qw/%.4f %.4f/,", canvas, cx1, cy1);
810 niceLine(stfp);
811 } else {
812 sprintf(stfp, "%s->createLine(", canvas);
813 niceLine(stfp);
814 }
815
816 for (p = p->next; p != NULL; p = p->next) {
817 x1 = x2;
818 y1 = y2;
819 x2 = p->x/ppi;
820 y2 = p->y/ppi;
821 cx3 = (3.0*x1 + x2)/4.0;
822 cy3 = (3.0*y1 + y2)/4.0;
823 cx4 = (x1 + x2)/2.0;
824 cy4 = (y1 + y2)/2.0;
825 quadraticSpline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
826 cx1 = cx4;
827 cy1 = cy4;
828 cx2 = (x1 + 3.0*x2)/4.0;
829 cy2 = (y1 + 3.0*y2)/4.0;
830 }
831 x1 = x2;
832 y1 = y2;
833 p = s->points->next;
834 x2 = p->x/ppi;
835 y2 = p->y/ppi;
836 cx3 = (3.0*x1 + x2)/4.0;
837 cy3 = (3.0*y1 + y2)/4.0;
838 cx4 = (x1 + x2)/2.0;
839 cy4 = (y1 + y2)/2.0;
840 if (closed_spline(s))
841 quadraticSpline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
842
843 if (closed_spline(s)) {
844 if (s->pen_color == NONE) {
845 sprintf(stfp, " -outline => undef,");
846 niceLine(stfp);
847 } else {
848 sprintf(stfp, " -outline => '#%6.6x',", s->pen_color);
849 niceLine(stfp);
850 }
851 if (s->fill_color == NONE) {
852 sprintf(stfp, " -fill => undef,");
853 niceLine(stfp);
854 } else {
855 sprintf(stfp, " -fill => '#%6.6x',", s->fill_color);
856 niceLine(stfp);
857 }
858 if (s->fill_style != NONE) {
859 sprintf(stfp, " -stipple => \"\\@%s\",",
860 stippleFilename(s->fill_style));
861 niceLine(stfp);
862 }
863 if (s->thickness != 1) {
864 sprintf(stfp, " -width => '%d'", s->thickness);
865 niceLine(stfp);
866 }
867 } else {
868
869 a = NULL;
870 if (s->for_arrow && !s->back_arrow) {
871 a = s->for_arrow;
872 strcpy(dir, "last");
873 } else if (!s->for_arrow && s->back_arrow) {
874 a = s->back_arrow;
875 strcpy(dir, "first");
876 } else if (s->for_arrow && s->back_arrow) {
877 a = s->back_arrow;
878 strcpy(dir, "both");
879 }
880 if (a)
881 switch (a->type) {
882 case 0: /* Stick type. */
883 sprintf(stfp, " -arrow => '%s', -arrowshape =>"
884 "[0, '%fi', '%fi'],",
885 dir, X(a->ht), X(a->wid)/2.);
886 niceLine(stfp);
887 fprintf(stderr, "Warning: stick arrows do not "
888 "work well in Tk.\n");
889 break;
890 case 1: /* Closed triangle. */
891 sprintf(stfp, " -arrow => '%s', -arrowshape =>"
892 "['%fi', '%fi', '%fi']",
893 dir, X(a->ht), X(a->ht), X(a->wid)/2.);
894 niceLine(stfp);
895 break;
896 case 2: /* Closed with indented butt. */
897 sprintf(stfp, " -arrow => '%s', -arrowshape =>"
898 "['%fi', '%fi', '%fi']", dir, 0.8 * X(a->ht),
899 X(a->ht), X(a->wid)/2.);
900 niceLine(stfp);
901 break;
902 case 3: /* Closed with pointed butt. */
903 sprintf(stfp, " -arrow => %s, -arrowshape =>"
904 "['%fi', '%fi', '%fi']", dir, 1.2 * X(a->ht),
905 X(a->ht), X(a->wid)/2.);
906 niceLine(stfp);
907 break;
908 default:
909 fprintf(stderr, "tkLine: unknown arrow "
910 "type.\n");
911 break;
912 }
913
914 switch (s->cap_style) {
915 case 0: /* Butt (Tk default). */
916 break;
917 case 1: /* Round. */
918 sprintf(stfp, " -capstyle => 'round',");
919 niceLine(stfp);
920 break;
921 case 2: /* Projecting. */
922 sprintf(stfp, " -capstyle => 'projecting',");
923 niceLine(stfp);
924 break;
925 default:
926 fprintf(stderr, "tkLine: unknown cap style.\n");
927 break;
928 }
929
930 if (s->thickness != 1) {
931 sprintf(stfp, " -width => '%d',", s->thickness);
932 niceLine(stfp);
933 }
934 if (s->pen_color != BLACK_COLOR && s->pen_color != DEFAULT) {
935 sprintf(stfp, " -fill => '#%6.6x',", s->pen_color);
936 niceLine(stfp);
937 }
938 }
939 sprintf(stfp, ");\n");
940 }
941
942 /*
943 * g e n p T k S p l i n e ( )
944 */
945
946 void
genptk_spline(F_spline * s)947 genptk_spline(F_spline *s)
948 {
949 /* print any comments prefixed with "#" */
950 print_comments("# ",s->comments, "");
951
952 if (int_spline(s))
953 genptk_itpSpline(s);
954 else
955 genptk_ctlSpline(s);
956 }
957
958 /*
959 * d r a w S h a p e ( )
960 *
961 * This routine is way too dependent on hardcoded fill_style values.
962 * Because so many other gen*.c routines use them, though, I'm too
963 * lazy to go through all the code.
964 */
965
966 static void
drawShape(void (* ptkShape)(),void * p,int thickness,int penColor,int fillColor,int fillStyle)967 drawShape(void (*ptkShape)(), void *p, int thickness, int penColor,
968 int fillColor, int fillStyle)
969 {
970 /* Draw filled and/or stippled region enclosed by shape. */
971 if (fillStyle != UNFILLED) {
972 switch (fillColor) {
973 case DEFAULT:
974 case BLACK_COLOR:
975 case WHITE_COLOR:
976 if (fillStyle < 20) {
977 /* Draw underlying shape. */
978 ptkShape(p, NONE, rgbColorVal(fillColor)
979 ^ 0xffffff, NONE, 0);
980 /* Draw stipple pattern in fill color. */
981 ptkShape(p, NONE, rgbColorVal(fillColor),
982 fillStyle, 0);
983 } else if (fillStyle == 20) {
984 /* Draw underlying shape. */
985 ptkShape(p, NONE, rgbColorVal(fillColor),
986 NONE, 0);
987 } else if (fillStyle <= 40) {
988 /* Should never get here... */
989 fprintf(stderr, "drawShape: b&w error.\n");
990 } else {
991 /* Draw underlying shape with fill color. */
992 ptkShape(p, NONE, rgbColorVal(fillColor),
993 NONE, 0);
994 /* Draw fill pattern with pen color. */
995 ptkShape(p, NONE, rgbColorVal(penColor),
996 fillStyle, 0);
997 }
998 break;
999 default:
1000 if (fillStyle < 20) {
1001 /* First, fill region with black. */
1002 ptkShape(p, NONE, 0x000000, NONE, 0);
1003 /* Then, stipple pattern in fill color. */
1004 ptkShape(p, NONE, rgbColorVal(fillColor),
1005 fillStyle, 0);
1006 } else if (fillStyle == 20) {
1007 /* Full saturation of fill color. */
1008 ptkShape(p, NONE, rgbColorVal(fillColor),
1009 NONE, 0);
1010 } else if (fillStyle < 40) {
1011 /* First, fill region with fill color. */
1012 ptkShape(p, NONE, rgbColorVal(fillColor),
1013 NONE, 0);
1014 /* Then, draw stipple pattern in white. */
1015 ptkShape(p, NONE, 0xffffff, fillStyle-20, 0);
1016 } else if (fillStyle == 40) {
1017 /* Maximally tinted: white. */
1018 ptkShape(p, NONE, 0xffffff, NONE, 0);
1019 } else {
1020 /* Draw underlying shape with fill color. */
1021 ptkShape(p, NONE, rgbColorVal(fillColor),
1022 NONE, 0);
1023 /* Draw fill pattern with pen color. */
1024 ptkShape(p, NONE, rgbColorVal(penColor),
1025 fillStyle, 0);
1026 }
1027 break;
1028 }
1029 }
1030
1031 /* Finally draw shape itself. */
1032 if (thickness > 0)
1033 ptkShape(p, rgbColorVal(penColor), NONE, NONE, thickness/15);
1034 }
1035
1036 /*
1037 * p t k A r c ( )
1038 *
1039 * Generate the Tk canvas item and options for an arc. Certain
1040 * assumptions are made regarding filling (using Tk chord style)
1041 * or unfilled (Tk arc style) to mimic xfig.
1042 */
1043
1044 void
ptkArc(void * shape,unsigned int outlineColor,unsigned int fillColor,unsigned int fillPattern,int thickness)1045 ptkArc(void *shape, unsigned int outlineColor, unsigned int fillColor,
1046 unsigned int fillPattern, int thickness)
1047 {
1048 char stfp[1024];
1049 double cx, cy, /* Center of circle containing arc. */
1050 sx, sy, /* Start point of arc. */
1051 ex, ey, /* Stop point of arc. */
1052 angle1, angle2, extent, radius, startAngle;
1053 F_arc *a;
1054
1055 a = (F_arc *) shape;
1056 cx = X(a->center.x); /* Center. */
1057 cy = Y(a->center.y);
1058 sx = X(a->point[0].x) - cx; /* Start point. */
1059 sy = cy - Y(a->point[0].y);
1060 ex = X(a->point[2].x) - cx; /* End point. */
1061 ey = cy - Y(a->point[2].y);
1062
1063 radius = sqrt(sy*sy + sx*sx);
1064 angle1 = atan2(sy, sx) * 180.0 / M_PI;
1065 if (angle1 < 0.)
1066 angle1 += 360.;
1067 angle2 = atan2(ey, ex) * 180.0 / M_PI;
1068 if (angle2 < 0.)
1069 angle2 += 360.;
1070
1071 if (a->direction == 1) { /* Counter-clockwise. */
1072 startAngle = angle1;
1073 extent = angle2 - angle1;
1074 } else { /* Clockwise. */
1075 startAngle = angle2;
1076 extent = angle1 - angle2;
1077 }
1078 if (extent < 0.) /* Sweep of arc. */
1079 extent += 360.;
1080
1081 sprintf(stfp, "%s->createArc(", canvas);
1082 niceLine(stfp);
1083 /* Coords of bounding rectangle. */
1084 sprintf(stfp, "qw/%.3fi %.3fi %.3fi %.3fi",
1085 cx-radius, cy-radius, cx+radius, cy+radius);
1086 niceLine(stfp);
1087 /* Start angle in degrees and its extent in degrees. */
1088 sprintf(stfp, " -start %lf -extent %lf/", startAngle, extent);
1089 niceLine(stfp);
1090
1091 if (outlineColor == NONE)
1092 sprintf(stfp, ", -outline => undef");
1093 else
1094 sprintf(stfp, ", -outline => '#%6.6x'", outlineColor);
1095 niceLine(stfp);
1096
1097 switch (a->type) {
1098 case T_OPEN_ARC:
1099 if (fillColor == NONE)
1100 sprintf(stfp, ", -style => 'arc', -fill => undef");
1101 else
1102 sprintf(stfp, ", -style => 'chord', -fill => '#%6.6x'", fillColor);
1103 niceLine(stfp);
1104 break;
1105 case T_PIE_WEDGE_ARC:
1106 if (fillColor == NONE)
1107 sprintf(stfp, ", -style => 'pieslice', -fill => undef");
1108 else
1109 sprintf(stfp, ", -style => 'pieslice', -fill => '#%6.6x'",
1110 fillColor);
1111 niceLine(stfp);
1112 break;
1113 default:
1114 fprintf(stderr, "ptkArc: unknown arc type.\n");
1115 break;
1116 }
1117
1118 if (fillPattern != NONE) {
1119 sprintf(stfp, ", -stipple => \"\\@%s\"", stippleFilename(fillPattern));
1120 niceLine(stfp);
1121 }
1122 if (thickness != 1) {
1123 sprintf(stfp, ", -width => '%d'", thickness);
1124 niceLine(stfp);
1125 }
1126
1127 sprintf(stfp, ");\n");
1128 niceLine(stfp);
1129 }
1130
1131 /*
1132 * p t k E l l i p s e ( )
1133 */
1134
1135 void
ptkEllipse(void * shape,unsigned int outlineColor,unsigned int fillColor,unsigned int fillPattern,int thickness)1136 ptkEllipse(void *shape, unsigned int outlineColor, unsigned int fillColor,
1137 unsigned int fillPattern, int thickness)
1138 {
1139 char stfp[1024];
1140 F_ellipse *e;
1141
1142 e = (F_ellipse *) shape;
1143 sprintf(stfp, "%s->createOval(qw/%lfi %lfi %lfi %lfi/",
1144 canvas,
1145 X(e->center.x - e->radiuses.x),
1146 Y(e->center.y - e->radiuses.y),
1147 X(e->center.x + e->radiuses.x),
1148 Y(e->center.y + e->radiuses.y));
1149 niceLine(stfp);
1150
1151 if (outlineColor == NONE)
1152 sprintf(stfp, ", -outline => undef");
1153 else
1154 sprintf(stfp, ", -outline => '#%6.6x'", outlineColor);
1155 niceLine(stfp);
1156
1157 if (fillColor == NONE)
1158 sprintf(stfp, ", -fill => undef");
1159 else
1160 sprintf(stfp, ", -fill => '#%6.6x'", fillColor);
1161 niceLine(stfp);
1162
1163 if (fillPattern != NONE) {
1164 sprintf(stfp, ", -stipple => \"\\@%s\"", stippleFilename(fillPattern));
1165 niceLine(stfp);
1166 }
1167
1168 if (thickness != 1) {
1169 sprintf(stfp, ", -width => '%d'", thickness);
1170 niceLine(stfp);
1171 }
1172
1173 sprintf(stfp, ");\n");
1174 niceLine(stfp);
1175 }
1176
1177 /*
1178 * p t k L i n e ( )
1179 */
1180
1181 static void
ptkLine(void * shape,unsigned int penColor,unsigned int fillColor,unsigned int fillPattern,int thickness)1182 ptkLine(void * shape, unsigned int penColor, unsigned int fillColor,
1183 unsigned int fillPattern, int thickness)
1184 {
1185 char dir[8], stfp[1024];
1186 extern char *canvas; /* Tk canvas name. */
1187 F_arrow *a;
1188 F_line *l;
1189 F_point *p, *q;
1190
1191 l = (F_line *) shape;
1192 p = l->points;
1193 q = p->next;
1194
1195 if (q == NULL) {
1196 /* Degenerate line (single point). */
1197 sprintf(stfp, "%s->createLine(qw/%lfi %lfi %lfi %lfi/",
1198 canvas, X(p->x), Y(p->y), X(p->x), Y(p->y));
1199 niceLine(stfp);
1200 } else {
1201 sprintf(stfp, "%s->createLine(", canvas);
1202 niceLine(stfp);
1203 sprintf(stfp, " '%lfi', '%lfi'", X(p->x), Y(p->y));
1204 niceLine(stfp);
1205 for ( /* No op. */ ; q != NULL; q = q->next) {
1206 sprintf(stfp, ", '%lfi', '%lfi'", X(q->x), Y(q->y));
1207 niceLine(stfp);
1208 }
1209 }
1210
1211 switch (l->style) {
1212 case -1:/* Default. */
1213 case 0: /* Solid line. */
1214 break;
1215 case 1: /* Dashed line. */
1216 case 2: /* Dotted line. */
1217 case 3: /* Dash-dotted line. */
1218 case 4: /* Dash-double-dotted line. */
1219 case 5: /* Dash-triple-dotted line. */
1220 default:
1221 fprintf(stderr, "ptkLine: only solid line styles supported.\n");
1222 break;
1223 }
1224
1225 a = NULL;
1226 if (l->for_arrow && !l->back_arrow) {
1227 a = l->for_arrow;
1228 strcpy(dir, "last");
1229 } else if (!l->for_arrow && l->back_arrow) {
1230 a = l->back_arrow;
1231 strcpy(dir, "first");
1232 } else if (l->for_arrow && l->back_arrow) {
1233 a = l->back_arrow;
1234 strcpy(dir, "both");
1235 }
1236 if (a)
1237 switch (a->type) {
1238 case 0: /* Stick type. */
1239 sprintf(stfp, ", -arrow => '%s', -arrowshape => [0, '%fi', '%fi']",
1240 dir, X(a->ht), X(a->wid)/2.);
1241 niceLine(stfp);
1242 fprintf(stderr, "Warning: stick arrows do not "
1243 "work well in Tk.\n");
1244 break;
1245 case 1: /* Closed triangle. */
1246 sprintf(stfp, ", -arrow => '%s', -arrowshape => ['%fi', '%fi', '%fi']",
1247 dir, X(a->ht), X(a->ht), X(a->wid)/2.);
1248 niceLine(stfp);
1249 break;
1250 case 2: /* Closed with indented butt. */
1251 sprintf(stfp, ", -arrow => '%s', -arrowshape => ['%fi', '%fi', '%fi']",
1252 dir, 0.8 * X(a->ht), X(a->ht), X(a->wid)/2.);
1253 niceLine(stfp);
1254 break;
1255 case 3: /* Closed with pointed butt. */
1256 sprintf(stfp, ", -arrow => '%s', -arrowshape => ['%fi', '%fi', '%fi']",
1257 dir, 1.2 * X(a->ht), X(a->ht), X(a->wid)/2.);
1258 niceLine(stfp);
1259 break;
1260 default:
1261 fprintf(stderr, "ptkLine: unknown arrow type.\n");
1262 break;
1263 }
1264
1265 switch (l->join_style) {
1266 case 0: /* Miter (Tk default). */
1267 break;
1268 case 1: /* Round. */
1269 sprintf(stfp, ", -joinstyle => 'round'");
1270 niceLine(stfp);
1271 break;
1272 case 2: /* Bevel. */
1273 sprintf(stfp, ", -joinstyle => 'bevel'");
1274 niceLine(stfp);
1275 break;
1276 default:
1277 fprintf(stderr, "ptkLine: unknown join style.\n");
1278 break;
1279 }
1280
1281 switch (l->cap_style) {
1282 case 0: /* Butt (Tk default). */
1283 break;
1284 case 1: /* Round. */
1285 sprintf(stfp, ", -capstyle => 'round'");
1286 niceLine(stfp);
1287 break;
1288 case 2: /* Projecting. */
1289 sprintf(stfp, ", -capstyle => 'projecting'");
1290 niceLine(stfp);
1291 break;
1292 default:
1293 fprintf(stderr, "ptkLine: unknown cap style.\n");
1294 break;
1295 }
1296
1297 if (thickness != 1) {
1298 sprintf(stfp, ", -width => %d", thickness);
1299 niceLine(stfp);
1300 }
1301 if (penColor != BLACK_COLOR && penColor != DEFAULT) {
1302 sprintf(stfp, ", -fill => '#%6.6x'", penColor);
1303 niceLine(stfp);
1304 }
1305 sprintf(stfp, ");\n");
1306 niceLine(stfp);
1307 }
1308
1309 /*
1310 * p t k P o l y g o n ( )
1311 */
1312
1313 static void
ptkPolygon(void * shape,unsigned int outlineColor,unsigned int fillColor,unsigned int fillPattern,int thickness)1314 ptkPolygon(void * shape, unsigned int outlineColor, unsigned int fillColor,
1315 unsigned int fillPattern, int thickness)
1316 {
1317 char stfp[1024];
1318 extern char *canvas; /* Tk canvas name. */
1319 F_point *p, *q;
1320 int pts;
1321
1322 p = (F_point *) shape;
1323
1324 q = p->next;
1325 for (pts = 0; q != NULL; q = q->next) {
1326 if (++pts == 3)
1327 break;
1328 }
1329 if (pts < 3)
1330 return; /* Bail out if it's not a polygon. */
1331
1332 q = p->next;
1333 sprintf(stfp, "%s->createPolygon(", canvas);
1334 niceLine(stfp);
1335 sprintf(stfp, "'%lfi', '%lfi'", X(p->x), Y(p->y));
1336 niceLine(stfp);
1337 for ( /* No op. */ ; q != NULL; q = q->next) {
1338 sprintf(stfp, ", '%lfi', '%lfi'", X(q->x), Y(q->y));
1339 niceLine(stfp);
1340 }
1341
1342 if (outlineColor == NONE)
1343 sprintf(stfp, ", -outline => undef");
1344 else
1345 sprintf(stfp, ", -outline => '#%6.6x'", outlineColor);
1346 niceLine(stfp);
1347
1348 if (fillColor == NONE)
1349 sprintf(stfp, ", -fill => undef");
1350 else
1351 sprintf(stfp, ", -fill => '#%6.6x'", fillColor);
1352 niceLine(stfp);
1353
1354 if (fillPattern != NONE) {
1355 sprintf(stfp, ", -stipple => \"\\@%s\"", stippleFilename(fillPattern));
1356 niceLine(stfp);
1357 }
1358
1359 if (thickness != 1) {
1360 sprintf(stfp, ", -width => '%d'", thickness);
1361 niceLine(stfp);
1362 }
1363
1364 sprintf(stfp, ");\n");
1365 niceLine(stfp);
1366 }
1367
1368 /*
1369 * r g b C o l o r V a l ( )
1370 *
1371 * Given an indexi into either the standard color list or into the
1372 * user defined color list, return the hex RGB value of the color.
1373 */
1374
1375 static unsigned int
rgbColorVal(int colorIndex)1376 rgbColorVal(int colorIndex)
1377 {
1378 extern User_color user_colors[];
1379 unsigned int rgb;
1380 static unsigned int rgbColors[NUM_STD_COLS] = {
1381 0x000000, 0x0000ff, 0x00ff00, 0x00ffff, 0xff0000, 0xff00ff,
1382 0xffff00, 0xffffff, 0x00008f, 0x0000b0, 0x0000d1, 0x87cfff,
1383 0x008f00, 0x00b000, 0x00d100, 0x008f8f, 0x00b0b0, 0x00d1d1,
1384 0x8f0000, 0xb00000, 0xd10000, 0x8f008f, 0xb000b0, 0xd100d1,
1385 0x803000, 0xa14000, 0xb46100, 0xff8080, 0xffa1a1, 0xffbfbf,
1386 0xffe0e0, 0xffd600
1387 };
1388
1389 if (colorIndex == DEFAULT)
1390 rgb = rgbColors[0];
1391 else if (colorIndex < NUM_STD_COLS)
1392 rgb = rgbColors[colorIndex];
1393 else
1394 rgb = ((user_colors[colorIndex-NUM_STD_COLS].r & 0xff) << 16)
1395 | ((user_colors[colorIndex-NUM_STD_COLS].g & 0xff) << 8)
1396 | (user_colors[colorIndex-NUM_STD_COLS].b & 0xff);
1397 return rgb;
1398 }
1399
1400 /*
1401 * s t i p p l e F i l e n a m e ( )
1402 *
1403 * Given xfig index number, return the filename of the corresponding
1404 * stipple pattern. Tk requires the bitmap to be in a file.
1405 */
1406
1407 static char *
stippleFilename(int patternIndex)1408 stippleFilename(int patternIndex)
1409 {
1410 static char * fillNames[63] = {
1411 "sp0.bmp", "sp1.bmp", "sp2.bmp", "sp3.bmp", "sp4.bmp",
1412 "sp5.bmp", "sp6.bmp", "sp7.bmp", "sp8.bmp", "sp9.bmp",
1413 "sp10.bmp", "sp11.bmp", "sp12.bmp", "sp13.bmp", "sp14.bmp",
1414 "sp15.bmp", "sp16.bmp", "sp17.bmp", "sp18.bmp", "sp19.bmp",
1415 "sp20.bmp",
1416
1417 "", "", "", "", "", "", "", "", "", "",
1418 "", "", "", "", "", "", "", "", "", "",
1419
1420 "left30.bmp", "right30.bmp", "crosshatch30.bmp",
1421 "left45.bmp", "right45.bmp", "crosshatch45.bmp",
1422 "bricks.bmp", "vert_bricks.bmp", "horizontal.bmp",
1423 "vertical.bmp", "crosshatch.bmp", "leftshingle.bmp",
1424 "rightshingle.bmp", "vert_leftshingle.bmp",
1425 "vert_rightshingle.bmp", "fishscales.bmp",
1426 "small_fishscales.bmp", "circles.bmp", "hexagons.bmp",
1427 "octagons.bmp", "horiz_saw.bmp", "vert_saw.bmp"
1428 };
1429 extern char *xbmPathVar; /* Global. */
1430 static char path[256];
1431
1432 /* XXX something like File::Spec would be better, but this is
1433 sufficient for Unix and Win32 */
1434 sprintf(path, "%s/%s",
1435 xbmPathVar, fillNames[patternIndex]);
1436 return path;
1437 }
1438
1439 /*
1440 * n i c e L i n e ( )
1441 *
1442 * Instead of directly calling fprintf()'s, this routine is used so
1443 * that lines are printed that are 80 characters long, give or take
1444 * a handful. Otherwise - spline routines in particular - will generate
1445 * humongously long lines that are a pain in the butt to edit...
1446 */
1447
1448 static void
niceLine(char * s)1449 niceLine(char *s)
1450 {
1451 extern FILE *tfp; /* File descriptor of Tk file. */
1452 int i, len;
1453 static int inQuote = 0;
1454 static int pos = 0;
1455
1456 len = strlen(s);
1457 for (i = 0; i < len; i++) {
1458 if (s[i] == '"') {
1459 inQuote ^= 1; /* Flip between 0/1. */
1460 putc(s[i], tfp);
1461 pos++;
1462 } else if (!inQuote && (pos > 80) && (s[i] == ' ')) {
1463 fprintf(tfp, " \n ");
1464 pos = 2;
1465 } else {
1466 putc(s[i], tfp);
1467 if (s[i] == '\n')
1468 pos = 0;
1469 else
1470 pos++;
1471 }
1472 }
1473 }
1474
1475 /*
1476 * d e v _ p t k
1477 *
1478 * The wrapper used by fig2dev to
1479 * isolate the device specific details.
1480 */
1481
1482 struct driver dev_ptk = {
1483 genptk_option,
1484 genptk_start,
1485 gendev_null,
1486 genptk_arc,
1487 genptk_ellipse,
1488 genptk_line,
1489 genptk_spline,
1490 genptk_text,
1491 genptk_end,
1492 INCLUDE_TEXT
1493 };
1494
1495