Annotation of OpenXM_contrib/gnuplot/term/pdf.trm, Revision 1.1.1.1
1.1 ohara 1: /*Hello, Emacs, this is -*-C-*- ! */
2: /*------------------------------
3: GNUPLOT - pdf.trm
4:
5: This file is included by ../term.c.
6:
7: This driver uses PDFlib from www.pdflib.com
8:
9: Author:
10:
11: Hans-Bernhard Br"oker
12: broeker@physik.rwth-aachen.de
13:
14: Licence: see the gnuplot copyright (to be merged into here...)
15:
16: Options: can #define PDF_DONT_COMPRESS to avoid PDF output
17: generated being compressed (by the 'deflate' algorithm as used
18: in 'zip' or 'gzip'). That helps in debugging.
19:
20: ------------------------------*/
21:
22: /* CODEME: Add patterned lines (?). Implement the PM3D stuff. */
23:
24: #include "driver.h"
25:
26: #ifdef TERM_REGISTER
27: register_term (pdf)
28: #endif
29:
30: #ifdef TERM_PROTO
31: TERM_PUBLIC void PDF_options __PROTO ((void));
32: TERM_PUBLIC void PDF_init __PROTO ((void));
33: TERM_PUBLIC void PDF_graphics __PROTO ((void));
34: TERM_PUBLIC void PDF_text __PROTO ((void));
35: TERM_PUBLIC void PDF_linetype __PROTO ((int linetype));
36: TERM_PUBLIC void PDF_move __PROTO ((unsigned int x, unsigned int y));
37: TERM_PUBLIC void PDF_vector __PROTO ((unsigned int x, unsigned int y));
38: TERM_PUBLIC void PDF_put_text __PROTO ((unsigned int x, unsigned int y, char *str));
39: TERM_PUBLIC void PDF_reset __PROTO ((void));
40: TERM_PUBLIC int PDF_justify_text __PROTO ((enum JUSTIFY mode));
41: TERM_PUBLIC int PDF_text_angle __PROTO ((int ang));
42: TERM_PUBLIC void PDF_point __PROTO ((unsigned int x, unsigned int y, int pointstyle));
43: TERM_PUBLIC int PDF_set_font __PROTO ((char *font));
44: TERM_PUBLIC void PDF_boxfill __PROTO((int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height));
45: TERM_PUBLIC void PDF_linewidth __PROTO ((double linewidth));
46:
47: #define PDF_NUM_POINTTYPES 75 /* number of point symbol types not counting the dot */
48:
49: #define PDF_RESOLUTION (20) /* number of terminal pixels per pt */
50: #define PDF_XMAX (5*72*PDF_RESOLUTION) /* 5 inches, 72 pt/inch */
51: #define PDF_YMAX (3*72*PDF_RESOLUTION) /* 3 inches, 72 pt/inch */
52:
53: #endif /* TERM_PROTO */
54:
55: #ifndef TERM_PROTO_ONLY
56: #ifdef TERM_BODY
57:
58: #include <pdflib.h>
59:
60: PDF *myPDF = NULL;
61:
62: unsigned int PDF_xLast = UINT_MAX; /* current pen horizontal position*/
63: unsigned int PDF_yLast = UINT_MAX; /* current pen vertical position*/
64:
65: int PDF_LineType = -3; /* current line type*/
66: double PDF_LineWidth = 1.0; /* current line width*/
67: int PDF_TextAngle = 0; /* current text orientation*/
68: enum JUSTIFY PDF_TextJust = LEFT; /* current text justification*/
69:
70: char PDF_fontNameDef[MAX_ID_LEN + 1] = "Helvetica"; /* default text font family*/
71: double PDF_fontSizeDef = 6; /* default text size*/
72: char PDF_fontNameCur[MAX_ID_LEN + 1] = "Helvetica"; /* current text font family*/
73: double PDF_fontSizeCur = 6; /* current text size*/
74:
75: TBOOLEAN PDF_pageIsOpen = FALSE; /* already started a page ?? */
76: TBOOLEAN PDF_pathIsOpen = FALSE; /* open path flag*/
77:
78: int PDF_fontAscent = 0; /* estimated current font ascent*/
79: int PDF_fontDescent = 0; /* estimated current font descent*/
80: int PDF_fontLeading = 0; /* estimated current font leading*/
81: int PDF_fontAvWidth = 0; /* estimated current font char average width*/
82:
83: static short PDF_Pen_RealID __PROTO ((int));
84: static void PDF_PathOpen __PROTO ((void));
85: static void PDF_PathClose __PROTO ((void));
86: static void PDF_SetFont __PROTO ((void));
87:
88: /*------------------------ helper functions -------------------*/
89:
90: static short
91: PDF_Pen_RealID (inPenCode)
92: int inPenCode;
93: {
94: if (inPenCode >= 13)
95: inPenCode %= 13; /* normalize pen code*/
96: if (inPenCode < -2)
97: inPenCode = -2;
98:
99: return (inPenCode + 2);
100: }
101:
102: /* Functions to ensure that as many move() and vector() calls as
103: * possible get converted into a single long 'path', before closing it
104: * with a stroke or similar command. */
105: static void
106: PDF_PathOpen ()
107: {
108: PDF_pathIsOpen = TRUE;
109: }
110:
111: static void
112: PDF_PathClose ()
113: {
114: if (PDF_pathIsOpen) {
115: PDF_stroke(myPDF);
116:
117: PDF_pathIsOpen = FALSE;
118: }
119: }
120:
121: /* Helper function to deal with switching over to a newly selected
122: * font. For now, this does not try to embed fonts into the PDF
123: * file. This relies on the user restricting herself to the 14
124: * 'classical' fonts built into every valid PDF reader application */
125: static void
126: PDF_SetFont ()
127: {
128: int font_handle = PDF_findfont(myPDF, PDF_fontNameCur, "host", 0);
129:
130: PDF_setfont(myPDF, font_handle, PDF_fontSizeCur * PDF_RESOLUTION);
131:
132: /* Ask PDFlib for the actual numbers */
133: PDF_fontAscent = (int) (PDF_RESOLUTION * PDF_fontSizeCur * PDF_get_value(myPDF, "ascender", 0));
134: PDF_fontDescent = (int) (- PDF_RESOLUTION * PDF_fontSizeCur * PDF_get_value(myPDF, "descender", 0));
135: PDF_fontLeading = (int) (PDF_RESOLUTION * PDF_fontSizeCur * 0.25);
136:
137: /* Assume this particular string is a somewhat reasonable typical
138: * output, for getting at the average character width */
139: PDF_fontAvWidth = (int)
140: (PDF_RESOLUTION * PDF_stringwidth(myPDF, "01234567890123456789",
141: font_handle, PDF_fontSizeCur)
142: / 20.0);
143: }
144:
145: /*------------------- the terminal entry functions --------------------*/
146:
147:
148: TERM_PUBLIC void
149: PDF_options ()
150: {
151: struct value a;
152:
153: if (!END_OF_COMMAND) { /* get default font family name*/
154: if (almost_equals (c_token, "fn$ame")) {
155: c_token++;
156:
157: if (!END_OF_COMMAND && isstring (c_token)) {
158: quote_str (PDF_fontNameDef, c_token, MAX_ID_LEN);
159: c_token++;
160: } else
161: int_error("fname: expecting font name", c_token);
162: }
163: }
164:
165: if (!END_OF_COMMAND) { /* get default font size*/
166: if (almost_equals (c_token, "fs$ize")) {
167: c_token++;
168:
169: if (END_OF_COMMAND)
170: int_error("fsize: expecting font size", c_token);
171: PDF_fontSizeDef = real (const_express (&a));
172: }
173: }
174:
175: if (!END_OF_COMMAND)
176: int_error("unexpected text at end of command", c_token);
177:
178: /* Save options back into options string in normalized format */
179: sprintf(term_options, "fname '%s' fsize %g",
180: PDF_fontNameDef, PDF_fontSizeDef);
181: }
182:
183:
184: TERM_PUBLIC void
185: PDF_init ()
186: {
187: static TBOOLEAN PDFlib_booted = FALSE;
188:
189: if (!PDFlib_booted) {
190: PDF_boot();
191: PDFlib_booted = TRUE;
192: }
193:
194: if (!myPDF)
195: myPDF = PDF_new();
196:
197: /*open new PDF file */
198: if (PDF_open_fp(myPDF, gpoutfile) == -1)
199: int_error("Error:cannot open PDF file .\n", NO_CARET);
200:
201: #ifdef PDF_DONT_COMPRESS
202: /* for easier debugging of the output, turn off PDF stream
203: * compression */
204: PDF_set_value(myPDF, "compress", 0);
205: #endif
206:
207: PDF_set_info(myPDF,"Creator","gnuplot-3.8e");
208: PDF_set_info(myPDF,"Author","Hans-Bernhard Broeker"); /* FIXME: put in username? */
209: PDF_set_info(myPDF,"Title","gnuplot diagram"); /* FIXME: use 'set title', if any ? */
210:
211: PDF_LineType = -3;
212:
213: /* set current font to default */
214: strcpy(PDF_fontNameCur, PDF_fontNameDef);
215: PDF_fontSizeCur = PDF_fontSizeDef;
216:
217: /* Have to start the first page now, in order to know the actual
218: * size of the selected font */
219: PDF_graphics();
220:
221: /* set h_char, v_char*/
222: term->h_char = PDF_fontAvWidth;
223: term->v_char = (PDF_fontAscent + PDF_fontDescent + PDF_fontLeading);
224:
225: /* set h_tic, v_tic*/
226: term->h_tic = term->v_tic = 3 * PDF_RESOLUTION;
227:
228: /* initialize terminal's pointsize from "set pointsize" value */
229: term_pointsize = pointsize;
230: }
231:
232:
233: TERM_PUBLIC void
234: PDF_graphics ()
235: {
236: if (PDF_pageIsOpen)
237: return; /* already open --> nothing to do */
238:
239: PDF_pathIsOpen = FALSE;
240: PDF_xLast = PDF_yLast = UINT_MAX;
241:
242: /* set xmax, ymax*/
243: term->xmax = PDF_XMAX * xsize;
244: term->ymax = PDF_YMAX * ysize;
245:
246: PDF_begin_page(myPDF, (double)term->xmax / PDF_RESOLUTION,
247: (double)term->ymax / PDF_RESOLUTION);
248: PDF_scale(myPDF, 1.0/PDF_RESOLUTION, 1.0/PDF_RESOLUTION);
249: if (title.text && title.text[0])
250: /* a title has been set --> use it as the bookmark name, too */
251: PDF_add_bookmark(myPDF, title.text, 0, 1);
252: PDF_pageIsOpen = TRUE;
253:
254: PDF_SetFont();
255: }
256:
257:
258: TERM_PUBLIC void
259: PDF_text ()
260: {
261: PDF_PathClose();
262: PDF_end_page(myPDF);
263: PDF_pageIsOpen = FALSE;
264: }
265:
266:
267: TERM_PUBLIC void
268: PDF_reset ()
269: {
270: assert(PDF_pageIsOpen == FALSE);
271: PDF_close(myPDF);
272: PDF_delete(myPDF);
273: myPDF = NULL;
274: }
275:
276:
277: TERM_PUBLIC void
278: PDF_linetype (int linetype)
279: {
280: if (linetype != PDF_LineType) {
281: int real_linetype = PDF_Pen_RealID(linetype);
282: struct rgb *this_color = web_color_rgbs + 1 + real_linetype;
283:
284: PDF_PathClose ();
285: PDF_LineType = linetype;
286:
287: PDF_setrgbcolor(myPDF, this_color->r / 255.0,
288: this_color->g / 255.0, this_color->b / 255.0);
289: }
290: }
291:
292:
293: TERM_PUBLIC void
294: PDF_linewidth (double linewidth)
295: {
296: PDF_PathClose();
297: PDF_LineWidth = PDF_RESOLUTION * linewidth / 4.0;
298: PDF_setlinewidth(myPDF, PDF_LineWidth);
299: }
300:
301:
302: TERM_PUBLIC void
303: PDF_move (unsigned int x, unsigned int y)
304: {
305: if (PDF_pathIsOpen && x == PDF_xLast && y == PDF_yLast)
306: return;
307:
308: PDF_PathOpen ();
309: PDF_moveto(myPDF, x, y);
310:
311: PDF_xLast = x;
312: PDF_yLast = y;
313: }
314:
315:
316: TERM_PUBLIC void
317: PDF_vector (unsigned int x, unsigned int y)
318: {
319: if (PDF_pathIsOpen && x == PDF_xLast && y == PDF_yLast)
320: return;
321:
322: PDF_PathOpen ();
323: PDF_lineto(myPDF, x, y);
324:
325: PDF_xLast = x;
326: PDF_yLast = y;
327: }
328:
329: /* Helper function. Many symbols have an additional dot in their
330: * center, so isolate its drawing into a separate function. */
331: static GP_INLINE void
332: PDF_dot (unsigned int x, unsigned int y)
333: {
334: /* Imitate PS's way of creating a small dot by a zero-length line
335: * segment with rounded endpoints */
336: PDF_setlinecap(myPDF, 1); /* rounded ends */
337: PDF_moveto(myPDF, x, y);
338: PDF_lineto(myPDF, x, y);
339: PDF_stroke(myPDF);
340: }
341:
342:
343: TERM_PUBLIC void
344: PDF_point (unsigned int x, unsigned int y, int number)
345: {
346: PDF_PathClose ();
347: PDF_save(myPDF);
348:
349: if (number < 0) {
350: /* Like the PostScript driver, treat all negative numbers as
351: * 'with dots'. */
352: PDF_dot(x, y);
353: } else {
354: /* Change coordinate system so the point symbols themselves
355: * can be drawn without depending on position or size (-->
356: * better compression and less coding for gnuplot) */
357: /* NB: I use the do_pointsize() default implementation, which
358: * just stores the last set pointsize into `term_pointsize',
359: * to avoid introducing another static driver-local variable
360: * */
361: PDF_translate(myPDF, x, y);
362: PDF_scale(myPDF, term->h_tic / 2.0 * term_pointsize,
363: term->v_tic / 2.0 * term_pointsize);
364: /* Correct linewidth to counter the scaling effect --- assume
365: * h_tic is usable, to avoid having to average h_ and v_tic */
366: PDF_setlinewidth(myPDF,
367: PDF_LineWidth / (term->h_tic / 2.0 * term_pointsize));
368: switch (number %= PDF_NUM_POINTTYPES) {
369: case 0: /* Plus */
370: PDF_moveto(myPDF, -1, 0);
371: PDF_lineto(myPDF, 1, 0);
372: PDF_moveto(myPDF, 0, -1);
373: PDF_lineto(myPDF, 0, 1);
374: PDF_stroke(myPDF);
375: break;
376: case 2: /* Star */
377: PDF_moveto(myPDF, -1, 0);
378: PDF_lineto(myPDF, 1, 0);
379: PDF_moveto(myPDF, 0, -1);
380: PDF_lineto(myPDF, 0, 1);
381: /* FALLTHROUGH */
382: case 1: /* Cross */
383: PDF_moveto(myPDF, -1, -1);
384: PDF_lineto(myPDF, 1, 1);
385: PDF_moveto(myPDF, 1, -1);
386: PDF_lineto(myPDF, -1, 1);
387: PDF_stroke(myPDF);
388: break;
389:
390: /* For each x = 0..5, 4 shapes are defined:
391: * 3 + 2*x --> hollow symbol with a dot at its center
392: * 4 + 2*x --> solid symbol filled in linetype's color
393: * 63 + x --> hollow symbol without the center dot
394: * 69 + x --> symbol filled with white --> opaque symbol */
395:
396: case 63+0: /* BoxEmpty */
397: case 3+2*0: /* Box */
398: PDF_moveto(myPDF, -1, -1);
399: PDF_lineto(myPDF, 1, -1);
400: PDF_lineto(myPDF, 1, 1);
401: PDF_lineto(myPDF, -1, 1);
402: PDF_closepath_stroke(myPDF);
403: if (number == 3) PDF_dot(0,0);
404: break;
405: case 69+0: /* BoxWhitefilled */
406: PDF_setgray_fill(myPDF, 1);
407: /* FALLTHROUGH */
408: case 4+2*0: /* BoxFilled */
409: PDF_moveto(myPDF, -1, -1);
410: PDF_lineto(myPDF, 1, -1);
411: PDF_lineto(myPDF, 1, 1);
412: PDF_lineto(myPDF, -1, 1);
413: PDF_closepath_fill_stroke(myPDF);
414: break;
415:
416: case 63+1: /* CircleEmpty */
417: case 3+2*1: /* Circle */
418: PDF_circle(myPDF, 0, 0, 1);
419: PDF_stroke(myPDF);
420: if (number == 5) PDF_dot(0,0);
421: break;
422: case 69+1: /* CircleWhitefilled */
423: PDF_setgray_fill(myPDF, 1);
424: /* FALLTHROUGH */
425: case 4+2*1: /* CircleFilled */
426: PDF_circle(myPDF, 0, 0, 1);
427: PDF_fill_stroke(myPDF);
428: break;
429:
430: case 63+2: /* TriangleUpEmpty */
431: case 3+2*2: /* TriangleUp */
432: PDF_moveto(myPDF, 0, 1.12);
433: PDF_lineto(myPDF, -1, -0.5);
434: PDF_lineto(myPDF, 1, -0.5);
435: PDF_closepath_stroke(myPDF);
436: if (number == 7) PDF_dot(0,0);
437: break;
438: case 69+2: /* TriangleUpWhitefilled */
439: PDF_setgray_fill(myPDF, 1);
440: /* FALLTHROUGH */
441: case 4+2*2: /* TriangleUpFilled */
442: PDF_moveto(myPDF, 0, 1.12);
443: PDF_lineto(myPDF, -1, -0.5);
444: PDF_lineto(myPDF, 1, -0.5);
445: PDF_closepath_fill_stroke(myPDF);
446: break;
447:
448: case 63+3: /* TriangleDownEmpty */
449: case 3+2*3: /* TriangleDown */
450: PDF_moveto(myPDF, 0, -1.12);
451: PDF_lineto(myPDF, -1, 0.5);
452: PDF_lineto(myPDF, 1, 0.5);
453: PDF_closepath_stroke(myPDF);
454: if (number == 9) PDF_dot(0,0);
455: break;
456: case 69+3: /* TriangleDownWhitefilled */
457: PDF_setgray_fill(myPDF, 1);
458: /* FALLTHROUGH */
459: case 4+2*3: /* TriangleDownFilled */
460: PDF_moveto(myPDF, 0, -1.12);
461: PDF_lineto(myPDF, -1, 0.5);
462: PDF_lineto(myPDF, 1, 0.5);
463: PDF_closepath_fill_stroke(myPDF);
464: break;
465:
466: case 63+4: /* DiamondEmpty */
467: case 3+2*4: /* Diamond */
468: PDF_moveto(myPDF, 0, -1);
469: PDF_lineto(myPDF, 1, 0);
470: PDF_lineto(myPDF, 0, 1);
471: PDF_lineto(myPDF, -1, 0);
472: PDF_closepath_stroke(myPDF);
473: if (number == 11) PDF_dot(0,0);
474: break;
475: case 69+4: /* DiamondWhitefilled */
476: PDF_setgray_fill(myPDF, 1);
477: /* FALLTHROUGH */
478: case 4+2*4: /* DiamondFilled */
479: PDF_moveto(myPDF, 0, -1);
480: PDF_lineto(myPDF, 1, 0);
481: PDF_lineto(myPDF, 0, 1);
482: PDF_lineto(myPDF, -1, 0);
483: PDF_closepath_fill_stroke(myPDF);
484: break;
485:
486: case 63+5: /* PentagonEmpty */
487: case 3+2*5: /* Pentagon */
488: PDF_moveto(myPDF, 0, 1);
489: PDF_lineto(myPDF, -0.95, 0.31);
490: PDF_lineto(myPDF, -0.58, -0.81);
491: PDF_lineto(myPDF, +0.58, -0.81);
492: PDF_lineto(myPDF, +0.95, 0.31);
493: PDF_closepath_stroke(myPDF);
494: if (number == 13) PDF_dot(0,0);
495: break;
496: case 69+5: /* PentagonWhitefilled */
497: PDF_setgray_fill(myPDF, 1);
498: /* FALLTHROUGH */
499: case 4+2*5: /* PentagonFilled */
500: PDF_moveto(myPDF, 0, 1);
501: PDF_lineto(myPDF, -0.95, 0.31);
502: PDF_lineto(myPDF, -0.58, -0.81);
503: PDF_lineto(myPDF, +0.58, -0.81);
504: PDF_lineto(myPDF, +0.95, 0.31);
505: PDF_closepath_fill_stroke(myPDF);
506: break;
507:
508: /* 15 + (0..15): circles with varying parts of'em filled. The added
509: * number is a bit-pattern of the 4 quadrants: 1 signals a quadrant
510: * filled */
511: case 15+0:
512: PDF_moveto(myPDF, 0, 0);
513: PDF_lineto(myPDF, 0, 1);
514: PDF_arc(myPDF, 0, 0, 1, 90, 360+90);
515: PDF_closepath_stroke(myPDF);
516: break;
517:
518: /* Generalize common code into a macro... */
519: #define CIRCLE_SINGLE_PIESLICE(x, y, angle1, angle2) \
520: PDF_moveto(myPDF, 0, 0); \
521: PDF_lineto(myPDF, (x), (y)); \
522: PDF_arc(myPDF, 0, 0, 1, (angle1), (angle2)); \
523: PDF_lineto(myPDF, 0, 0); \
524: PDF_closepath(myPDF); \
525: PDF_fill_stroke(myPDF); \
526: PDF_arc(myPDF, 0, 0, 1, (angle2), (angle1) + 360); \
527: PDF_stroke(myPDF); \
528: break;
529:
530: #define CIRCLE_SINGLE_QUADRANT(x, y, angle) \
531: CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+90);
532: case 15+1:
533: CIRCLE_SINGLE_QUADRANT(1, 0, 0);
534: case 15+2:
535: CIRCLE_SINGLE_QUADRANT(0, 1, 90);
536: case 15+4:
537: CIRCLE_SINGLE_QUADRANT(-1, 0, 180);
538: case 15+8:
539: CIRCLE_SINGLE_QUADRANT(0, -1, 270);
540: #undef CIRCLE_SINGLE_QUADRANT
541:
542: #define CIRCLE_TWO_NEIGHBOR_QUADRANTS(x, y, angle) \
543: CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+180)
544: case 15+3:
545: CIRCLE_TWO_NEIGHBOR_QUADRANTS(1, 0, 0);
546: case 15+6:
547: CIRCLE_TWO_NEIGHBOR_QUADRANTS(0, 1, 90);
548: case 15+12:
549: CIRCLE_TWO_NEIGHBOR_QUADRANTS(-1, 0, 180);
550: case 15+9:
551: CIRCLE_TWO_NEIGHBOR_QUADRANTS(0, -1, 270);
552: #undef CIRCLE_TWO_NEIGHBOR_QUADRANTS
553:
554: #define CIRCLE_TWO_OPPOSING_QUADRANTS(x, y, angle) \
555: PDF_moveto(myPDF, 0, 0); \
556: PDF_lineto(myPDF, x, y); \
557: PDF_arc(myPDF, 0, 0, 1, angle, angle + 90); \
558: PDF_lineto(myPDF, 0, 0); \
559: PDF_fill_stroke(myPDF); \
560: PDF_moveto(myPDF, 0, 0); \
561: PDF_lineto(myPDF, -x, -y); \
562: PDF_arc(myPDF, 0, 0, 1, angle + 180, angle + 270); \
563: PDF_lineto(myPDF, 0, 0); \
564: PDF_fill_stroke(myPDF); \
565: PDF_arc(myPDF, 0, 0, 1, angle + 90, angle + 360); \
566: PDF_stroke(myPDF); \
567: break;
568: case 15+5:
569: CIRCLE_TWO_OPPOSING_QUADRANTS(1, 0, 0);
570: case 15+10:
571: CIRCLE_TWO_OPPOSING_QUADRANTS(0, 1, 90);
572: #undef CIRCLE_TWO_OPPOSING_QUADRANTS
573:
574: #define CIRCLE_THREE_QUADRANTS(x, y, angle) \
575: CIRCLE_SINGLE_PIESLICE(x, y, angle, angle+270)
576: case 15+7:
577: CIRCLE_THREE_QUADRANTS(1, 0, 0);
578: case 15+14:
579: CIRCLE_THREE_QUADRANTS(0, 1, 90);
580: case 15+13:
581: CIRCLE_THREE_QUADRANTS(-1, 0, 180);
582: case 15+11:
583: CIRCLE_THREE_QUADRANTS(0, -1, 270);
584: #undef CIRCLE_THREE_QUADRANTS
585: #undef CIRCLE_SINGLE_PIESLICE
586:
587: case 15+15:
588: PDF_circle(myPDF, 0, 0, 1);
589: PDF_closepath_fill_stroke(myPDF);
590: break;
591:
592:
593: /*************************************************************************/
594: /* 31 + (0..15): squares with different quadrants of them filled in. */
595: /*************************************************************************/
596: /*************************************************************************/
597: /* 47 + (0..15): diamonds with filled quadrants as given by bit pattern */
598: /* Diamonds are drawn as squares rotated by 45 degrees, so can use
599: * fall-through from diamond to squares, and re-use some macros. */
600: /*************************************************************************/
601: case 47+0:
602: PDF_rotate(myPDF, 45);
603: /* FALLTHROUGH */
604: case 31+0:
605: PDF_moveto(myPDF, 0, 0);
606: PDF_lineto(myPDF, 0, 1);
607: PDF_lineto(myPDF, -1, 1);
608: PDF_lineto(myPDF, -1, -1);
609: PDF_lineto(myPDF, 1, -1);
610: PDF_lineto(myPDF, 1, 1);
611: PDF_lineto(myPDF, 0, 1);
612: PDF_stroke(myPDF);
613: break;
614:
615: case 47+15:
616: PDF_rotate(myPDF, 45);
617: /* FALLTHROUGH */
618: case 31+15:
619: PDF_moveto(myPDF, -1, 1);
620: PDF_lineto(myPDF, -1, -1);
621: PDF_lineto(myPDF, 1, -1);
622: PDF_lineto(myPDF, 1, 1);
623: PDF_closepath_fill_stroke(myPDF);
624: break;
625:
626: /* macros defining shapes of the partly filled symbols. Done by
627: * rotating the starting point (x0, y0) by 90 degrees or 45 degrees
628: * (with length adjustment). The rotations can be done without
629: * trigonometric function calls, since their values are known:
630: * cos(90)=0, sin(90)=1, cos(45)=sin(45)=1/sqrt(2). A good compiler
631: * should be able to optimize away all the local variables and
632: * loops... */
633:
634: #define SQUARE_SINGLE_PIESLICE(x0, y0, quadrants) \
635: { \
636: int quadrant = 0; \
637: int x= x0, y=y0; \
638: PDF_moveto(myPDF, 0, 0); \
639: PDF_lineto(myPDF, x, y); \
640: /* poor man's rotation by 45 and 90 degrees around the \
641: * square's outline. */ \
642: while (quadrant++ < quadrants) { \
643: int dummy; \
644: PDF_lineto(myPDF, x-y, x+y); \
645: dummy = x; x = -y; y = dummy; \
646: } \
647: PDF_lineto(myPDF, x, y); \
648: PDF_closepath_fill_stroke(myPDF); \
649: PDF_moveto(myPDF, x, y); \
650: while (quadrant++ <= 4) { \
651: int dummy; \
652: PDF_lineto(myPDF, x-y, x+y); \
653: dummy = x; x = -y; y = dummy; \
654: } \
655: PDF_lineto(myPDF, x, y); \
656: PDF_stroke(myPDF); \
657: } \
658: break;
659:
660: #define SQUARE_TWO_OPPOSING_QUADRANTS(x0, y0, angle) \
661: { \
662: int x = x0, y = y0, dummy; \
663: int counter = 0; \
664: \
665: while (counter++ < 2) { \
666: PDF_moveto(myPDF, 0, 0); \
667: PDF_lineto(myPDF, x, y); \
668: PDF_lineto(myPDF, x-y, x+y); \
669: dummy = x; x = -y; y = dummy; \
670: PDF_lineto(myPDF, x, y); \
671: PDF_closepath_fill_stroke(myPDF); \
672: \
673: PDF_moveto(myPDF, x, y); \
674: PDF_lineto(myPDF, x-y, x+y); \
675: dummy = x; x = -y; y = dummy; \
676: PDF_lineto(myPDF, x, y); \
677: PDF_stroke(myPDF); \
678: } \
679: break; \
680: }
681:
682: /* Macros for diamonds just prepend the rotation and then call those
683: * for squares: */
684: #define DIAMOND_SINGLE_PIESLICE(x, y, quadrants) \
685: PDF_rotate(myPDF, 45); \
686: SQUARE_SINGLE_PIESLICE(x, y, quadrants);
687: #define DIAMOND_TWO_OPPOSING_QUADRANTS(x, y, angle) \
688: PDF_rotate(myPDF, 45); \
689: SQUARE_TWO_OPPOSING_QUADRANTS(x, y, angle);
690:
691: /* ... and now all the individual cases. The 'angle' arguments' are
692: * purely for the sake of easing cut'n'paste with the circle case */
693: #define SQUARE_SINGLE_QUADRANT(x, y, angle) \
694: SQUARE_SINGLE_PIESLICE(x, y, 1);
695: case 31+1:
696: SQUARE_SINGLE_QUADRANT(1, 0, 0);
697: case 31+2:
698: SQUARE_SINGLE_QUADRANT(0, 1, 90);
699: case 31+4:
700: SQUARE_SINGLE_QUADRANT(-1, 0, 180);
701: case 31+8:
702: SQUARE_SINGLE_QUADRANT(0, -1, 270);
703: #undef SQUARE_SINGLE_QUADRANT
704:
705: #define SQUARE_TWO_NEIGHBOR_QUADRANTS(x, y, angle) \
706: SQUARE_SINGLE_PIESLICE(x, y, 2)
707: case 31+3:
708: SQUARE_TWO_NEIGHBOR_QUADRANTS(1, 0, 0);
709: case 31+6:
710: SQUARE_TWO_NEIGHBOR_QUADRANTS(0, 1, 90);
711: case 31+12:
712: SQUARE_TWO_NEIGHBOR_QUADRANTS(-1, 0, 180);
713: case 31+9:
714: SQUARE_TWO_NEIGHBOR_QUADRANTS(0, -1, 270);
715: #undef SQUARE_TWO_NEIGHBOR_QUADRANTS
716:
717: case 31+5:
718: SQUARE_TWO_OPPOSING_QUADRANTS(1, 0, 0);
719: case 31+10:
720: SQUARE_TWO_OPPOSING_QUADRANTS(0, 1, 90);
721:
722: #define SQUARE_THREE_QUADRANTS(x, y, angle) \
723: SQUARE_SINGLE_PIESLICE(x, y, 3)
724: case 31+7:
725: SQUARE_THREE_QUADRANTS(1, 0, 0);
726: case 31+14:
727: SQUARE_THREE_QUADRANTS(0, 1, 90);
728: case 31+13:
729: SQUARE_THREE_QUADRANTS(-1, 0, 180);
730: case 31+11:
731: SQUARE_THREE_QUADRANTS(0, -1, 270);
732: #undef SQUARE_THREE_QUADRANTS
733:
734: #define DIAMOND_SINGLE_QUADRANT(x, y, angle) \
735: DIAMOND_SINGLE_PIESLICE(x, y, 1)
736: case 47+1:
737: DIAMOND_SINGLE_QUADRANT(1, 0, 0);
738: case 47+2:
739: DIAMOND_SINGLE_QUADRANT(0, 1, 90);
740: case 47+4:
741: DIAMOND_SINGLE_QUADRANT(-1, 0, 180);
742: case 47+8:
743: DIAMOND_SINGLE_QUADRANT(0, -1, 270);
744: #undef DIAMOND_SINGLE_QUADRANT
745:
746: #define DIAMOND_TWO_NEIGHBOR_QUADRANTS(x, y, angle) \
747: DIAMOND_SINGLE_PIESLICE(x, y, 2)
748: case 47+3:
749: DIAMOND_TWO_NEIGHBOR_QUADRANTS(1, 0, 0);
750: case 47+6:
751: DIAMOND_TWO_NEIGHBOR_QUADRANTS(0, 1, 90);
752: case 47+12:
753: DIAMOND_TWO_NEIGHBOR_QUADRANTS(-1, 0, 180);
754: case 47+9:
755: DIAMOND_TWO_NEIGHBOR_QUADRANTS(0, -1, 270);
756: #undef DIAMOND_TWO_NEIGHBOR_QUADRANTS
757:
758:
759: case 47+5:
760: DIAMOND_TWO_OPPOSING_QUADRANTS(1, 0, 0);
761: case 47+10:
762: DIAMOND_TWO_OPPOSING_QUADRANTS(0, 1, 90);
763: #undef DIAMOND_TWO_OPPOSING_QUADRANTS
764: #undef SQUARE_TWO_OPPOSING_QUADRANTS
765:
766: #define DIAMOND_THREE_QUADRANTS(x, y, angle) \
767: DIAMOND_SINGLE_PIESLICE(x, y, 3)
768: case 47+7:
769: DIAMOND_THREE_QUADRANTS(1, 0, 0);
770: case 47+14:
771: DIAMOND_THREE_QUADRANTS(0, 1, 90);
772: case 47+13:
773: DIAMOND_THREE_QUADRANTS(-1, 0, 180);
774: case 47+11:
775: DIAMOND_THREE_QUADRANTS(0, -1, 270);
776: #undef DIAMOND_THREE_QUADRANTS
777: #undef DIAMOND_SINGLE_PIESLICE
778: #undef SQUARE_SINGLE_PIESLICE
779:
780: default:
781: {
782: char temp[64];
783: sprintf(temp, "PDF: unknown point type number %d", number);
784: int_warn(temp,NO_CARET);
785: }
786: }
787: }
788:
789: PDF_restore(myPDF);
790: PDF_xLast = x;
791: PDF_yLast = y;
792: }
793:
794:
795: TERM_PUBLIC int
796: PDF_justify_text (enum JUSTIFY mode)
797: {
798: PDF_TextJust = mode;
799: return (TRUE);
800: }
801:
802:
803: TERM_PUBLIC int
804: PDF_text_angle (int ang)
805: {
806: if (ang == 0 || ang == 1) {
807: /* FIXME: need to do this in a different way? */
808: PDF_TextAngle = ang;
809: return (TRUE);
810: }
811:
812: return (FALSE);
813: }
814:
815:
816: TERM_PUBLIC void
817: PDF_put_text (unsigned int x, unsigned int y, char *str)
818: {
819: char *alignment = NULL;
820: double h = x, v = y;
821:
822: PDF_PathClose ();
823:
824: /* horizontal justification*/
825: switch (PDF_TextJust) {
826: case LEFT:
827: alignment = "left";
828: break;
829: case CENTRE:
830: alignment = "center";
831: break;
832: case RIGHT:
833: alignment = "right";
834: break;
835: }
836:
837: /* vertical justification*/
838: switch (PDF_TextAngle) {
839: case 1:
840: h += (PDF_fontAscent - PDF_fontDescent) / 2;
841: break; /* vertical text*/
842: default:
843: v -= (PDF_fontAscent - PDF_fontDescent) / 2;
844: break; /* horizontal text*/
845: }
846:
847: if (PDF_TextAngle) {
848: PDF_save(myPDF);
849: PDF_rotate(myPDF, 90);
850: PDF_show_boxed(myPDF, str, v , -h, 0, 0, alignment, NULL);
851: PDF_restore(myPDF);
852: } else {
853: PDF_show_boxed(myPDF, str, h , v, 0, 0, alignment, NULL);
854: }
855:
856: }
857:
858:
859: TERM_PUBLIC int
860: PDF_set_font (char *font)
861: {
862: if (strlen (font) > 0) { /* if available, parse the font specification ("fontname,fontsize")*/
863: short index;
864: char *token,
865: seps[] = ",", *buffer = (char *) malloc (strlen (font) + 1);
866:
867: if (buffer == NULL)
868: return (FALSE);
869: strcpy (buffer, font);
870:
871: for (token = strtok (buffer, seps), index = 1;
872: token != NULL; token = strtok (NULL, seps), index++
873: ) {
874: switch (index) {
875: case 1:
876: strcpy (PDF_fontNameCur, token);
877: break; /* font name*/
878: case 2:
879: PDF_fontSizeCur = atoi (token);
880: break; /* font size*/
881: default:
882: break;
883: }
884: }
885:
886: free (buffer);
887: } else { /* otherwise simply reset the default font*/
888: strcpy (PDF_fontNameCur, PDF_fontNameDef);
889: PDF_fontSizeCur = PDF_fontSizeDef;
890: }
891:
892:
893: PDF_PathClose();
894: PDF_SetFont();
895: return (TRUE);
896: }
897:
898: TERM_PUBLIC void
899: PDF_boxfill(int style, unsigned int x1, unsigned int y1,
900: unsigned int width, unsigned int height)
901: {
902: (void) style; /* unused */
903: PDF_PathClose();
904: PDF_save(myPDF);
905: PDF_setgray(myPDF, 1);
906: PDF_moveto(myPDF, x1, y1);
907: PDF_lineto(myPDF, x1+width, y1);
908: PDF_lineto(myPDF, x1+width, y1+height);
909: PDF_lineto(myPDF, x1, y1+height);
910: PDF_fill(myPDF);
911: PDF_restore(myPDF);
912: }
913:
914: #endif /* TERM_BODY */
915:
916: #ifdef TERM_TABLE
917: TERM_TABLE_START (pdf_driver)
918: "pdf", "PDF (Portable Document File) file driver",
919: 0 /* xmax */ , 0 /* ymax */ , 0 /* vchar */ , 0 /* hchar */ ,
920: 0 /* vtic */ , 0 /* htic */ ,
921: PDF_options, PDF_init, PDF_reset, PDF_text, null_scale, PDF_graphics,
922: PDF_move, PDF_vector, PDF_linetype, PDF_put_text, PDF_text_angle,
923: PDF_justify_text, PDF_point, do_arrow, PDF_set_font, do_pointsize,
924: TERM_BINARY,
925: 0 /* suspend */, 0 /* resume */ , PDF_boxfill, PDF_linewidth
926: TERM_TABLE_END (pdf_driver)
927: #undef LAST_TERM
928: #define LAST_TERM pdf_driver
929: #endif /* TERM_TABLE */
930:
931: #endif /* TERM_PROTO_ONLY */
932:
933: #ifdef TERM_HELP
934: START_HELP (pdf)
935: "1 pdf",
936: "?commands set terminal pdf",
937: "?set terminal pdf",
938: "?set term pdf",
939: "?terminal pdf",
940: "?term pdf",
941: "?pdf",
942: " This terminal produces files in the Adobe Portable Document Format",
943: " (PDF), useable for printing or display with tools like Acrobat Reader",
944: "",
945: " Syntax:",
946: " set terminal pdf {fname \"<font>\"} {fsize <fontsize>}",
947: "",
948: " where <font> is the name of the default font to use (default Helvetica)",
949: " and <fontsize> is the font size (in points, default 12)"
950: END_HELP (pdf)
951: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>