1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
24
25
26 /*
27 * University Copyright- Copyright (c) 1982, 1986, 1988
28 * The Regents of the University of California
29 * All Rights Reserved
30 *
31 * University Acknowledgment- Portions of this document are derived from
32 * software developed by the University of California, Berkeley, and its
33 * contributors.
34 */
35
36 /* from OpenSolaris "draw.c 1.6 05/06/08 SMI" SVr4.0 1.1 */
37
38 /*
39 * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
40 *
41 * Sccsid @(#)draw.c 1.7 (gritter) 3/27/07
42 */
43
44 /*
45 *
46 * Drawing routines used by dpost. Almost no real work is done here. Instead
47 * the required calculations are done in special Postscript procedures that
48 * include:
49 *
50 *
51 * Dl
52 *
53 * x1 y1 x y Dl -
54 *
55 * Starts a new path and then draws a line from the current point
56 * (x, y) to (x1, y1).
57 *
58 * De
59 *
60 * x y a b De -
61 *
62 * Starts a new path and then draws an ellipse that has its left side
63 * at the current point (x, y) and horizontal and vertical axes lengths
64 * given by a and b respectively.
65 *
66 * Da
67 *
68 * x y dx1 dy1 dx2 dy2 Da -
69 *
70 * Starts a new segment and then draws a circular arc from the current
71 * point (x, y) to (x + dx1 + dx2, y + dy1 + dy2). The center of the
72 * circle is at (x + dx1, y + dy1). Arcs always go counter-clockwise
73 * from the starting point to the end point.
74 *
75 * DA
76 *
77 * x y dx1 dy1 dx2 dy2 DA -
78 *
79 * Draws a clockwise arc from (x, y) to (x + dx1 + dx2, y + dy1 + dy2)
80 * with center at (x + dx1, y + dy1). Only needed when we're building
81 * large paths that use arcs and want to control the current point. The
82 * arguments passed to drawarc() will be whatever they would have been
83 * for a counter-clockwise arc, so we need to map them into appropriate
84 * arguments for PostScript's arcn operator. The mapping is,
85 *
86 * x = hpos + dx1' + dx2'
87 * y = vpos + dy1' + dy2'
88 * dx1 = -dx2'
89 * dy1 = -dy2'
90 * dx2 = -dx1'
91 * dy2 = -dy1'
92 *
93 * where primed values represent the drawarc() arguments and (hpos, vpos)
94 * is our current position.
95 *
96 * Ds
97 *
98 * x0 y0 x1 y1 x2 y2 Ds -
99 *
100 * Starts a new segment and then draws a quadratic spline connecting
101 * point ((x0 + x1)/2, (y0 + y1)/2) to ((x1 + x2)/2, (y1 + y2)/2).
102 * The points used in Postscript's curveto procedure are given by,
103 *
104 * x0' = (x0 + 5 * x1) / 6
105 * x1' = (x2 + 5 * x1) / 6
106 * x2' = (x1 + x2) / 2
107 *
108 * with similar equations for the y coordinates.
109 *
110 * By default all the PostScript drawing procedures begin with a newpath (just to
111 * be safe) and end with a stroke, which essentially isolates the path elements
112 * built by the drawing procedures. In order to accommodate big paths built from
113 * smaller pieces each of the PostScript drawing procedures can forced to retain
114 * the path that's being built. That's what happens in beginpath() when an "x X
115 * BeginPath" command is read. beginpath() sets the PostScript variable inpath to
116 * true, and that essentially eliminates the newpath/stroke pair that bracket the
117 * individual pieces. In that case the path is terminated and drawn when dpost
118 * reads an "x X DrawPath" command.
119 *
120 * Early versions of dpost included the PostScript drawing procedures as part of
121 * the prologue, and as a result they were included with every job, even if they
122 * were never used. This version has separated the drawing procedures from the
123 * default prologue (they're now in *drawfile) and only includes them if they're
124 * really needed, which is yet another convenient violation of page independence.
125 * Routine getdraw() is responsible for adding *drawfile to the output file, and
126 * if it can't read *drawfile it continues on as if nothing happened. That means
127 * everything should still work if you append *drawfile to *prologue and then
128 * delete *drawfile.
129 *
130 */
131
132
133 #include <stdio.h>
134 #include <math.h>
135 #include <unistd.h>
136 #include <string.h>
137
138 #include "gen.h" /* general purpose definitions */
139 #include "ext.h" /* external variable definitions */
140
141
142 int gotdraw = FALSE; /* TRUE when *drawfile has been added */
143 int gotbaseline = FALSE; /* TRUE after *baselinefile is added */
144 int inpath = FALSE; /* TRUE if we're putting pieces together */
145
146
147 /*
148 *
149 * All these should be defined in file dpost.c.
150 *
151 */
152
153
154 extern int hpos;
155 extern int vpos;
156 extern int encoding;
157 extern int maxencoding;
158 extern int realencoding;
159
160 extern char *drawfile;
161 extern char *baselinefile;
162 extern FILE *tf;
163
164
165 /*****************************************************************************/
166
167
168 void
getdraw(void)169 getdraw(void)
170
171
172 {
173
174
175 /*
176 *
177 * Responsible for making sure the PostScript drawing procedures are downloaded
178 * from *drawfile. Stuff is done at most once per job, and only if the job needs
179 * them. For now I've decided not to quit if we can't read the drawing file. That
180 * pretty much assumes an old version of prologue is being used that includes all
181 * the drawing procedures.
182 *
183 */
184
185
186 if ( gotdraw == FALSE && access(drawfile, 04) == 0 )
187 doglobal(drawfile);
188
189 if ( tf == stdout )
190 gotdraw = TRUE;
191
192 } /* End of getdraw */
193
194
195 /*****************************************************************************/
196
197
198 void
drawline(int dx,int dy)199 drawline (
200 int dx,
201 int dy /* endpoint is (hpos+dx, vpos+dy) */
202 )
203
204
205 {
206
207
208 /*
209 *
210 * Draws a line from (hpos, vpos) to (hpos+dx, vpos+dy), and leaves the current
211 * position at the endpoint.
212 *
213 */
214
215
216 if ( dx == 0 && dy == 0 )
217 drawcirc(1, 'c');
218 else fprintf(tf, "%d %d %d %d Dl\n", hpos + dx, vpos + dy, hpos, vpos);
219
220 hgoto(hpos+dx); /* where troff expects to be */
221 vgoto(vpos+dy);
222
223 resetpos(); /* not sure where the printer is */
224
225 } /* End of drawline */
226
227
228 /*****************************************************************************/
229
230
231 void
drawcirc(int d,int c)232 drawcirc (
233 int d, /* diameter of the circle */
234 int c
235 )
236
237
238 {
239
240
241 /*
242 *
243 * Draws a circle of diameter d with the left 'side' of the circle at the
244 * current point. After we're finished drawing we move the current position
245 * to the right side.
246 *
247 */
248
249 drawellip(d, d, c == 'C' ? 'E' : 'e');
250
251 } /* End of drawcirc */
252
253
254 /*****************************************************************************/
255
256
257 void
drawellip(int a,int b,int c)258 drawellip (
259 int a,
260 int b, /* axes lengths for the ellipse */
261 int c
262 )
263
264
265 {
266
267
268 /*
269 *
270 * Draws an ellipse having axes lengths horizontally and vertically of a and
271 * b. The left side of the ellipse is at the current point. After we're done
272 * drawing the path we move the current position to the right side.
273 *
274 */
275
276
277 if ( a == 0 && b == 0 )
278 return;
279
280 fprintf(tf, "%d %d %d %d D%c\n", hpos, vpos, a, b, c);
281
282 hgoto(hpos + a); /* where troff expects to be */
283 vgoto(vpos);
284
285 resetpos(); /* not sure where the printer is */
286
287 } /* End of drawellip */
288
289
290 /*****************************************************************************/
291
292
293 void
drawarc(int dx1,int dy1,int dx2,int dy2,int c)294 drawarc (
295 int dx1,
296 int dy1, /* vector from current pos to center */
297 int dx2,
298 int dy2, /* from center to end of the arc */
299 int c /* clockwise if c is A */
300 )
301
302
303 {
304
305
306 /*
307 *
308 * If c isn't set to 'A' a counter-clockwise arc is drawn from the current point
309 * (hpos, vpos) to (hpos+dx1+dx2, vpos+dy1+dy2). The center of the circle is the
310 * point (hpos+dx1, vpos+dy1). If c is 'A' the arc goes clockwise from the point
311 * (hpos+dx1+dx2, vpos+dy1+dy2) to (hpos, vpos). Clockwise arcs are only needed
312 * if we're building a larger path out of pieces that include arcs, and want to
313 * have PostScript manage the path for us. Arguments (for a clockwise arc) are
314 * what would have been supplied if the arc was drawn in a counter-clockwise
315 * direction, and are converted to values suitable for use with PostScript's arcn
316 * operator.
317 *
318 */
319
320
321 if ( (dx1 != 0 || dy1 != 0) && (dx2 != 0 || dy2 != 0) )
322 {
323 if ( c != 'A' )
324 fprintf(tf, "%d %d %d %d %d %d Da\n", hpos, vpos, dx1, dy1, dx2, dy2);
325 else fprintf(tf, "%d %d %d %d %d %d DA\n", hpos+dx1+dx2, vpos+dy1+dy2,
326 -dx2, -dy2, -dx1, -dy1);
327 }
328
329 hgoto(hpos + dx1 + dx2); /* where troff expects to be */
330 vgoto(vpos + dy1 + dy2);
331
332 resetpos(); /* not sure where the printer is */
333
334 } /* End of drawarc */
335
336
337 /*****************************************************************************/
338
339 void
drawspline(FILE * fp,int flag)340 drawspline(
341
342
343 FILE *fp, /* input for point list */
344 int flag /* flag!=1 connect end points */
345 )
346
347
348 {
349
350
351 int x[5000], y[5000];
352 int i, N;
353
354
355 /*
356 *
357 * Spline drawing routine for Postscript printers. The complicated stuff is
358 * handled by procedure Ds, which should be defined in the library file. I've
359 * seen wrong implementations of troff's spline drawing, so fo the record I'll
360 * write down the parametric equations and the necessary conversions to Bezier
361 * cubic splines (as used in Postscript).
362 *
363 *
364 * Parametric equation (x coordinate only):
365 *
366 *
367 * (x2 - 2 * x1 + x0) 2 (x0 + x1)
368 * x = ------------------ * t + (x1 - x0) * t + ---------
369 * 2 2
370 *
371 *
372 * The coefficients in the Bezier cubic are,
373 *
374 *
375 * A = 0
376 * B = (x2 - 2 * x1 + x0) / 2
377 * C = x1 - x0
378 *
379 *
380 * while the current point is,
381 *
382 * current-point = (x0 + x1) / 2
383 *
384 * Using the relationships given in the Postscript manual (page 121) it's easy to
385 * see that the control points are given by,
386 *
387 *
388 * x0' = (x0 + 5 * x1) / 6
389 * x1' = (x2 + 5 * x1) / 6
390 * x2' = (x1 + x2) / 2
391 *
392 *
393 * where the primed variables are the ones used by curveto. The calculations
394 * shown above are done in procedure Ds using the coordinates set up in both
395 * the x[] and y[] arrays.
396 *
397 * A simple test of whether your spline drawing is correct would be to use cip
398 * to draw a spline and some tangent lines at appropriate points and then print
399 * the file.
400 *
401 */
402
403
404 for ( N = 2; N < sizeof(x)/sizeof(x[0]); N++ )
405 if (fscanf(fp, "%d %d", &x[N], &y[N]) != 2)
406 break;
407
408 x[0] = x[1] = hpos;
409 y[0] = y[1] = vpos;
410
411 for (i = 1; i < N; i++) {
412 x[i+1] += x[i];
413 y[i+1] += y[i];
414 } /* End for */
415
416 x[N] = x[N-1];
417 y[N] = y[N-1];
418
419 for (i = ((flag!=1)?0:1); i < ((flag!=1)?N-1:N-2); i++)
420 fprintf(tf, "%d %d %d %d %d %d Ds\n", x[i], y[i], x[i+1], y[i+1], x[i+2], y[i+2]);
421
422 hgoto(x[N]); /* where troff expects to be */
423 vgoto(y[N]);
424
425 resetpos(); /* not sure where the printer is */
426
427 } /* End of drawspline */
428
429
430 /*****************************************************************************/
431
432
433 void
beginpath(char * buf,int copy)434 beginpath (
435 char *buf, /* whatever followed "x X BeginPath" */
436 int copy /* ignore *buf if FALSE */
437 )
438
439
440 {
441
442
443 /*
444 *
445 * Called from devcntrl() whenever an "x X BeginPath" command is read. It's used
446 * to mark the start of a sequence of drawing commands that should be grouped
447 * together and treated as a single path. By default the drawing procedures in
448 * *drawfile treat each drawing command as a separate object, and usually start
449 * with a newpath (just as a precaution) and end with a stroke. The newpath and
450 * stroke isolate individual drawing commands and make it impossible to deal with
451 * composite objects. "x X BeginPath" can be used to mark the start of drawing
452 * commands that should be grouped together and treated as a single object, and
453 * part of what's done here ensures that the PostScript drawing commands defined
454 * in *drawfile skip the newpath and stroke, until after the next "x X DrawPath"
455 * command. At that point the path that's been built up can be manipulated in
456 * various ways (eg. filled and/or stroked with a different line width).
457 *
458 * String *buf is unnecessary and is only included for compatibility with an early
459 * verion of that's still in use. In that version "x X BeginObject" marked the
460 * start of a graphical object, and whatever followed it was passed along in *buf
461 * and copied to the output file. Color selection is one of the options that's
462 * available in parsebuf(), so if we get here we add *colorfile to the output
463 * file before doing anything important.
464 *
465 */
466
467
468
469 if ( inpath == FALSE ) {
470 endtext();
471 getdraw();
472 getcolor();
473 fprintf(tf, "gsave\n");
474 fprintf(tf, "newpath\n");
475 fprintf(tf, "%d %d m\n", hpos, vpos);
476 fprintf(tf, "/inpath true def\n");
477 if ( copy == TRUE )
478 fprintf(tf, "%s", buf);
479 inpath = TRUE;
480 } /* End if */
481
482 } /* End of beginpath */
483
484
485 /*****************************************************************************/
486
487
488 void
drawpath(char * buf,int copy)489 drawpath(char *buf, int copy)
490
491
492 {
493
494
495 /*
496 *
497 * Called from devcntrl() whenever an "x X DrawPath" command is read. It marks the
498 * end of the path started by the last "x X BeginPath" command and uses whatever
499 * has been passed along in *buf to manipulate the path (eg. fill and/or stroke
500 * the path). Once that's been done the drawing procedures are restored to their
501 * default behavior in which each drawing command is treated as an isolated path.
502 * The new version (called after "x X DrawPath") has copy set to FALSE, and calls
503 * parsebuf() to figure out what goes in the output file. It's a feeble attempt
504 * to free users and preprocessors (like pic) from having to know PostScript. The
505 * comments in parsebuf() describe what's handled.
506 *
507 * In the early version a path was started with "x X BeginObject" and ended with
508 * "x X EndObject". In both cases *buf was just copied to the output file, and
509 * was expected to be legitimate PostScript that manipulated the current path.
510 * The old escape sequence will be supported for a while (for Ravi), and always
511 * call this routine with copy set to TRUE.
512 *
513 *
514 */
515
516
517 if ( inpath == TRUE ) {
518 if ( copy == TRUE )
519 fprintf(tf, "%s", buf);
520 else parsebuf(buf);
521 fprintf(tf, "grestore\n");
522 fprintf(tf, "/inpath false def\n");
523 reset();
524 inpath = FALSE;
525 } /* End if */
526
527 } /* End of drawpath */
528
529
530 /*****************************************************************************/
531
532
533 void
parsebuf(char * buf)534 parsebuf (
535 char *buf /* whatever followed "x X DrawPath" */
536 )
537
538
539 {
540
541
542 char *p; /* usually the next token */
543 char *p1; /* for grabbing arguments */
544 char *pend; /* end of the original string (ie. *buf) */
545 int gsavelevel = 0; /* non-zero if we've done a gsave */
546
547 /*
548 *
549 * Simple minded attempt at parsing the string that followed an "x X DrawPath"
550 * command. Everything not recognized here is simply ignored - there's absolutely
551 * no error checking and what was originally in buf is clobbered by strtok().
552 * A typical *buf might look like,
553 *
554 * gray .9 fill stroke
555 *
556 * to fill the current path with a gray level of .9 and follow that by stroking the
557 * outline of the path. Since unrecognized tokens are ignored the last example
558 * could also be written as,
559 *
560 * with gray .9 fill then stroke
561 *
562 * The "with" and "then" strings aren't recognized tokens and are simply discarded.
563 * The "stroke", "fill", and "wfill" force out appropriate PostScript code and are
564 * followed by a grestore. In otherwords changes to the grahics state (eg. a gray
565 * level or color) are reset to default values immediately after the stroke, fill,
566 * or wfill tokens. For now "fill" gets invokes PostScript's eofill operator and
567 * "wfill" calls fill (ie. the operator that uses the non-zero winding rule).
568 *
569 * The tokens that cause temporary changes to the graphics state are "gray" (for
570 * setting the gray level), "color" (for selecting a known color from the colordict
571 * dictionary defined in *colorfile), and "line" (for setting the line width). All
572 * three tokens can be extended since strncmp() makes the comparison. For example
573 * the strings "line" and "linewidth" accomplish the same thing. Colors are named
574 * (eg. "red"), but must be appropriately defined in *colorfile. For now all three
575 * tokens must be followed immediately by their single argument. The gray level
576 * (ie. the argument that follows "gray") should be a number between 0 and 1, with
577 * 0 for black and 1 for white.
578 *
579 * To pass straight PostScript through enclose the appropriate commands in double
580 * quotes. Straight PostScript is only bracketed by the outermost gsave/grestore
581 * pair (ie. the one from the initial "x X BeginPath") although that's probably
582 * a mistake. Suspect I may have to change the double quote delimiters.
583 *
584 */
585
586
587 pend = buf + strlen(buf);
588 p = strtok(buf, " \n");
589
590 while ( p != NULL ) {
591 if ( gsavelevel == 0 ) {
592 fprintf(tf, "gsave\n");
593 gsavelevel++;
594 } /* End if */
595 if ( strcmp(p, "stroke") == 0 ) {
596 fprintf(tf, "closepath stroke\ngrestore\n");
597 gsavelevel--;
598 } else if ( strcmp(p, "openstroke") == 0 ) {
599 fprintf(tf, "stroke\ngrestore\n");
600 gsavelevel--;
601 } else if ( strcmp(p, "fill") == 0 ) {
602 fprintf(tf, "eofill\ngrestore\n");
603 gsavelevel--;
604 } else if ( strcmp(p, "wfill") == 0 ) {
605 fprintf(tf, "fill\ngrestore\n");
606 gsavelevel--;
607 } else if ( strcmp(p, "sfill") == 0 ) {
608 fprintf(tf, "eofill\ngrestore\ngsave\nstroke\ngrestore\n");
609 gsavelevel--;
610 } else if ( strncmp(p, "gray", strlen("gray")) == 0 ) {
611 p1 = strtok(NULL, " \n");
612 fprintf(tf, "%s setgray\n", p1);
613 } else if ( strncmp(p, "color", strlen("color")) == 0 ) {
614 p1 = strtok(NULL, " \n");
615 fprintf(tf, "/%s _setcolor\n", p1);
616 } else if ( strncmp(p, "line", strlen("line")) == 0 ) {
617 p1 = strtok(NULL, " \n");
618 fprintf(tf, "%s resolution mul 2 div setlinewidth\n", p1);
619 } else if ( strncmp(p, "reverse", strlen("reverse")) == 0 )
620 fprintf(tf, "reversepath\n");
621 else if ( *p == '"' ) {
622 for ( ; gsavelevel > 0; gsavelevel-- )
623 fprintf(tf, "grestore\n");
624 if ( (p1 = p + strlen(p)) < pend )
625 *p1 = ' ';
626 p = strtok(p, "\"\n");
627 fprintf(tf, "%s\n", p);
628 } /* End else */
629 p = strtok(NULL, " \n");
630 } /* End while */
631
632 for ( ; gsavelevel > 0; gsavelevel-- )
633 fprintf(tf, "grestore\n");
634
635 } /* End of parsebuf */
636
637
638 /*****************************************************************************/
639
640
641 void
getbaseline(void)642 getbaseline(void)
643
644
645 {
646
647
648 /*
649 *
650 * Responsible for making sure the PostScript procedures needed for printing text
651 * along an arbitrary baseline are downloaded from *baselinefile. Done at most
652 * once per job, and only if the the stuff is really used.
653 *
654 */
655
656
657 if ( gotbaseline == FALSE && access(baselinefile, 04) == 0 )
658 doglobal(baselinefile);
659
660 if ( tf == stdout )
661 gotbaseline = TRUE;
662
663 } /* End of getbaseline */
664
665
666 /*****************************************************************************/
667
668
669 void
newbaseline(char * buf)670 newbaseline (
671 char *buf /* whatever followed "x X NewBaseline" */
672 )
673
674
675 {
676
677
678 char *p; /* for eliminating white space etc. */
679
680
681 /*
682 *
683 * Called from devcntrl() whenever an "x X NewBaseline" command is recognized. We
684 * assume whatever is in *buf is a set of parametric equations that describe the
685 * new baseline. Equations for x(t), y(t), dx/dt, and dy/dt must be written in
686 * PostScript, bracketed by { and } characters, and supplied in exactly that order.
687 * In particular the equation for x must come first in *buf and it ends up as the
688 * last one on the stack, while the equation for dy/dt comes last (in *buf) and
689 * ends up on the top of the PostScript stack. For example if *buf is given by,
690 *
691 * {} {180 mul 3.1416 div cos} {pop 1} {180 mul 3.1416 div sin neg}
692 *
693 * text will be printed along the curve y = cos(x).
694 *
695 * Angles given in radians must be converted to degrees for the PostScript trig
696 * functions, and things are scaled so that 1 unit maps into 1 inch. In the last
697 * example the cosine curve that describes the baseline has an amplitude of 1 inch.
698 * As another example of this rather confusing syntax if *buf is,
699 *
700 * {} {} {pop 1} {pop 1}
701 *
702 * the baseline will be the 45 degree line y = x.
703 *
704 * When any of the four functions is used they're called with a single number on
705 * the stack that's equal to the current value of the parameter t. The coordinate
706 * system axes run parallel to the PostScript coordinate system that's currently
707 * being used.
708 *
709 */
710
711
712 for ( p = buf; *p; p++ ) /* eliminate trailing '\n' */
713 if ( *p == '\n' ) {
714 *p = '\0';
715 break;
716 } /* End if */
717
718 for ( p = buf; *p && (*p == ' ' || *p == ':'); p++ ) ;
719
720 if ( *p != '\0' ) { /* something's there */
721 endtext();
722 getbaseline();
723 fprintf(tf, "mark resolution %s newbaseline\n", p);
724 t_sf(1);
725 resetpos();
726 } /* End if */
727
728 } /* End of newbaseline */
729
730
731 /*****************************************************************************/
732
733
734 void
drawtext(char * buf)735 drawtext (
736 char *buf /* whatever followed "x X DrawText */
737 )
738
739
740 {
741
742
743 char *p; /* for eliminating white space etc. */
744
745
746 /*
747 *
748 * Called from devcntrl() whenever an "x X DrawText command is recognized. *buf
749 * should contain three arguments in the following order. First comes the text we
750 * want to print along the current baseline. Right now the string should be given
751 * as a PostScript string using characters '(' and ')' as the delimiters. Next in
752 * *buf comes a justification mode that can be the words left, right, or center.
753 * Last comes a number that represents the starting value of the parameter t that's
754 * given as the argument to the parametric equations that describe the current
755 * baseline. For example if *buf is given by,
756 *
757 * (hello world) left .5
758 *
759 * hello world will be printed along the path described by the current baseline
760 * and left justified at whatever (x(.5), y(.5)) happens to be. Usually will be
761 * preceeded by an "x X NewBaseline" call that defines the current baseline. The
762 * origin of the coordinate system used by the parametric equations will be the
763 * current point.
764 *
765 */
766
767
768 for ( p = buf; *p; p++ ) /* eliminate trailing '\n' */
769 if ( *p == '\n' ) {
770 *p = '\0';
771 break;
772 } /* End if */
773
774 for ( p = buf; *p && (*p == ' ' || *p == ':'); p++ ) ;
775
776 if ( *p != '\0' ) { /* something's there */
777 endtext();
778 getbaseline();
779 xymove(hpos, vpos);
780 fprintf(tf, "mark %s drawfunnytext\n", p);
781 resetpos();
782 } /* End if */
783
784 } /* End of drawtext */
785
786
787 /*****************************************************************************/
788
789
790 void
settext(char * buf)791 settext(char *buf)
792
793
794 {
795
796
797 char *p;
798
799
800 /*
801 *
802 * Does whatever is needed to ensure any text that follows will be set along the
803 * curve described by the PostScript procedures listed in *buf. If *buf doesn't
804 * contain anything useful (eg. just a newline) things are restored to whatever
805 * they originally were. Doesn't work well if we try to start in the middle of a
806 * line of text.
807 *
808 * The parametric equations needed are,
809 *
810 * x = f(t)
811 * y = g(t)
812 * dx/dt = f'(t)
813 * dy/dt = g'(t)
814 *
815 * and must be given as proper PostScript procedures. The equation for x must come
816 * first (ie. it ends up on the bottom of the stack) and the equation for dy/dt
817 * must be given last (ie. it ends up on top of the stack). For example if *buf
818 * is given by,
819 *
820 * {} {180 mul 3.1416 div cos} {pop 1} {180 mul 3.1416 div sin neg}
821 *
822 * text will be set along the curve y=cos(x).
823 *
824 */
825
826
827 endtext();
828 getbaseline();
829
830 for ( p = buf; *p && *p == ' '; p++ ) ;
831
832 if ( *p && *p != '\n' ) {
833 encoding = maxencoding + 2;
834 fprintf(tf, "mark resolution %s newbaseline\n", buf);
835 } else encoding = realencoding;
836
837 fprintf(tf, "%d setdecoding\n", encoding);
838 resetpos();
839
840 } /* End of settext */
841
842
843 /*****************************************************************************/
844
845