metafun-text.tex /size: 51 Kb    last modification: 2023-12-21 09:43
1% language=us runpath=texruns:manuals/metafun
2
3\startcomponent metafun-text
4
5\environment metafun-environment
6
7\startchapter[reference=sec:typesetting,title={Typesetting in \METAPOST}]
8
9\startintro
10
11It is said that a picture tells more than a thousand words. So you might expect
12that text in graphics becomes superfluous. Out of experience we can tell you that
13this is not the case. In this chapter we explore the ways to add text to
14\METAPOST\ graphics, and let you choose whether or not to have it typeset by
15\TEX.
16
17\stopintro
18
19\startsection[title={The process}]
20
21\index{text}
22
23You can let \METAPOST\ process text that is typeset by \TEX. Such text is first
24embedded in the \METAPOST\ file in the following way:
25
26\starttyping
27btex Some text to be typeset by \TEX etex
28\stoptyping
29
30This returns a picture, but only after \METAPOST\ has made sure that \TEX\ has
31converted it into something useful. This process of conversion is slightly system
32dependent and even a bit obscure. Traditional \METAPOST\ calls a program that
33filters the \type {btex}|\unknown|\type {etex} commands, next it calls \TEX\ by
34passing the output routine, in order to make sure that each piece of text ends up
35on its own page, and afterwards it again calls a program that converts the \DVI\
36pages into \METAPOST\ pictures. In \LUATEX's \MPLIB\ a different route is
37followed.
38
39In \CONTEXT\ \MKII, when using \WEBC, you can generate the graphics at run||time.
40This takes more time than processing the graphics afterwards, but has the
41advantage that \TEX\ knows immediately what graphic it is dealing with. When
42enabled, \CONTEXT\ will call either \METAPOST, or, when the graphic contains
43\type {btex}||\type {etex} commands, call \TEXEXEC, which in turn makes sure that
44the right auxiliary programs are executed.
45
46In \CONTEXT\ \MKIV\ you won't notice this at all because everything is tightly
47integrated with \LUATEX's \MPLIB. This has an enormous speed gain: when this
48manual had about 425 pages, on my laptop with mobile 3840QM processor, one run of
49this document takes 18 seconds (14.5 with \LUAJITTEX) and that includes loading a
50bunch of (outline) fonts and processing some 2200 \METAPOST\ images. While
51writing the first version of this manual runtime was upto 50 times slower for
52half the number of pages so compared to \MKII\ we have gained a lot.
53
54\startFLOWchart[metatex]
55    \startFLOWcell
56      \name       {script 1}
57      \location   {1,1}
58      \shape      {action}
59      \text       {\type{context}}
60      \connection [rl] {context 1}
61    \stopFLOWcell
62    \startFLOWcell
63      \name       {context 1}
64      \location   {2,1}
65      \shape      {action}
66      \text       {\CONTEXT}
67      \connection [bt] {metapost 1}
68      \connection [rl] {script 2}
69    \stopFLOWcell
70    \startFLOWcell
71      \name       {metapost 1}
72      \location   {2,2}
73      \shape      {action}
74      \text       {\METAPOST}
75    \stopFLOWcell
76    \startFLOWcell
77      \name       {script 2}
78      \location   {3,1}
79      \shape      {action}
80      \text       {\type{context}}
81      \connection [rl] {context  2}
82      \connection [bt] {metapost 2}
83    \stopFLOWcell
84    \startFLOWcell
85      \name       {context 2}
86      \location   {4,1}
87      \shape      {action}
88      \text       {\CONTEXT}
89    \stopFLOWcell
90    \startFLOWcell
91      \name       {metapost 2}
92      \location   {3,2}
93      \shape      {action}
94      \text       {\METAPOST}
95    \stopFLOWcell
96\stopFLOWchart
97
98\startplacefigure[title={How \TEX\ and \METAPOST\ work together.}]
99    \FLOWchart[metatex]
100\stopplacefigure
101
102\stopsection
103
104\startsection[title={Environments}]
105
106\index{environments}
107
108In case you want to pass code that is shared by all \type {btex}||\type {etex}
109pictures, \METAPOST\ provides:
110
111\starttyping
112verbatimtex \DefineSomeCommands etex ;
113\stoptyping
114
115However, in \CONTEXT\ one has a better mechanism available. In \CONTEXT\ \MKII\
116the advised method is passing environments. The best way to pass them is the
117following. As an example we switch to the 15 basic \POSTSCRIPT\ fonts.
118
119\startbuffer[pos]
120\startMPenvironment
121  \usetypescript[palatino][texnansi] % mkii has encodings
122  \setupbodyfont[palatino]
123\stopMPenvironment
124\stopbuffer
125
126\typebuffer[pos]
127
128This means that in code like the following, a Palatino font will be used.
129
130\starttyping
131\startMPcode
132draw btex Meta is a female lion! etex
133  xysized (\the\textwidth,\the\textheight) ;
134\stopMPcode
135\stoptyping
136
137However, in \CONTEXT\ \MKIV\ this method is no longer recomended as all
138processing happens in the same run anyway.
139
140% beware: extensive scaling can make acrobat crash and okular drop the !
141
142\startbuffer[lioncode]
143\startMPcode
144numeric w, h ; w := \the\textwidth ; h := w/2 ;
145
146picture p ; p := btex \colored[r=.375,g=.375]{Meta is a female lion!} etex
147    xysized (w,h) ;
148picture q ; q := btex \colored[r=.625]       {Meta is a female lion!} etex
149    xysized (w,h) ;
150
151path b ; b := boundingbox p ; draw p ;
152
153for i=(.28w,.90h),(.85w,.90h),(w,.05h) :
154  picture r ; r := q ;
155  path s ; s := (fullsquare xscaled .05w yscaled .4h) shifted i ;
156  clip r to s ; draw r ; % draw s ;
157endfor ;
158
159setbounds currentpicture to b ;
160\stopMPcode
161\stopbuffer
162
163\typebuffer[lioncode]
164
165\in {Figure} [lionclip] shows the previous sentence in a slightly different look.
166You may consider coloring the dots to be an exercise in clipping.
167
168\getbuffer[pos]
169
170\placefigure
171  [here][lionclip]
172  {An example of clipping.}
173  {\getbuffer[lioncode]}
174
175\resetMPenvironment
176
177An environment can be reset with \typ {\resetMPenvironment} or by passing \type
178{reset} as first argument:
179
180\starttyping
181\startMPenvironment[reset]
182  \usetypescript[postscript][texnansi] % mkii
183  \setupbodyfont[postscript]
184\stopMPenvironment
185\stoptyping
186
187So, to summarize: if you're using \CONTEXT\ \MKIV\ you might as well forgot what
188you just read.
189
190\stopsection
191
192\startsection[title={Labels}]
193
194\index{labels}
195
196In \METAPOST\ you can use the \type {label} macro to position text at certain
197points.
198
199\starttyping
200label("x", origin) ;
201\stoptyping
202
203The font and scale are determined by two variables, \type {defaultfont} and \type
204{defaultscale}, the former expecting the name of a font in the form of a string,
205the latter expecting a numeric to be used in the scaling of the font. Should you
206choose not to set these yourself, they default to \type {"Mono"} and \type
207{1.0}, respectively. However, you can change the defaults as follows:
208
209\starttyping
210defaultfont  := "texgyrepagella-regular*default" ;
211defaultscale := 1.2 ;
212\stoptyping
213
214These settings selects Pagella at about 12pt. You can also set these variables
215to \CONTEXT\ related values. For \CONTEXT\ graphics they are set to:
216
217\starttyping
218defaultfont  := "\truefontname{Regular}*default" ;
219defaultscale := \the\bodyfontsize/10 ;
220\stoptyping
221
222This means that they will adapt themselves to the current body font (in this
223document we get \truefontname{Regular}) and the current size of the bodyfont
224(here \the\bodyfontsize/10).
225
226\stopsection
227
228\startsection[title={\TeX\ text}]
229
230\index{text}
231
232In the next example we will use a special mechanism for building graphics step by
233step. The advantage of this method is that we can do intermediate calculations in
234\TEX. Our objective is to write a macro that draws text along a circular path.
235While doing so we want to achieve the following:
236
237\startitemize[packed]
238\item  the text should be properly kerned, i.e.\ the
239       spacing between characters should be optimal,
240\item  the position on the circle should vary, and
241\item  the radius of the circle should vary.
242\stopitemize
243
244This implementation is not the most straightforward one, but by doing it step by
245step, at least we see what is involved. Later, we will see a better method. If
246you run these examples yourself, you must make sure that the \TEX\ environment of
247your document matches the one used by \METAPOST.
248
249We let the bodyfont match the font used in this document, and define \type
250{RotFont} to be the regular typeface, the one you are reading right now, but
251bold.
252
253\startbuffer
254\definefont[RotFont][RegularBold*default]
255\stopbuffer
256
257\typebuffer \getbuffer
258
259Since \METAPOST\ is unaware of kerning, we have to use \TEX\ to keep track of the
260positions. We will split the text into tokens (often characters) and store the
261result in an array of pictures (\type {pic}). We will also store the accumulated
262width in an array (\type {len}). The number of characters is stored in~\type {n}.
263In a few paragraphs we will see why the other arrays are needed.
264
265While defining the graphic, we need \TEX\ to do some calculations. Therefore, we
266will use \typ {\startMPdrawing ... \stopMPdrawing} to stepwise construct the
267definition. The basic pattern we will follow is:
268
269\starttyping
270\resetMPdrawing
271\startMPdrawing
272  metapost code
273\stopMPdrawing
274tex code
275\startMPdrawing
276  metapost code
277\stopMPdrawing
278\MPdrawingdonetrue
279\getMPdrawing
280\stoptyping
281
282In the process, we will use a few variables. We will store the individual
283characters of the text in the variable \type {pic}, its width in \type {wid} and
284the length of the string so far in \type {len}. Later we will use the \type {pos}
285array to store the position where a character ends up. The variable \type {n}
286holds the number of tokens.
287
288\startbuffer[init]
289\resetMPdrawing
290\startMPdrawing
291  picture pic[] ;
292  numeric wid[], len[], pos[], n ;
293  wid[0] := len[0] := pos[0] := n := 0 ;
294\stopMPdrawing
295\stopbuffer
296
297\typebuffer[init]
298
299We also started fresh by resetting the drawing. From now on, each start command
300will add some more to this graphic. The next macro is responsible for collecting
301the data. Each element is passed on to \TEX, using the \type {btex} construct.
302So, \METAPOST\ itself will call \TEX !
303
304\startbuffer[toks]
305\def\whatever#1%
306  {\appendtoks#1\to\MPtoks
307   \setbox\MPbox=\hbox{\bfd\the\MPtoks}%
308   \startMPdrawing
309     n := n + 1 ; len[n] := \the\wd\MPbox ;
310   \stopMPdrawing
311   \startMPdrawing[-]
312     pic[n] := textext("\bfd\setstrut\strut#1") ;
313     pic[n] := pic[n] shifted - llcorner pic[n] ;
314   \stopMPdrawing}
315
316\handletokens MetaPost is Fun!\with\whatever
317\stopbuffer
318
319\typebuffer[toks]
320
321We use the low level \CONTEXT\ macro \type {\appendtoks} to extend the token list
322\type {\MPtoks}. The \type {\handletokens} macro passes each token (character) of
323\typ {MetaPost is Fun!} to the macro \type {\whatever}. The tokens are appended
324to the token register \type {\MPtoks} (already defined). Then we typeset the
325content of \type {\MPtoks} in \type {\MPbox} (also already defined). The width of
326the box is passed to \METAPOST\ and stored in \type {len}.
327
328By default the content of the drawing is expanded, which means that the macro is
329replaced by its current meaning, so the current width ends up in the \METAPOST\
330file. The next part of the drawing, starting with \type {btex}, puts the token in
331a picture. This time we don't expand the drawing, since we want to pass font
332information. Here, the \type {[-]} suppresses expansion of \typ {btex \bfd #1
333etex}. The process is iterated by \type {\handletokens} for each character of the
334text \typ {MetaPost is Fun!}.
335
336Before we typeset the text, now available in pieces in \type {pic}, in a circle,
337we will first demonstrate what they look like. You may like to take a look at the
338file \type {mpgraph.mp} to see what is passed to \METAPOST.
339
340\startbuffer[test]
341\startMPdrawing
342  pair len ; len := origin ;
343  for i=1 upto n :
344    draw pic[i] shifted len ;
345    draw boundingbox pic[i] shifted len
346      withpen pencircle scaled .25pt withcolor red ;
347    len := len+(xpart urcorner pic[i]-xpart llcorner pic[i],0) ;
348  endfor ;
349\stopMPdrawing
350\stopbuffer
351
352\typebuffer[test]
353
354\startbuffer[show]
355\MPdrawingdonetrue\getMPdrawing
356\stopbuffer
357
358We can call up this drawing with \type {\getMPdrawing}, but first we inform the
359compiler that our \METAPOST\ drawing is completed.
360
361\typebuffer[show]
362
363This results in:
364
365\startlinecorrection[blank]
366\getbuffer[init,toks,test,show]
367\stoplinecorrection
368
369Compare this text with the text as typeset by \TEX:
370
371\blank \start \bfd MetaPost is Fun!\par \stop \blank
372
373and you will see that the text produced by \METAPOST\ is not properly kerned.
374When putting characters after each other, \TEX\ uses the information available in
375the font, to optimize the spacing between characters, while \METAPOST\ looks at
376characters as separate entities. But, since we have stored the optimal spacing in
377\type {len}, we can let \METAPOST\ do a better job. Let's first calculate the
378correction needed.
379
380\startbuffer[kern]
381\startMPdrawing
382  for i=1 upto n :
383    wid[i] := abs(xpart urcorner pic[i] - xpart llcorner pic[i]) ;
384    pos[i] := len[i]-wid[i] ;
385  endfor ;
386\stopMPdrawing
387\stopbuffer
388
389\typebuffer[kern]
390
391This compares well to the text as typeset by \TEX:
392
393\blank \start \bfd MetaPost is Fun!\par \stop \blank
394
395We can now use the values in \type {pos} to position the pictures according to
396what \TEX\ considered to be the best (relative) position.
397
398\startbuffer[test]
399\startMPdrawing
400  for i=1 upto n :
401    draw pic[i] shifted (pos[i],0) ;
402    draw boundingbox pic[i] shifted (pos[i],0)
403      withpen pencircle scaled .25pt withcolor red ;
404  endfor ;
405\stopMPdrawing
406\stopbuffer
407
408\typebuffer[test]
409
410That this correction is adequate, is demonstrated in the next graphic. If you
411look closely, you will see that for instance the \quote {o} is moved to the left,
412under the capital \quote {P}.
413
414\startlinecorrection[blank]
415\getbuffer[init,toks,kern,test,show]
416\stoplinecorrection
417
418When we want to position the pictures along a circle, we need to apply some
419rotations, especially because we want to go clockwise. Since we don't want to use
420\quote {complicated} math or more advanced \METAPOST\ code yet, we will do it in
421steps.
422
423\startbuffer[swap]
424\startMPdrawing
425  for i=1 upto n:
426    pic[i] := pic[i] rotatedaround(origin,-270) ;
427  endfor ;
428\stopMPdrawing
429\stopbuffer
430
431\typebuffer[swap]
432
433\startlinecorrection[blank]
434\getbuffer[init,toks,kern,swap,test,show]
435\stoplinecorrection
436
437\startbuffer[cent]
438\startMPdrawing
439  for i=1 upto n :
440    pic[i] := pic[i]
441      shifted (0,ypart -.5[ulcorner pic[i],llcorner pic[i]]) ;
442  endfor ;
443\stopMPdrawing
444\stopbuffer
445
446We will now center the pictures around the baseline. Centering comes down to
447shifting over half the height of the picture. This can be expressed by:
448
449\starttyping
450ypart -.5[ulcorner pic[i],llcorner pic[i]]
451\stoptyping
452
453but different ways of calculating the distance are possible
454too.
455
456\typebuffer[cent]
457
458So, now we have:
459
460\startlinecorrection[blank]
461\getbuffer[init,toks,kern,swap,cent,test,show]
462\stoplinecorrection
463
464When we typeset on a (half) circle, we should map the actual length onto a
465partial circle. We denote the radius with an~\type {r} and shift the pictures to
466the left.
467
468\startbuffer[shif]
469\startMPdrawing
470  numeric r ; r := len[n]/pi ;
471  for i=1 upto n :
472    pic[i] := pic[i] shifted (-r,0) ;
473  endfor ;
474\stopMPdrawing
475\stopbuffer
476
477\typebuffer[shif]
478
479You can now use the following code to test the current state of the pictures. Of
480course this code should not end up in the final definitions.
481
482\startbuffer[test]
483\startMPdrawing
484  draw origin
485    withpen pencircle scaled 5pt withcolor red ;
486  for i=1 upto n :
487    draw pic[i] ;
488    draw boundingbox pic[i]
489      withpen pencircle scaled .25pt withcolor red ;
490  endfor ;
491\stopMPdrawing
492\stopbuffer
493
494\typebuffer[test]
495
496\startlinecorrection[blank]
497\getbuffer[init,toks,kern,swap,cent,shif,test,show]
498\stoplinecorrection
499
500Later we will write a compact, efficient macro to take care of rotation. However,
501for the moment, so as not to overwhelm you with complicated code, we will rotate
502each individual picture with the following code fragment.
503
504\startbuffer[rots]
505\startMPdrawing
506  numeric delta, extra, radius, rot[] ;
507
508  delta  := extra := radius := 0 ;
509
510  for i=1 upto n :
511    rot[i] := extra+delta-((pos[i]+.5wid[i])/len[n])*(180+2delta) ;
512  endfor ;
513\stopMPdrawing
514\stopbuffer
515
516\typebuffer[rots]
517
518Here we introduce a few variables that we can use later to tune the result a bit.
519With \type {delta}, the space between the characters can be increased, while
520\type {extra} rotates the whole string around the origin. The \type {radius}
521variable can be used to increase the distance to the origin. Without these
522variables, the assignment would have been:
523
524\starttyping
525rot[i] := ((pos[i]+.5wid[i])/len[n])*180 ;
526\stoptyping
527
528Placing the pictures is now rather easy:
529
530\startbuffer[done]
531\startMPdrawing
532  for i=1 upto n :
533    draw pic[i] shifted (-radius,0) rotatedaround(origin,rot[i]) ;
534  endfor ;
535\stopMPdrawing
536\stopbuffer
537
538\typebuffer[done]
539
540The pictures are now positioned on half a circle, properly kerned.
541
542\startlinecorrection[blank]
543\getbuffer[init,toks,kern,swap,cent,shif,rots,done,show]
544\stoplinecorrection
545
546A bit more insight is given in the next picture:
547
548\startbuffer[test]
549\startMPdrawing
550  def moved(expr i) =
551    shifted (-radius,0) rotatedaround(origin,rot[i])
552  enddef ;
553  pickup pencircle scaled .5pt ;
554  for i=1 upto n :
555    draw pic[i] moved(i) ;
556    draw boundingbox pic[i] moved(i) withcolor red ;
557    draw origin -- center pic[i] moved(i) withcolor green ;
558  endfor ;
559  draw tcircle scaled 2r withcolor blue ;
560\stopMPdrawing
561\stopbuffer
562
563\startlinecorrection[blank]
564\getbuffer[init,toks,kern,swap,cent,shif,rots,test,show]
565\stoplinecorrection
566
567This was defined as follows. The path variable \type {tcycle} is predefined to
568the top half of a fullcircle.
569
570\typebuffer[test]
571
572We will now package all of this into a nice, efficient macro, using, of course,
573the predefined scratch registers \type {\MPtoks} and \type {\MPbox}. First we
574define the token processor. Note again the expansion inhibition switch \type
575{[-]}.
576
577\startbuffer
578\def\processrotationtoken#1%
579  {\appendtoks#1\to\MPtoks
580   \setbox\MPbox=\hbox{\RotFont\the\MPtoks}%
581   \startMPdrawing
582     n := n + 1 ; len[n] := \the\wd\MPbox ;
583   \stopMPdrawing
584   \startMPdrawing[-]
585     pic[n] := textext("\RotFont\setstrut\strut#1") ;
586     pic[n] := pic[n] shifted - llcorner pic[n] ;
587   \stopMPdrawing}
588\stopbuffer
589
590\typebuffer
591
592\getbuffer
593
594The main macro is a bit more complicated but by using a few scratch numerics, we
595can keep it readable.
596
597\startbuffer
598\def\rotatetokens#1#2#3#4% delta extra radius tokens
599  {\vbox\bgroup
600   \MPtoks\emptytoks
601   \resetMPdrawing
602   \startMPdrawing
603     picture pic[] ;
604     numeric wid, len[], rot ;
605     numeric delta, extra, radius, n, r ;
606     len[0] := n := 0 ;
607     delta  := #1 ; extra := #2 ; radius := #3 ;
608   \stopMPdrawing
609   \handletokens#4\with\processrotationtoken
610   \startMPdrawing
611     r := len[n]/pi ;
612     for i=1 upto n :
613       wid := abs(xpart lrcorner pic[i] -
614                  xpart llcorner pic[i]) ;
615       rot := extra + delta -
616              ((len[i]-.5wid)/len[n]) * (180+2delta) ;
617       draw pic[i]
618         rotatedaround (origin,-270) shifted (-r-radius,
619         ypart -.5[ulcorner pic[i], llcorner pic[i]])
620         rotatedaround (origin,rot) ;
621     endfor ;
622   \stopMPdrawing
623   \MPdrawingdonetrue
624   \getMPdrawing
625   \resetMPdrawing
626   \egroup}
627\stopbuffer
628
629\typebuffer
630
631\getbuffer
632
633\startbuffer
634\startcombination[3*1]
635  {\rotatetokens {0} {0}{0}{Does it work ok?}} {A}
636  {\rotatetokens{20} {0}{0}{Does it work ok?}} {B}
637  {\rotatetokens{20}{30}{0}{Does it work ok?}} {C}
638\stopcombination
639\stopbuffer
640
641We can use this macro as follows:
642
643\typebuffer
644
645\startlinecorrection[blank]
646\getbuffer
647\stoplinecorrection
648
649The previous macro is not really an example of generalization, but we used it for
650demonstrating how to build graphics in a stepwise way. If you put the steps in
651buffers, you can even combine steps and replace them at will. This is how we made
652the previous step by step examples: We put each sub||graphic in a buffer and then
653called the ones we wanted.
654
655We now present a more general approach to typesetting along a given path. This
656method is not only more robust and general, it is also a more compact definition,
657especially if we omit the tracing and testing code. We use a familiar auxiliary
658definition. The \type {\setstrut} and \type {\strut} commands ensure that the
659lines have the proper depth and height.
660
661\startbuffer
662\def\processfollowingtoken#1%
663  {\appendtoks#1\to\MPtoks
664   \setbox\MPbox=\hbox{\RotFont\setstrut\strut\the\MPtoks}%
665   \startMPdrawing
666     n := n + 1 ; len[n] := \the\wd\MPbox ;
667   \stopMPdrawing
668   \startMPdrawing[-]
669     pic[n] := btex \RotFont\setstrut\strut#1 etex ;
670     pic[n] := pic[n] shifted -llcorner pic[n] ;
671   \stopMPdrawing}
672\stopbuffer
673
674\typebuffer \getbuffer
675
676In \MKII\ the previous code is collected in the macro \type {\followtokens} but
677in \MKIV\ we use a different approach. There we use a mix of \TEX, \METAPOST, and
678\LUA\ to define that macro. The principles remain the same but the code is more
679robust.
680
681\useMPlibrary[txt]
682
683So, how does this compare to earlier results? The original, full text as typeset
684by \TEX, looks like:
685
686\blank \start \RotFont We now follow some arbitrary path ... \stop \blank
687
688In the examples, the text is typeset along the path with:
689
690\startbuffer[toks]
691\followtokens{We now follow some arbitrary path ...}
692\stopbuffer
693
694\typebuffer[toks]
695
696%  \startlinecorrection[blank]
697%  \getbuffer[toks]
698%  \stoplinecorrection
699
700%  Since we did not set a path, a dummy path is used. We can provide a path by
701%  (re)defining the graphic \type {followtokens}.
702
703%  \startbuffer[trac]
704%  \startMPinclusions
705%    boolean TraceRot ; TraceRot := true ;
706%  \stopMPinclusions
707%  \stopbuffer
708
709\startbuffer[draw]
710\startuseMPgraphic{followtokens}
711  path RotPath ; RotPath := fullcircle ;
712\stopuseMPgraphic
713\stopbuffer
714
715\startbuffer
716\typebuffer[draw]
717\startlinecorrection[blank]
718\hbox
719  {\getbuffer[draw,toks]\hskip1cm
720   \getbuffer[trac,draw,toks]}
721\stoplinecorrection
722\stopbuffer
723
724\getbuffer
725
726\startbuffer[draw]
727\startuseMPgraphic{followtokens}
728  path RotPath ; RotPath := reverse fullcircle ;
729\stopuseMPgraphic
730\stopbuffer
731
732\getbuffer
733
734\startbuffer[draw]
735\startuseMPgraphic{followtokens}
736  path RotPath ; RotPath := (-3cm,-1cm)--(0,1cm)--(3cm,-1cm) ;
737\stopuseMPgraphic
738\stopbuffer
739
740\getbuffer
741
742\startbuffer[draw]
743\startuseMPgraphic{followtokens}
744  path RotPath ; RotPath := (-3cm,0)--(3cm,1cm) ;
745\stopuseMPgraphic
746\stopbuffer
747
748\getbuffer
749
750\startbuffer[draw]
751\startuseMPgraphic{followtokens}
752  path RotPath ; RotPath := (-3cm,0)..(-1cm,1cm)..(3cm,0) ;
753\stopuseMPgraphic
754\stopbuffer
755
756\getbuffer
757
758\startbuffer[draw]
759\startuseMPgraphic{followtokens}
760  path RotPath ; RotPath := (-3cm,0)..(-1cm,1cm)..(0cm,-2cm)..(3cm,0) ;
761\stopuseMPgraphic
762\stopbuffer
763
764\getbuffer
765
766When turned on, tracing will produce bounding boxes as well as draw the path.
767Tracing can be turned on by saying:
768
769\typebuffer[trac]
770
771% let's turn it off now
772
773\startMPinclusions
774  boolean TraceRot ; TraceRot := false ;
775\stopMPinclusions
776
777The next example is dedicated to Giuseppe Bilotta who wants to handle multiple
778strings and uses a patched version of \type {\followtokens}. To avoid a
779complicated explanation, we will present an alternative here that uses overlays.
780This method also avoids complicated path definitions.
781
782\startbuffer
783\startoverlay
784  {\startuseMPgraphic{followtokens}
785     draw fullcircle scaled 5cm .
786       withpen pencircle scaled 1pt withcolor .625yellow ;
787     draw fullsquare scaled 5.25cm
788       withpen pencircle scaled 1pt withcolor .625red ;
789     drawoptions (withcolor .625red) ;
790     path RotPath ; RotPath := halfcircle scaled 5cm ;
791     setbounds currentpicture to boundingbox fullcircle scaled 5.25cm ;
792   \stopuseMPgraphic
793   \followtokens { Met{\`a} superiore }}
794  {\startuseMPgraphic{followtokens}
795     drawoptions (withcolor .625red) ;
796     path RotPath ; RotPath := halfcircle rotated 90 scaled 5cm ;
797     setbounds currentpicture to boundingbox fullcircle scaled 5.25cm ;
798   \stopuseMPgraphic
799   \followtokens { {$\star$} }}
800  {\startuseMPgraphic{followtokens}
801     drawoptions (withcolor .625red) ;
802     path RotPath ; RotPath := halfcircle rotated 180 scaled 5cm ;
803     setbounds currentpicture to boundingbox fullcircle scaled 5.25cm ;
804   \stopuseMPgraphic
805   \followtokens { Met{\`a} inferiore }}
806  {\startuseMPgraphic{followtokens}
807     drawoptions (withcolor .625red) ;
808     path RotPath ; RotPath := halfcircle rotated 270 scaled 5cm ;
809     setbounds currentpicture to boundingbox fullcircle scaled 5.25cm ;
810   \stopuseMPgraphic
811   \followtokens { {$\star$} }}
812\stopoverlay
813\stopbuffer
814
815\typebuffer
816
817In order to fool the overlay macro that each graphic has the same size, we force
818a bounding box.
819
820\startlinecorrection[blank]
821\getbuffer
822\stoplinecorrection
823
824\stopsection
825
826\startsection[title={Talking to \TEX}]
827
828Sometimes, others may say oftentimes, we are in need for some fancy typesetting.
829If we want to typeset a paragraph of text in a non standard shape, like a circle,
830we have to fall back on \type {\parshape}. Unfortunately, \TEX\ is not that
831strong in providing the specifications of more complicated shapes, unless you are
832willing to do some complicated arithmetic \TEX. Given that \METAPOST\ knows how
833to deal with shapes, the question is: \quotation {Can \METAPOST\ be of help?}
834
835In the process of finding out how to deal with this, we first define a simple
836path. Because we are going to replace pieces of code, we will compose the graphic
837from components. First, we create the path.
838
839\startbuffer
840\startuseMPgraphic{text path}
841  path p ; p := ((0,1)..(-1,0)..(1,0)--cycle) scaled 65pt ;
842\stopuseMPgraphic
843\stopbuffer
844
845\typebuffer \getbuffer
846
847This shape is not that beautiful, but it has a few characteristics that will help
848us to identify bordercases.
849
850\startbuffer
851\startuseMPgraphic{text draw}
852  drawarrow p withpen pencircle scaled 1pt withcolor red ;
853\stopuseMPgraphic
854\stopbuffer
855
856\typebuffer \getbuffer
857
858Now we use \CONTEXT's \type {\includeMPgraphic} command to build our graphic from
859the previously defined components.
860
861\startbuffer
862\startuseMPgraphic{text}
863  \includeMPgraphic{text path}
864  \includeMPgraphic{text draw}
865\stopuseMPgraphic
866\stopbuffer
867
868\typebuffer \getbuffer
869
870When called with \type {\useMPgraphic{text}}, we get:
871
872\startlinecorrection[blank]
873\useMPgraphic{text}
874\stoplinecorrection
875
876For the moment we start the path at $(x=0,y>0)$, but later using more complicated
877macros, we will see that we can use arbitrary paths.
878
879We are going to split the path in two, and will use the points that make up the
880bounding box as calcutated by \METAPOST. The next graphic shows one of these
881points, the lower left corner, available as point \typ {llcorner p}.
882
883\startbuffer
884\startuseMPgraphic{text draw}
885  draw             p withpen pencircle scaled 3pt withcolor red ;
886  draw boundingbox p withpen pencircle scaled 1pt ;
887  draw llcorner    p withpen pencircle scaled 5pt ;
888\stopuseMPgraphic
889\stopbuffer
890
891\typebuffer \getbuffer
892
893\startlinecorrection[blank]
894\useMPgraphic{text}
895\stoplinecorrection
896
897The five points that \METAPOST\ can report for each path or picture are:
898
899\starttabulate[|Tl|l|]
900\NC llcorner \NC lower left  corner            \NC \NR
901\NC lrcorner \NC lower right corner            \NC \NR
902\NC urcorner \NC upper right corner            \NC \NR
903\NC ulcorner \NC upper left  corner            \NC \NR
904\NC center   \NC intersection of the diagonals \NC \NR
905\stoptabulate
906
907If we want to typeset text inside this circle, we need to know where a line
908starts and ends. Given that lines are horizontal and straight, we therefore need
909to calculate the intersection points of the lines and the path. As a first step,
910we calculate the top and bottom of the path and after that we split off the left
911and right path.
912
913\startbuffer
914\startuseMPgraphic{text split}
915  pair t, b ; path l, r ;
916
917  t := (ulcorner p -- urcorner p) intersectionpoint p ;
918  b := (llcorner p -- lrcorner p) intersectionpoint p ;
919
920  l := p cutbefore t ; l := l cutafter b ;
921  r := p cutbefore b ; r := r cutafter t ;
922\stopuseMPgraphic
923\stopbuffer
924
925\typebuffer \getbuffer
926
927The \type {intersectionpoint} macro returns the point where two paths cross. If
928the paths don't cross, an error is reported, when the paths cross more times,
929just one point is returned. The \type {cutafter} and \type {cutbefore} commands
930do as their names say and return a path.
931
932In the \type {text split} code fragment, \type {t} and \type {b} are the top
933points of the main path, while \type {l} and \type {r} become the left and right
934half of path \type {p}.
935
936We now draw the original path using a thick pen and both halves with a thinner
937pen on top of the original. The arrows show the direction.
938
939\startbuffer
940\startuseMPgraphic{text draw}
941  draw      p withpen pencircle scaled 3pt withcolor red ;
942  drawarrow l withpen pencircle scaled 1pt withcolor green ;
943  drawarrow r withpen pencircle scaled 1pt withcolor blue ;
944\stopuseMPgraphic
945\stopbuffer
946
947\typebuffer \getbuffer
948
949We use \type {\includeMPgraphic} to assemble the components:
950
951\startbuffer
952\startuseMPgraphic{text}
953  \includeMPgraphic{text path}
954  \includeMPgraphic{text split}
955  \includeMPgraphic{text draw}
956\stopuseMPgraphic
957\stopbuffer
958
959\typebuffer \getbuffer
960
961This graphic is typeset with \type {\useMPgraphic{text}}:
962
963\startlinecorrection[blank]
964\useMPgraphic{text}
965\stoplinecorrection
966
967Before we are going to use them, we define some variables that specify the text.
968We use a baseline distance of 8~points. The part of the line above the baseline
969is 7.2~points, while the (maximum) depth is 2.8~points. These ratios are the ones
970we use in \CONTEXT. Because we don't want the text to touch the circle so we
971define an offset too.
972
973\startbuffer
974\startuseMPgraphic{text vars}
975  MyOffset  := LineHeight/2 ;
976  MyTopSkip := StrutHeight ;
977\stopuseMPgraphic
978\stopbuffer
979
980\typebuffer \getbuffer
981
982We more or less achieve the offset by scaling the path. In doing so, we use the
983width and height, which we call \type {hsize} and \type {vsize}, thereby
984conforming to the \TEX\ naming scheme.
985
986First we calculate both dimensions from the bounding box of the path. Next we
987down scale the path to compensate for the offset. When done, we recalculate the
988dimensions.
989
990\startbuffer
991\startuseMPgraphic{text move}
992  pair t, b ; path q, l, r ;
993
994  hsize := xpart lrcorner p - xpart llcorner p ;
995  vsize := ypart urcorner p - ypart lrcorner p ;
996
997  q := p xscaled ((hsize-2MyOffset)/hsize)
998         yscaled ((vsize-2MyOffset)/vsize) ;
999
1000  hsize := xpart lrcorner q - xpart llcorner q ;
1001  vsize := ypart urcorner q - ypart lrcorner q ;
1002\stopuseMPgraphic
1003\stopbuffer
1004
1005\typebuffer \getbuffer
1006
1007\startbuffer
1008\startuseMPgraphic{text split}
1009  t := (ulcorner q -- urcorner q) intersectionpoint q ;
1010  b := (llcorner q -- lrcorner q) intersectionpoint q ;
1011
1012  l := q cutbefore t ; l := l cutafter b ;
1013  r := q cutbefore b ; r := r cutafter t ;
1014\stopuseMPgraphic
1015\stopbuffer
1016
1017We adapt the \type {text split} code to use the reduced path
1018instead of the original.
1019
1020\typebuffer \getbuffer
1021
1022\startbuffer
1023\startuseMPgraphic{text draw}
1024  drawarrow p withpen pencircle scaled 1pt withcolor red ;
1025  draw      t withpen pencircle scaled 2pt ;
1026  draw      b withpen pencircle scaled 2pt ;
1027  drawarrow l withpen pencircle scaled 1pt withcolor green ;
1028  drawarrow r withpen pencircle scaled 1pt withcolor blue ;
1029\stopuseMPgraphic
1030\stopbuffer
1031
1032In order to test what we have reached so far, we draw the original path, the left
1033and right part of the reduced path, and both the top and bottom point.
1034
1035\typebuffer \getbuffer
1036
1037Again we use \type {\includeMPgraphic} to combine the
1038components into a graphic.
1039
1040\startbuffer
1041\startuseMPgraphic{text}
1042  \includeMPgraphic{text path} \includeMPgraphic{text vars}
1043  \includeMPgraphic{text move} \includeMPgraphic{text split}
1044  \includeMPgraphic{text draw}
1045\stopuseMPgraphic
1046\stopbuffer
1047
1048\typebuffer \getbuffer
1049
1050Then we use \type {\useMPgraphic{text}} to call up the picture.
1051
1052\startlinecorrection[blank]
1053\useMPgraphic{text}
1054\stoplinecorrection
1055
1056The offset is not optimal. Note the funny gap at the top. We could try to fix
1057this, but there is a better way to optimize both paths.
1058
1059We lower the top edge of \type {q}'s bounding box by \type {MyTopSkip}, then cut
1060any part of the left and right pieces of \type {q} that lie above it. Similarly,
1061we raise the bottom edge and cut off the pieces that fall below this line.
1062
1063\startbuffer
1064\startuseMPgraphic{text cutoff}
1065  path tt, bb ;
1066
1067  tt := (ulcorner q -- urcorner q) shifted (0,-MyTopSkip) ;
1068  bb := (llcorner q -- lrcorner q) shifted (0,StrutDepth) ;
1069
1070  l := l cutbefore (l intersectionpoint tt) ;
1071  l := l cutafter  (l intersectionpoint bb) ;
1072  r := r cutbefore (r intersectionpoint bb) ;
1073  r := r cutafter  (r intersectionpoint tt) ;
1074\stopuseMPgraphic
1075\stopbuffer
1076
1077\typebuffer \getbuffer
1078
1079Because we use \type {\includeMPgraphic} to construct the graphic, we can
1080redefine \type {text draw} to show the result of this effort.
1081
1082\startbuffer
1083\startuseMPgraphic{text draw}
1084  drawarrow p withpen pencircle scaled 1pt withcolor red ;
1085  drawarrow l withpen pencircle scaled 1pt withcolor green ;
1086  drawarrow r withpen pencircle scaled 1pt withcolor blue ;
1087\stopuseMPgraphic
1088\stopbuffer
1089
1090\typebuffer \getbuffer
1091
1092The \type {text} graphic now becomes:
1093
1094\startbuffer
1095\startuseMPgraphic{text}
1096  \includeMPgraphic{text path}   \includeMPgraphic{text vars}
1097  \includeMPgraphic{text move}   \includeMPgraphic{text split}
1098  \includeMPgraphic{text cutoff} \includeMPgraphic{text draw}
1099\stopuseMPgraphic
1100\stopbuffer
1101
1102\typebuffer \getbuffer
1103
1104Or, as graphic:
1105
1106\startlinecorrection[blank]
1107\useMPgraphic{text}
1108\stoplinecorrection
1109
1110We are now ready for an attempt to calculate the shape of the text. For each
1111line, we have to calculate the left and right intersection points, and since a
1112line has a height and depth, we have to determine which part touches first.
1113
1114\startbuffer
1115\startuseMPgraphic{text calc}
1116  vardef found_point (expr lin, pat, sig) =
1117    pair a, b ;
1118    a := pat intersection_point (lin shifted (0,StrutHeight)) ;
1119    if intersection_found :
1120      a := a shifted (0,-StrutHeight) ;
1121    else :
1122      a := pat intersection_point lin ;
1123    fi ;
1124    b := pat intersection_point (lin shifted (0,-StrutDepth)) ;
1125    if intersection_found :
1126      if sig :
1127        if xpart b > xpart a : a := b shifted (0,StrutDepth) fi ;
1128      else :
1129        if xpart b < xpart a : a := b shifted (0,StrutDepth) fi ;
1130      fi ;
1131    fi ;
1132    a
1133  enddef ;
1134\stopuseMPgraphic
1135\stopbuffer
1136
1137\typebuffer \getbuffer
1138
1139Instead of using \METAPOST's \type {intersectionpoint} macro, we use one that
1140comes with \CONTEXT. That way we don't get an error message when no point is
1141found, and can use a boolean flag to take further action. Since we use a \type
1142{vardef}, all calculations are hidden and the~\type {a} at the end is returned,
1143so that we can use this macro in an assignment. The \type {sig} variable is used
1144to distinguish between the beginning and end of a line (the left and right
1145subpath).
1146
1147\startbuffer
1148\startuseMPgraphic{text step}
1149  path line; pair lll, rrr ;
1150
1151  for i=MyTopSkip step LineHeight until vsize :
1152
1153    line := (ulcorner q -- urcorner q) shifted (0,-i) ;
1154
1155    lll := found_point(line,l,true ) ;
1156    rrr := found_point(line,r,false) ;
1157\stopuseMPgraphic
1158\stopbuffer
1159
1160\typebuffer \getbuffer
1161
1162Here we divide the available space in lines. The first line starts at \type
1163{StrutHeight} from the top.
1164
1165We can now finish our graphic by visualizing the lines. Both the height and depth
1166of the lines are shown.
1167
1168\startbuffer
1169\startuseMPgraphic{text line}
1170    fill (lll--rrr--rrr shifted (0,StrutHeight)--lll
1171      shifted (0,StrutHeight)--cycle) withcolor .5white ;
1172    fill (lll--rrr--rrr shifted (0,-StrutDepth)--lll
1173      shifted (0,-StrutDepth)--cycle) withcolor .7white ;
1174    draw lll withpen pencircle scaled 2pt ;
1175    draw rrr withpen pencircle scaled 2pt ;
1176    draw (lll--rrr) withpen pencircle scaled .5pt ;
1177\stopuseMPgraphic
1178
1179\startuseMPgraphic{text done}
1180  endfor ;
1181\stopuseMPgraphic
1182\stopbuffer
1183
1184\typebuffer \getbuffer
1185
1186The result is still a bit disappointing.
1187
1188\startbuffer
1189\startuseMPgraphic{text}
1190  \includeMPgraphic{text path}   \includeMPgraphic{text vars}
1191  \includeMPgraphic{text move}   \includeMPgraphic{text split}
1192  \includeMPgraphic{text cutoff} \includeMPgraphic{text draw}
1193  \includeMPgraphic{text calc}   \includeMPgraphic{text step}
1194  \includeMPgraphic{text line}   \includeMPgraphic{text done}
1195\stopuseMPgraphic
1196\stopbuffer
1197
1198\typebuffer \getbuffer
1199\startlinecorrection[blank]
1200\useMPgraphic{text}
1201\stoplinecorrection
1202
1203In order to catch the overflow at the bottom, we need to change the \type
1204{for}||loop a bit, so that the number of lines does not exceed the available
1205space. The test that surrounds the assignment of \type {vvsize} makes sure that
1206we get better results when we (on purpose) take a smaller height.
1207
1208\startbuffer
1209\startuseMPgraphic{text step}
1210  path line; pair lll, rrr ; numeric vvsize ;
1211
1212  if (StrutHeight+StrutDepth<LineHeight) :
1213    vvsize := vsize ;
1214  else :
1215    vvsize := (vsize div LineHeight) * LineHeight ;
1216  fi ;
1217
1218  for i=MyTopSkip step LineHeight until vvsize :
1219
1220    line := (ulcorner q -- urcorner q) shifted (0,-i) ;
1221
1222    lll := found_point(line,l,true ) ;
1223    rrr := found_point(line,r,false) ;
1224\stopuseMPgraphic
1225\stopbuffer
1226
1227\typebuffer \getbuffer
1228
1229\startlinecorrection[blank]
1230\useMPgraphic{text}
1231\stoplinecorrection
1232
1233We can manipulate the heigth and depth of the lines to give different (and maybe
1234better) results.
1235
1236\startbuffer
1237\startuseMPgraphic{text vars}
1238MyOffset  := .5LineHeight ;
1239MyTopSkip := StrutHeight ;
1240\stopuseMPgraphic
1241\stopbuffer
1242
1243\typebuffer \getbuffer
1244
1245\startlinecorrection[blank]
1246\useMPgraphic{text}
1247\stoplinecorrection
1248
1249This kind of graphic trickery in itself is not enough to get \TEX\ into
1250typesetting within the bounds of a closed curve. Since \METAPOST\ can write
1251information to a file, and \TEX\ can read such a file, a natural way to handle
1252this is to let \METAPOST\ write a \type {\parshape} specification.
1253
1254\startbuffer
1255\startuseMPgraphic{text macro}
1256  def provide_parshape (expr p, MyOffset, LineHeight,
1257    StrutHeight, StrutDepth, MyTopSkip) =
1258
1259    \includeMPgraphic{text move}
1260    \includeMPgraphic{text split}
1261    \includeMPgraphic{text cutoff}
1262    \includeMPgraphic{text draw}
1263    \includeMPgraphic{text calc}
1264    \includeMPgraphic{text loop}
1265    \includeMPgraphic{text save}
1266
1267  enddef ;
1268\stopuseMPgraphic
1269\stopbuffer
1270
1271\typebuffer \getbuffer
1272
1273We have to adapt the for||loop to register the information about the lines. After
1274the loop we write those values to a file using another loop.
1275
1276\startbuffer
1277\startuseMPgraphic{text loop}
1278  path line; pair lll, rrr ; numeric vvsize, n ; n := 0 ;
1279
1280  if (StrutHeight+StrutDepth<LineHeight) :
1281    vvsize := vsize ;
1282  else :
1283    vvsize := (vsize div LineHeight) * LineHeight ;
1284  fi ;
1285
1286  for i=MyTopSkip step LineHeight until vvsize :
1287
1288    line := (ulcorner q -- urcorner q) shifted (0,-i) ;
1289
1290    lll := found_point(line,l,true ) ;
1291    rrr := found_point(line,r,false) ;
1292
1293    n := n + 1 ;
1294
1295    indent[n] := abs(xpart lll - xpart llcorner q) ;
1296    width[n]  := abs(xpart rrr - xpart lll) ;
1297
1298  endfor ;
1299\stopuseMPgraphic
1300
1301\startuseMPgraphic{text save}
1302  write "\parshape " & decimal n to "mfun-mp-data.txt" ;
1303  for i=1 upto n:
1304    write decimal indent[i]&"bp " &
1305          decimal  width[i]&"bp " to "mfun-mp-data.txt" ;
1306  endfor ;
1307  write EOF to "mfun-mp-data.txt" ;
1308\stopuseMPgraphic
1309\stopbuffer
1310
1311\typebuffer \getbuffer
1312
1313We can call this macro using the part we used in the previous examples.
1314
1315\startbuffer
1316\startuseMPgraphic{text}
1317  \includeMPgraphic{text macro}
1318
1319  path p ; p := ((0,1)..(-1,0)..(1,0)--cycle) scaled 65pt ;
1320
1321  provide_parshape
1322   (p,              % shape path
1323    .5*LineHeight,  % offset
1324    LineHeight,     % distance between lines
1325    StrutHeight,    % height of a line
1326    StrutDepth,     % depth of a line
1327    StrutHeight) ;  % height of first line
1328\stopuseMPgraphic
1329\stopbuffer
1330
1331\typebuffer \getbuffer
1332
1333After we called \type {\useMPgraphic{text}}, the resulting file looks as follows.
1334You can call up this file by its anonymous name \type {\MPdatafile}, since this
1335macro gets the value of the graphic at hand.
1336
1337\startnointerference
1338    \useMPgraphic{text}
1339\stopnointerference
1340
1341\typefile{mfun-mp-data.txt}
1342
1343So, reading in this file at the start of a paragraph will setup \TEX\ to follow
1344this shape.
1345
1346The final implementation is a bit more complicated since it takes care of paths
1347that are not centered around the origin and don't start at the top point. We
1348achieve this by moving the path to the center:
1349
1350\starttyping
1351cp := center p ; q := p shifted - cp ;
1352\stoptyping
1353
1354The arbitrary starting point is taken care of by a slightly more complicated path
1355cutter. First we make sure that the path runs counterclockwise.
1356
1357\starttyping
1358if xpart directionpoint t of q < 0 : q := reverse q fi ;
1359\stoptyping
1360
1361Knowing this, we can split the path in two, using a slightly different splitter:
1362
1363\starttyping
1364l := q cutbefore t ;
1365l := l if xpart point 0 of q < 0 : & q fi cutafter b ;
1366r := q cutbefore b ;
1367r := r if xpart point 0 of q > 0 : & q fi cutafter t ;
1368\stoptyping
1369
1370As always, when implementing a feature like this, some effort goes into a proper
1371user interface. In doing so, we need some \TEX\ trickery that goes beyond this
1372text, like collecting text and splitting of the part needed. Also, we want to be
1373able to handle multiple shapes at once, like the next example demonstrates.
1374
1375\stopsection
1376
1377\startsection[title={Libraries}]
1378
1379\index{graphics+libraries}
1380
1381In \MKIV\ and \LMTX\ the \METAFUN\ driven text around a curve is a core
1382functionality. In \LMTX\ the specific paragraph shape are available in the core
1383too. Otherwise you need to load a module:
1384
1385\startbuffer
1386\useMPlibrary[txt]
1387\stopbuffer
1388
1389\typebuffer \getbuffer
1390
1391We define four shapes. They are not really beautiful, but they demonstrate what
1392happens in border cases. For instance, too small first lines are ignored. First
1393we define a circle. Watch how the dimensions are set in the graphic. The
1394arguments passed to \type {build_parshape} are: path, an offset, an additional
1395horizontal and vertical displacement, the baseline distance, the height and depth
1396of the line, and the height of the first line (MyTopSkip in \TEX\ terminology). The
1397height and depth of a line are often called strut height and depth, with a strut
1398being an invisible character with maximum dimensions.
1399
1400\startbuffer
1401\startuseMPgraphic{test 1}
1402  path p ; p := fullcircle scaled 6cm ;
1403
1404  build_parshape(p,6pt,0,0,LineHeight,
1405    StrutHeight,StrutDepth,StrutHeight) ;
1406
1407  draw p withpen pencircle scaled 1pt ;
1408\stopuseMPgraphic
1409\stopbuffer
1410
1411\typebuffer \getbuffer
1412
1413The second shape is a diamond. This is a rather useless shape, unless the text
1414suits the small lines at the top and bottom.
1415
1416\startbuffer
1417\startuseMPgraphic{test 2}
1418  path p ; p := fullsquare rotated 45 scaled 5cm ;
1419
1420  build_parshape(p,6pt,0,0,LineHeight,
1421    StrutHeight,StrutDepth,StrutHeight) ;
1422
1423  draw p withpen pencircle scaled 1pt ;
1424\stopuseMPgraphic
1425\stopbuffer
1426
1427\typebuffer \getbuffer
1428
1429The third and fourth shape demonstrate that providing a suitable offset is not
1430always trivial.
1431
1432\startbuffer
1433\startuseMPgraphic{test 3}
1434  numeric w, h ; w := h := 6cm ;
1435  path p ; p := (.5w,h) -- (0,h) -- (0,0) -- (w,0) &
1436    (w,0) .. (.75w,.5h) .. (w,h) & (w,h) -- cycle ;
1437
1438  build_parshape(p,6pt,0,0,LineHeight,
1439    StrutHeight,StrutDepth,StrutHeight) ;
1440
1441  draw p withpen pencircle scaled 1pt ;
1442\stopuseMPgraphic
1443\stopbuffer
1444
1445\typebuffer \getbuffer
1446
1447Contrary to the first three shapes, here we use a different path for the
1448calculations and the drawing. Watch carefully! If, instead of an offset, we pass
1449a path, \METAPOST\ is able to calculate the right dimensions and offsets. This is
1450needed, since we need these later on.
1451
1452\startbuffer
1453\startuseMPgraphic{test 4}
1454  numeric w, h, o ;
1455
1456  def shape = (o,o) -- (w-o,o) & (w-o,o) .. (.75w-o,.5h) ..
1457    (w-2o,h-o) & (w-2o,h-o) -- (o,h-o) -- cycle
1458  enddef ;
1459
1460  w := h := 6cm ; o := 6pt ; path p ; p := shape ;
1461  w := h := 6cm ; o := 0pt ; path q ; q := shape ;
1462
1463  build_parshape(p,q,6pt,6pt,LineHeight,
1464    StrutHeight,StrutDepth,StrutHeight) ;
1465
1466  draw q withpen pencircle scaled 1pt ;
1467\stopuseMPgraphic
1468\stopbuffer
1469
1470\typebuffer \getbuffer
1471
1472Since we also want these graphics as backgrounds, we define them as overlays. If
1473you don't want to show the graphic, you may omit this step.
1474
1475\startbuffer
1476\defineoverlay[test 1][\useMPgraphic{test 1}]
1477\defineoverlay[test 2][\useMPgraphic{test 2}]
1478\defineoverlay[test 3][\useMPgraphic{test 3}]
1479\defineoverlay[test 4][\useMPgraphic{test 4}]
1480\stopbuffer
1481
1482\typebuffer \getbuffer
1483
1484As text, we use a quote from Douglas R.~Hofstadter's book \quotation {Metamagical
1485Themas, Questing for the Essence of Mind and Pattern}. Watch how we pass a list
1486of shapes.
1487
1488\startbuffer[text]
1489\startshapetext[test 1,test 2,test 3,test 4]
1490  \forgetall % as it says
1491  \setupalign[verytolerant,stretch,normal]%
1492  \input douglas % Douglas R. Hofstadter
1493\stopshapetext
1494\stopbuffer
1495
1496\typebuffer[text]
1497
1498Finally we combine text and shapes. Since we also want a background, we use \type
1499{\framed}. The macros \type {\parwidth} and \type {\parheight} are automatically
1500set to the current shape dimensions. The normal result is shown in \in {figure}
1501[fig:shapes].
1502
1503\startbuffer[shapes]
1504\startbuffer
1505\startcombination[2*2]
1506  {\framed[offset=overlay,frame=off,background=test 1]{\getshapetext}} {test 1}
1507  {\framed[offset=overlay,frame=off,background=test 2]{\getshapetext}} {test 2}
1508  {\framed[offset=overlay,frame=off,background=test 3]{\getshapetext}} {test 3}
1509  {\framed[offset=overlay,frame=off,background=test 4]{\getshapetext}} {test 4}
1510\stopcombination
1511\stopbuffer
1512\stopbuffer
1513
1514\typebuffer[shapes]
1515
1516\getbuffer[shapes]
1517
1518By using a buffer we keep \type {\placefigure} readable.
1519
1520\startbuffer[a]
1521\placefigure
1522  [here][fig:shapes]
1523  {A continuous text, typeset in a non||standard shape,
1524   spread over four areas, and right aligned.}
1525  {\getbuffer}
1526\stopbuffer
1527
1528\startbuffer[b]
1529\placefigure
1530  [here][fig:shapes]
1531  {A continuous text, typeset in a non||standard shape,
1532   spread over four areas.}
1533  {\scale[factor=max,height=.9\textheight]{\getbuffer}}
1534\stopbuffer
1535
1536\typebuffer[a]
1537
1538\doifmodeelse{screen}{\getbuffer[text,b]}{\getbuffer[text,a]}
1539
1540The traced alternative is shown in \in {figure} [fig:traced shapes]. This one is
1541defined as:
1542
1543\startbuffer[a]
1544\placefigure
1545  [here][fig:traced shapes]
1546  {A continuous text, typeset in a non||standard shape,
1547   spread over four areas (tracing on).}
1548  {\startMPinclusions
1549     boolean trace_parshape ; trace_parshape := true ;
1550   \stopMPinclusions
1551   \getbuffer}
1552\stopbuffer
1553
1554\startbuffer[b]
1555\placefigure
1556  [here][fig:traced shapes]
1557  {A continuous text, typeset in a non||standard shape,
1558   spread over four areas (tracing on).}
1559  {\startMPinclusions
1560     boolean trace_parshape ; trace_parshape := true ;
1561   \stopMPinclusions
1562   \scale[factor=max,height=.9\textheight]{\getbuffer}}
1563\stopbuffer
1564
1565\typebuffer[a]
1566
1567\doifmodeelse{screen}{\getbuffer[text,b]}{\getbuffer[text,a]}
1568
1569% {\em This mechanism is still somewhat experimental and will be optimized and
1570% extended with name spaces and more.}
1571
1572\blank
1573
1574We can combine all those tricks, although the input is somewhat fuzzy. First we
1575define a quote typeset in a circular paragraph shape.
1576
1577\startbuffer[shape]
1578\startuseMPgraphic{center}
1579  build_parshape(fullcircle scaled 8cm,0,0,0,LineHeight,
1580    StrutHeight,StrutDepth,StrutHeight) ;
1581\stopuseMPgraphic
1582
1583\startshapetext[center]
1584  \input douglas
1585\stopshapetext
1586
1587\defineoverlay[center][\useMPgraphic{center}]
1588\stopbuffer
1589
1590\typebuffer[shape]
1591
1592We will surround this text with a circular line, that we define as follows. By
1593using a buffer we keep things organized.
1594
1595\startbuffer
1596\startbuffer[circle]
1597\startuseMPgraphic{followtokens}
1598  path RotPath ; RotPath := reverse fullcircle
1599    rotatedaround(origin,90)
1600    xscaled \overlaywidth yscaled \overlayheight ;
1601  drawoptions (withcolor .625red) ;
1602\stopuseMPgraphic
1603
1604\followtokens
1605  {This is just a dummy text, kerned by \TeX\ and typeset
1606   in a circle using \MetaPost.\quad}
1607\stopbuffer
1608
1609\defineoverlay[edge][{\getbuffer[circle]}]
1610\stopbuffer
1611
1612\typebuffer \getbuffer
1613
1614The text and graphics come together in a framed text:
1615
1616\startbuffer
1617\startbuffer[quote]
1618\framed
1619  [offset=24pt,
1620   background=edge,
1621   frame=off,
1622   backgroundoffset=-18pt]
1623  {\getshapetext}
1624\stopbuffer
1625
1626\placefigure
1627  {One more time Hofstadter's quotation (normal).}
1628  {\getbuffer[shape,quote]}
1629
1630\placefigure
1631  {One more time Hofstadter's quotation (traced).}
1632  {\startMPinclusions
1633      boolean TraceRot ; TraceRot := true ;
1634   \stopMPinclusions
1635   \getbuffer[shape,quote]}
1636\stopbuffer
1637
1638\typebuffer \getbuffer
1639
1640% {\em Here also, I will rewrite things a bit so that we can avoid \type
1641% {\startMPdrawing} outside the macro, and thereby avoid problems. I can also add
1642% the maps cdrom cover as example.}
1643
1644\stopsection
1645
1646% \startsection[title={Visualizing \TEX}]
1647%
1648% The next example is a bit out of place in this manual, but nevertheless
1649% demonstrates how one can use \METAPOST\ to get insight in what \TEX\ is doing
1650% inside.
1651%
1652% The author of \PDFTEX, \THANH, has extended the paragraph builder with a
1653% provision for protruding characters and glyphs substitution, also known as {\it
1654% hz} (which stands for Hermann Zapf). The {\it hz} optimization involves an
1655% additional pass over the lines and|/|or paragraph, in order to determine how
1656% inconsistency in gaps can be reduced by substituting an \quote {\scale [sx=1.01]
1657% {a}} by an \quote {\scale [sx=5] {a}} or \quote {\scale [sx=.5] {a}}. In \in
1658% {figure} [fig:hz] you can find the visualization in action. By means of colors we
1659% indicate in what way glyphs are substituted by slightly larger or smaller values.
1660% More details on how the {\it hz} optimization works can be found in \THANH's
1661% thesis.
1662%
1663% \placefigure
1664%   [page][fig:hz]
1665%   {When we feed \TEX\ code into \METAPOST\ and back, we
1666%    can visualize {\it hz}||optimization in a colorful way.}
1667%   {\doifmodeelse{screen}
1668%      {\externalfigure[mfun-hzs.pdf][height=.8\textheight]}
1669%      {\externalfigure[mfun-hzp.pdf][height=.8\textheight]}}
1670%
1671% In order to avoid a complicated discussion about how to set up \PDFTEX\ to use
1672% {\it hz} |<|this can best be left over to the macro package that you use|>| we
1673% will illustrate the method behind this kind of visualizations in a more simple
1674% case.
1675%
1676% When you include a \METAPOST\ graphic in \PDFTEX, the output produced by
1677% \METAPOST\ is interpreted by a bunch of macros and converted into raw \PDF\ code.
1678% In the process special extensions, like shading, transparency, graphic inclusion,
1679% are taken care of. When the converter encounters a font inclusion directive,
1680% i.e.\ the \POSTSCRIPT\ \type {fshow} operator, it uses the \TEX\ font handler to
1681% take care of the font. A benefit of this approach is that \TEX\ and \METAPOST\
1682% share the same font resources and therefore the inclusion is done in the way
1683% expected.
1684%
1685% The low level macro that takes care of the font inclusion provides a couple of so
1686% called hooks, that permit us to do additional manipulations with the character
1687% sequences that are encountered.
1688%
1689% \startbuffer[demo]
1690% draw
1691%   btex \definedfont[cmr10]%
1692%     Combine the power of \TeX\ and \MetaPost !
1693%   etex scaled 2 ;
1694% \stopbuffer
1695%
1696% \typebuffer[demo]
1697%
1698% When processed, this gives the graphic:
1699%
1700% \startlinecorrection[blank]
1701% \processMPbuffer[demo]
1702% \stoplinecorrection
1703%
1704% The result is not spectacular, and there is no indication that \METAPOST\ has
1705% been in action. The following line of code sets the hook \type {\MPfshowcommand}
1706% |<|this commands takes one argument|>| to produce a ruled horizontal box.
1707%
1708% \startbuffer
1709% \let\MPfshowcommand\ruledhbox
1710% \stopbuffer
1711%
1712% \typebuffer
1713%
1714% \startlinecorrection[blank]
1715% \getbuffer \processMPbuffer[demo]
1716% \stoplinecorrection
1717%
1718% If you watch closely, you will see that the ruled boxes contain one or more
1719% characters (or more precise glyphs). This is a result from \TEX\ explicitely
1720% kerning characters.
1721%
1722% A second hook is provided in the macro that takes care of the font switch. This
1723% command is defined as follows:
1724%
1725% \starttyping
1726% \def\setMPfshowfont#1#2%
1727%   {\font\temp=#1\space at #2\relax\temp}
1728% \stoptyping
1729%
1730% The first argument is the raw font name, and the second argument specifies the
1731% desired size. If we want to see what fonts are involved, we can redefine the
1732% hooks as follows.
1733%
1734% \starttyping
1735% \def\setMPfshowfont#1#2%
1736%   {\message{[using #1 at #2 in mp graphic]}%
1737%    \font\temp=#1\space at #2\relax\temp}
1738% \stoptyping
1739%
1740% It happens that two fonts are used: \type {cmr10} and \type {logo10}. Once we
1741% know this, we can apply some magic: we set the color to the fontname and define a
1742% couple of colors that match the name.
1743%
1744% \startbuffer
1745% \definecolor [cmr10]  [darkred]
1746% \definecolor [logo10] [darkyellow]
1747%
1748% \def\setMPfshowfont#1#2%
1749%   {\color[#1]\font\temp=#1\space at #2\relax\temp}
1750% \stopbuffer
1751%
1752% \typebuffer
1753%
1754% In the case of the \type {\it hz} examples we had to define a couple of more
1755% colors, but the principle remains.
1756%
1757% \startlinecorrection[blank]
1758% \getbuffer \processMPbuffer[demo]
1759% \stoplinecorrection
1760%
1761% We don't expect the user to use tricks like this on a daily basis, but it
1762% demonstrates that with a bit of knowlegde of the internals of \CONTEXT, you can
1763% produce nice examples of typographic programming.
1764%
1765% \stopsection
1766
1767\stopchapter
1768
1769\stopcomponent
1770