summaryrefslogtreecommitdiff
path: root/doc/context/sources/general/manuals/metafun/metafun-text.tex
blob: 135fe7e3504aae54ac2b9d97e4633bbd1bcfb328 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
% language=us runpath=texruns:manuals/metafun

\startcomponent metafun-text

\environment metafun-environment

\startchapter[reference=sec:typesetting,title={Typesetting in \METAPOST}]

\startintro

It is said that a picture tells more than a thousand words. So you might expect
that text in graphics becomes superfluous. Out of experience we can tell you that
this is not the case. In this chapter we explore the ways to add text to
\METAPOST\ graphics, and let you choose whether or not to have it typeset by
\TEX.

\stopintro

\startsection[title={The process}]

\index{text}

You can let \METAPOST\ process text that is typeset by \TEX. Such text is first
embedded in the \METAPOST\ file in the following way:

\starttyping
btex Some text to be typeset by \TEX etex
\stoptyping

This returns a picture, but only after \METAPOST\ has made sure that \TEX\ has
converted it into something useful. This process of conversion is slightly system
dependent and even a bit obscure. Traditional \METAPOST\ calls a program that
filters the \type {btex}|\unknown|\type {etex} commands, next it calls \TEX\ by
passing the output routine, in order to make sure that each piece of text ends up
on its own page, and afterwards it again calls a program that converts the \DVI\
pages into \METAPOST\ pictures. In \LUATEX's \MPLIB\ a different route is
followed.

In \CONTEXT\ \MKII, when using \WEBC, you can generate the graphics at run||time.
This takes more time than processing the graphics afterwards, but has the
advantage that \TEX\ knows immediately what graphic it is dealing with. When
enabled, \CONTEXT\ will call either \METAPOST, or, when the graphic contains
\type {btex}||\type {etex} commands, call \TEXEXEC, which in turn makes sure that
the right auxiliary programs are executed.

In \CONTEXT\ \MKIV\ you won't notice this at all because everything is tightly
integrated with \LUATEX's \MPLIB. This has an enormous speed gain: when this
manual had about 425 pages, on my laptop with mobile 3840QM processor, one run of
this document takes 18 seconds (14.5 with \LUAJITTEX) and that includes loading a
bunch of (outline) fonts and processing some 2200 \METAPOST\ images. While
writing the first version of this manual runtime was upto 50 times slower for
half the number of pages so compared to \MKII\ we have gained a lot.

\startFLOWchart[metatex]
    \startFLOWcell
      \name       {script 1}
      \location   {1,1}
      \shape      {action}
      \text       {\type{context}}
      \connection [rl] {context 1}
    \stopFLOWcell
    \startFLOWcell
      \name       {context 1}
      \location   {2,1}
      \shape      {action}
      \text       {\CONTEXT}
      \connection [bt] {metapost 1}
      \connection [rl] {script 2}
    \stopFLOWcell
    \startFLOWcell
      \name       {metapost 1}
      \location   {2,2}
      \shape      {action}
      \text       {\METAPOST}
    \stopFLOWcell
    \startFLOWcell
      \name       {script 2}
      \location   {3,1}
      \shape      {action}
      \text       {\type{context}}
      \connection [rl] {context  2}
      \connection [bt] {metapost 2}
    \stopFLOWcell
    \startFLOWcell
      \name       {context 2}
      \location   {4,1}
      \shape      {action}
      \text       {\CONTEXT}
    \stopFLOWcell
    \startFLOWcell
      \name       {metapost 2}
      \location   {3,2}
      \shape      {action}
      \text       {\METAPOST}
    \stopFLOWcell
\stopFLOWchart

\startplacefigure[title={How \TEX\ and \METAPOST\ work together.}]
    \FLOWchart[metatex]
\stopplacefigure

\stopsection

\startsection[title={Environments}]

\index{environments}

In case you want to pass code that is shared by all \type {btex}||\type {etex}
pictures, \METAPOST\ provides:

\starttyping
verbatimtex \DefineSomeCommands etex ;
\stoptyping

However, in \CONTEXT\ one has a better mechanism available. In \CONTEXT\ \MKII\
the advised method is passing environments. The best way to pass them is the
following. As an example we switch to the 15 basic \POSTSCRIPT\ fonts.

\startbuffer[pos]
\startMPenvironment
  \usetypescript[palatino][texnansi] % mkii has encodings
  \setupbodyfont[palatino]
\stopMPenvironment
\stopbuffer

\typebuffer[pos]

This means that in code like the following, a Palatino font will be used.

\starttyping
\startMPcode
draw btex Meta is a female lion! etex
  xysized (\the\textwidth,\the\textheight) ;
\stopMPcode
\stoptyping

However, in \CONTEXT\ \MKIV\ this method is no longer recomended as all
processing happens in the same run anyway.

% beware: extensive scaling can make acrobat crash and okular drop the !

\startbuffer[lioncode]
\startMPcode
numeric w, h ; w := \the\textwidth ; h := w/2 ;

picture p ; p := btex \colored[r=.375,g=.375]{Meta is a female lion!} etex
    xysized (w,h) ;
picture q ; q := btex \colored[r=.625]       {Meta is a female lion!} etex
    xysized (w,h) ;

path b ; b := boundingbox p ; draw p ;

for i=(.28w,.90h),(.85w,.90h),(w,.05h) :
  picture r ; r := q ;
  path s ; s := (fullsquare xscaled .05w yscaled .4h) shifted i ;
  clip r to s ; draw r ; % draw s ;
endfor ;

setbounds currentpicture to b ;
\stopMPcode
\stopbuffer

\typebuffer[lioncode]

\in {Figure} [lionclip] shows the previous sentence in a slightly different look.
You may consider coloring the dots to be an exercise in clipping.

\getbuffer[pos]

\placefigure
  [here][lionclip]
  {An example of clipping.}
  {\getbuffer[lioncode]}

\resetMPenvironment

An environment can be reset with \typ {\resetMPenvironment} or by passing \type
{reset} as first argument:

\starttyping
\startMPenvironment[reset]
  \usetypescript[postscript][texnansi] % mkii
  \setupbodyfont[postscript]
\stopMPenvironment
\stoptyping

So, to summarize: if you're using \CONTEXT\ \MKIV\ you might as well forgot what
you just read.

\stopsection

\startsection[title={Labels}]

\index{labels}

In \METAPOST\ you can use the \type {label} macro to position text at certain
points.

\starttyping
label("x", origin) ;
\stoptyping

The font and scale are determined by two variables, \type {defaultfont} and \type
{defaultscale}, the former expecting the name of a font in the form of a string,
the latter expecting a numeric to be used in the scaling of the font. Should you
choose not to set these yourself, they default to \type {"Mono"} and \type
{1.0}, respectively. However, you can change the defaults as follows:

\starttyping
defaultfont  := "texgyrepagella-regular*default" ;
defaultscale := 1.2 ;
\stoptyping

These settings selects Pagella at about 12pt. You can also set these variables
to \CONTEXT\ related values. For \CONTEXT\ graphics they are set to:

\starttyping
defaultfont  := "\truefontname{Regular}*default" ;
defaultscale := \the\bodyfontsize/10 ;
\stoptyping

This means that they will adapt themselves to the current body font (in this
document we get \truefontname{Regular}) and the current size of the bodyfont
(here \the\bodyfontsize/10).

\stopsection

\startsection[title={\TeX\ text}]

\index{text}

In the next example we will use a special mechanism for building graphics step by
step. The advantage of this method is that we can do intermediate calculations in
\TEX. Our objective is to write a macro that draws text along a circular path.
While doing so we want to achieve the following:

\startitemize[packed]
\item  the text should be properly kerned, i.e.\ the
       spacing between characters should be optimal,
\item  the position on the circle should vary, and
\item  the radius of the circle should vary.
\stopitemize

This implementation is not the most straightforward one, but by doing it step by
step, at least we see what is involved. Later, we will see a better method. If
you run these examples yourself, you must make sure that the \TEX\ environment of
your document matches the one used by \METAPOST.

We let the bodyfont match the font used in this document, and define \type
{RotFont} to be the regular typeface, the one you are reading right now, but
bold.

\startbuffer
\definefont[RotFont][RegularBold*default]
\stopbuffer

\typebuffer \getbuffer

Since \METAPOST\ is unaware of kerning, we have to use \TEX\ to keep track of the
positions. We will split the text into tokens (often characters) and store the
result in an array of pictures (\type {pic}). We will also store the accumulated
width in an array (\type {len}). The number of characters is stored in~\type {n}.
In a few paragraphs we will see why the other arrays are needed.

While defining the graphic, we need \TEX\ to do some calculations. Therefore, we
will use \typ {\startMPdrawing ... \stopMPdrawing} to stepwise construct the
definition. The basic pattern we will follow is:

\starttyping
\resetMPdrawing
\startMPdrawing
  metapost code
\stopMPdrawing
tex code
\startMPdrawing
  metapost code
\stopMPdrawing
\MPdrawingdonetrue
\getMPdrawing
\stoptyping

In the process, we will use a few variables. We will store the individual
characters of the text in the variable \type {pic}, its width in \type {wid} and
the length of the string so far in \type {len}. Later we will use the \type {pos}
array to store the position where a character ends up. The variable \type {n}
holds the number of tokens.

\startbuffer[init]
\resetMPdrawing
\startMPdrawing
  picture pic[] ;
  numeric wid[], len[], pos[], n ;
  wid[0] := len[0] := pos[0] := n := 0 ;
\stopMPdrawing
\stopbuffer

\typebuffer[init]

We also started fresh by resetting the drawing. From now on, each start command
will add some more to this graphic. The next macro is responsible for collecting
the data. Each element is passed on to \TEX, using the \type {btex} construct.
So, \METAPOST\ itself will call \TEX !

\startbuffer[toks]
\def\whatever#1%
  {\appendtoks#1\to\MPtoks
   \setbox\MPbox=\hbox{\bfd\the\MPtoks}%
   \startMPdrawing
     n := n + 1 ; len[n] := \the\wd\MPbox ;
   \stopMPdrawing
   \startMPdrawing[-]
     pic[n] := textext("\bfd\setstrut\strut#1") ;
     pic[n] := pic[n] shifted - llcorner pic[n] ;
   \stopMPdrawing}

\handletokens MetaPost is Fun!\with\whatever
\stopbuffer

\typebuffer[toks]

We use the low level \CONTEXT\ macro \type {\appendtoks} to extend the token list
\type {\MPtoks}. The \type {\handletokens} macro passes each token (character) of
\typ {MetaPost is Fun!} to the macro \type {\whatever}. The tokens are appended
to the token register \type {\MPtoks} (already defined). Then we typeset the
content of \type {\MPtoks} in \type {\MPbox} (also already defined). The width of
the box is passed to \METAPOST\ and stored in \type {len}.

By default the content of the drawing is expanded, which means that the macro is
replaced by its current meaning, so the current width ends up in the \METAPOST\
file. The next part of the drawing, starting with \type {btex}, puts the token in
a picture. This time we don't expand the drawing, since we want to pass font
information. Here, the \type {[-]} suppresses expansion of \typ {btex \bfd #1
etex}. The process is iterated by \type {\handletokens} for each character of the
text \typ {MetaPost is Fun!}.

Before we typeset the text, now available in pieces in \type {pic}, in a circle,
we will first demonstrate what they look like. You may like to take a look at the
file \type {mpgraph.mp} to see what is passed to \METAPOST.

\startbuffer[test]
\startMPdrawing
  pair len ; len := origin ;
  for i=1 upto n :
    draw pic[i] shifted len ;
    draw boundingbox pic[i] shifted len
      withpen pencircle scaled .25pt withcolor red ;
    len := len+(xpart urcorner pic[i]-xpart llcorner pic[i],0) ;
  endfor ;
\stopMPdrawing
\stopbuffer

\typebuffer[test]

\startbuffer[show]
\MPdrawingdonetrue\getMPdrawing
\stopbuffer

We can call up this drawing with \type {\getMPdrawing}, but first we inform the
compiler that our \METAPOST\ drawing is completed.

\typebuffer[show]

This results in:

\startlinecorrection[blank]
\getbuffer[init,toks,test,show]
\stoplinecorrection

Compare this text with the text as typeset by \TEX:

\blank \start \bfd MetaPost is Fun!\par \stop \blank

and you will see that the text produced by \METAPOST\ is not properly kerned.
When putting characters after each other, \TEX\ uses the information available in
the font, to optimize the spacing between characters, while \METAPOST\ looks at
characters as separate entities. But, since we have stored the optimal spacing in
\type {len}, we can let \METAPOST\ do a better job. Let's first calculate the
correction needed.

\startbuffer[kern]
\startMPdrawing
  for i=1 upto n :
    wid[i] := abs(xpart urcorner pic[i] - xpart llcorner pic[i]) ;
    pos[i] := len[i]-wid[i] ;
  endfor ;
\stopMPdrawing
\stopbuffer

\typebuffer[kern]

This compares well to the text as typeset by \TEX:

\blank \start \bfd MetaPost is Fun!\par \stop \blank

We can now use the values in \type {pos} to position the pictures according to
what \TEX\ considered to be the best (relative) position.

\startbuffer[test]
\startMPdrawing
  for i=1 upto n :
    draw pic[i] shifted (pos[i],0) ;
    draw boundingbox pic[i] shifted (pos[i],0)
      withpen pencircle scaled .25pt withcolor red ;
  endfor ;
\stopMPdrawing
\stopbuffer

\typebuffer[test]

That this correction is adequate, is demonstrated in the next graphic. If you
look closely, you will see that for instance the \quote {o} is moved to the left,
under the capital \quote {P}.

\startlinecorrection[blank]
\getbuffer[init,toks,kern,test,show]
\stoplinecorrection

When we want to position the pictures along a circle, we need to apply some
rotations, especially because we want to go clockwise. Since we don't want to use
\quote {complicated} math or more advanced \METAPOST\ code yet, we will do it in
steps.

\startbuffer[swap]
\startMPdrawing
  for i=1 upto n:
    pic[i] := pic[i] rotatedaround(origin,-270) ;
  endfor ;
\stopMPdrawing
\stopbuffer

\typebuffer[swap]

\startlinecorrection[blank]
\getbuffer[init,toks,kern,swap,test,show]
\stoplinecorrection

\startbuffer[cent]
\startMPdrawing
  for i=1 upto n :
    pic[i] := pic[i]
      shifted (0,ypart -.5[ulcorner pic[i],llcorner pic[i]]) ;
  endfor ;
\stopMPdrawing
\stopbuffer

We will now center the pictures around the baseline. Centering comes down to
shifting over half the height of the picture. This can be expressed by:

\starttyping
ypart -.5[ulcorner pic[i],llcorner pic[i]]
\stoptyping

but different ways of calculating the distance are possible
too.

\typebuffer[cent]

So, now we have:

\startlinecorrection[blank]
\getbuffer[init,toks,kern,swap,cent,test,show]
\stoplinecorrection

When we typeset on a (half) circle, we should map the actual length onto a
partial circle. We denote the radius with an~\type {r} and shift the pictures to
the left.

\startbuffer[shif]
\startMPdrawing
  numeric r ; r := len[n]/pi ;
  for i=1 upto n :
    pic[i] := pic[i] shifted (-r,0) ;
  endfor ;
\stopMPdrawing
\stopbuffer

\typebuffer[shif]

You can now use the following code to test the current state of the pictures. Of
course this code should not end up in the final definitions.

\startbuffer[test]
\startMPdrawing
  draw origin
    withpen pencircle scaled 5pt withcolor red ;
  for i=1 upto n :
    draw pic[i] ;
    draw boundingbox pic[i]
      withpen pencircle scaled .25pt withcolor red ;
  endfor ;
\stopMPdrawing
\stopbuffer

\typebuffer[test]

\startlinecorrection[blank]
\getbuffer[init,toks,kern,swap,cent,shif,test,show]
\stoplinecorrection

Later we will write a compact, efficient macro to take care of rotation. However,
for the moment, so as not to overwhelm you with complicated code, we will rotate
each individual picture with the following code fragment.

\startbuffer[rots]
\startMPdrawing
  numeric delta, extra, radius, rot[] ;

  delta  := extra := radius := 0 ;

  for i=1 upto n :
    rot[i] := extra+delta-((pos[i]+.5wid[i])/len[n])*(180+2delta) ;
  endfor ;
\stopMPdrawing
\stopbuffer

\typebuffer[rots]

Here we introduce a few variables that we can use later to tune the result a bit.
With \type {delta}, the space between the characters can be increased, while
\type {extra} rotates the whole string around the origin. The \type {radius}
variable can be used to increase the distance to the origin. Without these
variables, the assignment would have been:

\starttyping
rot[i] := ((pos[i]+.5wid[i])/len[n])*180 ;
\stoptyping

Placing the pictures is now rather easy:

\startbuffer[done]
\startMPdrawing
  for i=1 upto n :
    draw pic[i] shifted (-radius,0) rotatedaround(origin,rot[i]) ;
  endfor ;
\stopMPdrawing
\stopbuffer

\typebuffer[done]

The pictures are now positioned on half a circle, properly kerned.

\startlinecorrection[blank]
\getbuffer[init,toks,kern,swap,cent,shif,rots,done,show]
\stoplinecorrection

A bit more insight is given in the next picture:

\startbuffer[test]
\startMPdrawing
  def moved(expr i) =
    shifted (-radius,0) rotatedaround(origin,rot[i])
  enddef ;
  pickup pencircle scaled .5pt ;
  for i=1 upto n :
    draw pic[i] moved(i) ;
    draw boundingbox pic[i] moved(i) withcolor red ;
    draw origin -- center pic[i] moved(i) withcolor green ;
  endfor ;
  draw tcircle scaled 2r withcolor blue ;
\stopMPdrawing
\stopbuffer

\startlinecorrection[blank]
\getbuffer[init,toks,kern,swap,cent,shif,rots,test,show]
\stoplinecorrection

This was defined as follows. The path variable \type {tcycle} is predefined to
the top half of a fullcircle.

\typebuffer[test]

We will now package all of this into a nice, efficient macro, using, of course,
the predefined scratch registers \type {\MPtoks} and \type {\MPbox}. First we
define the token processor. Note again the expansion inhibition switch \type
{[-]}.

\startbuffer
\def\processrotationtoken#1%
  {\appendtoks#1\to\MPtoks
   \setbox\MPbox=\hbox{\RotFont\the\MPtoks}%
   \startMPdrawing
     n := n + 1 ; len[n] := \the\wd\MPbox ;
   \stopMPdrawing
   \startMPdrawing[-]
     pic[n] := textext("\RotFont\setstrut\strut#1") ;
     pic[n] := pic[n] shifted - llcorner pic[n] ;
   \stopMPdrawing}
\stopbuffer

\typebuffer

\getbuffer

The main macro is a bit more complicated but by using a few scratch numerics, we
can keep it readable.

\startbuffer
\def\rotatetokens#1#2#3#4% delta extra radius tokens
  {\vbox\bgroup
   \MPtoks\emptytoks
   \resetMPdrawing
   \startMPdrawing
     picture pic[] ;
     numeric wid, len[], rot ;
     numeric delta, extra, radius, n, r ;
     len[0] := n := 0 ;
     delta  := #1 ; extra := #2 ; radius := #3 ;
   \stopMPdrawing
   \handletokens#4\with\processrotationtoken
   \startMPdrawing
     r := len[n]/pi ;
     for i=1 upto n :
       wid := abs(xpart lrcorner pic[i] -
                  xpart llcorner pic[i]) ;
       rot := extra + delta -
              ((len[i]-.5wid)/len[n]) * (180+2delta) ;
       draw pic[i]
         rotatedaround (origin,-270) shifted (-r-radius,
         ypart -.5[ulcorner pic[i], llcorner pic[i]])
         rotatedaround (origin,rot) ;
     endfor ;
   \stopMPdrawing
   \MPdrawingdonetrue
   \getMPdrawing
   \resetMPdrawing
   \egroup}
\stopbuffer

\typebuffer

\getbuffer

\startbuffer
\startcombination[3*1]
  {\rotatetokens {0} {0}{0}{Does it work ok?}} {A}
  {\rotatetokens{20} {0}{0}{Does it work ok?}} {B}
  {\rotatetokens{20}{30}{0}{Does it work ok?}} {C}
\stopcombination
\stopbuffer

We can use this macro as follows:

\typebuffer

\startlinecorrection[blank]
\getbuffer
\stoplinecorrection

The previous macro is not really an example of generalization, but we used it for
demonstrating how to build graphics in a stepwise way. If you put the steps in
buffers, you can even combine steps and replace them at will. This is how we made
the previous step by step examples: We put each sub||graphic in a buffer and then
called the ones we wanted.

We now present a more general approach to typesetting along a given path. This
method is not only more robust and general, it is also a more compact definition,
especially if we omit the tracing and testing code. We use a familiar auxiliary
definition. The \type {\setstrut} and \type {\strut} commands ensure that the
lines have the proper depth and height.

\startbuffer
\def\processfollowingtoken#1%
  {\appendtoks#1\to\MPtoks
   \setbox\MPbox=\hbox{\RotFont\setstrut\strut\the\MPtoks}%
   \startMPdrawing
     n := n + 1 ; len[n] := \the\wd\MPbox ;
   \stopMPdrawing
   \startMPdrawing[-]
     pic[n] := btex \RotFont\setstrut\strut#1 etex ;
     pic[n] := pic[n] shifted -llcorner pic[n] ;
   \stopMPdrawing}
\stopbuffer

\typebuffer \getbuffer

In \MKII\ the previous code is collected in the macro \type {\followtokens} but
in \MKIV\ we use a different approach. There we use a mix of \TEX, \METAPOST, and
\LUA\ to define that macro. The principles remain the same but the code is more
robust.

\useMPlibrary[txt]

So, how does this compare to earlier results? The original, full text as typeset
by \TEX, looks like:

\blank \start \RotFont We now follow some arbitrary path ... \stop \blank

In the examples, the text is typeset along the path with:

\startbuffer[toks]
\followtokens{We now follow some arbitrary path ...}
\stopbuffer

\typebuffer[toks]

%  \startlinecorrection[blank]
%  \getbuffer[toks]
%  \stoplinecorrection

%  Since we did not set a path, a dummy path is used. We can provide a path by
%  (re)defining the graphic \type {followtokens}.

%  \startbuffer[trac]
%  \startMPinclusions
%    boolean TraceRot ; TraceRot := true ;
%  \stopMPinclusions
%  \stopbuffer

\startbuffer[draw]
\startuseMPgraphic{followtokens}
  path RotPath ; RotPath := fullcircle ;
\stopuseMPgraphic
\stopbuffer

\startbuffer
\typebuffer[draw]
\startlinecorrection[blank]
\hbox
  {\getbuffer[draw,toks]\hskip1cm
   \getbuffer[trac,draw,toks]}
\stoplinecorrection
\stopbuffer

\getbuffer

\startbuffer[draw]
\startuseMPgraphic{followtokens}
  path RotPath ; RotPath := reverse fullcircle ;
\stopuseMPgraphic
\stopbuffer

\getbuffer

\startbuffer[draw]
\startuseMPgraphic{followtokens}
  path RotPath ; RotPath := (-3cm,-1cm)--(0,1cm)--(3cm,-1cm) ;
\stopuseMPgraphic
\stopbuffer

\getbuffer

\startbuffer[draw]
\startuseMPgraphic{followtokens}
  path RotPath ; RotPath := (-3cm,0)--(3cm,1cm) ;
\stopuseMPgraphic
\stopbuffer

\getbuffer

\startbuffer[draw]
\startuseMPgraphic{followtokens}
  path RotPath ; RotPath := (-3cm,0)..(-1cm,1cm)..(3cm,0) ;
\stopuseMPgraphic
\stopbuffer

\getbuffer

\startbuffer[draw]
\startuseMPgraphic{followtokens}
  path RotPath ; RotPath := (-3cm,0)..(-1cm,1cm)..(0cm,-2cm)..(3cm,0) ;
\stopuseMPgraphic
\stopbuffer

\getbuffer

When turned on, tracing will produce bounding boxes as well as draw the path.
Tracing can be turned on by saying:

\typebuffer[trac]

% let's turn it off now

\startMPinclusions
  boolean TraceRot ; TraceRot := false ;
\stopMPinclusions

The next example is dedicated to Giuseppe Bilotta who wants to handle multiple
strings and uses a patched version of \type {\followtokens}. To avoid a
complicated explanation, we will present an alternative here that uses overlays.
This method also avoids complicated path definitions.

\startbuffer
\startoverlay
  {\startuseMPgraphic{followtokens}
     draw fullcircle scaled 5cm .
       withpen pencircle scaled 1pt withcolor .625yellow ;
     draw fullsquare scaled 5.25cm
       withpen pencircle scaled 1pt withcolor .625red ;
     drawoptions (withcolor .625red) ;
     path RotPath ; RotPath := halfcircle scaled 5cm ;
     setbounds currentpicture to boundingbox fullcircle scaled 5.25cm ;
   \stopuseMPgraphic
   \followtokens { Met{\`a} superiore }}
  {\startuseMPgraphic{followtokens}
     drawoptions (withcolor .625red) ;
     path RotPath ; RotPath := halfcircle rotated 90 scaled 5cm ;
     setbounds currentpicture to boundingbox fullcircle scaled 5.25cm ;
   \stopuseMPgraphic
   \followtokens { {$\star$} }}
  {\startuseMPgraphic{followtokens}
     drawoptions (withcolor .625red) ;
     path RotPath ; RotPath := halfcircle rotated 180 scaled 5cm ;
     setbounds currentpicture to boundingbox fullcircle scaled 5.25cm ;
   \stopuseMPgraphic
   \followtokens { Met{\`a} inferiore }}
  {\startuseMPgraphic{followtokens}
     drawoptions (withcolor .625red) ;
     path RotPath ; RotPath := halfcircle rotated 270 scaled 5cm ;
     setbounds currentpicture to boundingbox fullcircle scaled 5.25cm ;
   \stopuseMPgraphic
   \followtokens { {$\star$} }}
\stopoverlay
\stopbuffer

\typebuffer

In order to fool the overlay macro that each graphic has the same size, we force
a bounding box.

\startlinecorrection[blank]
\getbuffer
\stoplinecorrection

\stopsection

\startsection[title={Talking to \TEX}]

Sometimes, others may say oftentimes, we are in need for some fancy typesetting.
If we want to typeset a paragraph of text in a non standard shape, like a circle,
we have to fall back on \type {\parshape}. Unfortunately, \TEX\ is not that
strong in providing the specifications of more complicated shapes, unless you are
willing to do some complicated arithmetic \TEX. Given that \METAPOST\ knows how
to deal with shapes, the question is: \quotation {Can \METAPOST\ be of help?}

In the process of finding out how to deal with this, we first define a simple
path. Because we are going to replace pieces of code, we will compose the graphic
from components. First, we create the path.

\startbuffer
\startuseMPgraphic{text path}
  path p ; p := ((0,1)..(-1,0)..(1,0)--cycle) scaled 65pt ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

This shape is not that beautiful, but it has a few characteristics that will help
us to identify bordercases.

\startbuffer
\startuseMPgraphic{text draw}
  drawarrow p withpen pencircle scaled 1pt withcolor red ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

Now we use \CONTEXT's \type {\includeMPgraphic} command to build our graphic from
the previously defined components.

\startbuffer
\startuseMPgraphic{text}
  \includeMPgraphic{text path}
  \includeMPgraphic{text draw}
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

When called with \type {\useMPgraphic{text}}, we get:

\startlinecorrection[blank]
\useMPgraphic{text}
\stoplinecorrection

For the moment we start the path at $(x=0,y>0)$, but later using more complicated
macros, we will see that we can use arbitrary paths.

We are going to split the path in two, and will use the points that make up the
bounding box as calcutated by \METAPOST. The next graphic shows one of these
points, the lower left corner, available as point \typ {llcorner p}.

\startbuffer
\startuseMPgraphic{text draw}
  draw             p withpen pencircle scaled 3pt withcolor red ;
  draw boundingbox p withpen pencircle scaled 1pt ;
  draw llcorner    p withpen pencircle scaled 5pt ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

\startlinecorrection[blank]
\useMPgraphic{text}
\stoplinecorrection

The five points that \METAPOST\ can report for each path or picture are:

\starttabulate[|Tl|l|]
\NC llcorner \NC lower left  corner            \NC \NR
\NC lrcorner \NC lower right corner            \NC \NR
\NC urcorner \NC upper right corner            \NC \NR
\NC ulcorner \NC upper left  corner            \NC \NR
\NC center   \NC intersection of the diagonals \NC \NR
\stoptabulate

If we want to typeset text inside this circle, we need to know where a line
starts and ends. Given that lines are horizontal and straight, we therefore need
to calculate the intersection points of the lines and the path. As a first step,
we calculate the top and bottom of the path and after that we split off the left
and right path.

\startbuffer
\startuseMPgraphic{text split}
  pair t, b ; path l, r ;

  t := (ulcorner p -- urcorner p) intersectionpoint p ;
  b := (llcorner p -- lrcorner p) intersectionpoint p ;

  l := p cutbefore t ; l := l cutafter b ;
  r := p cutbefore b ; r := r cutafter t ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

The \type {intersectionpoint} macro returns the point where two paths cross. If
the paths don't cross, an error is reported, when the paths cross more times,
just one point is returned. The \type {cutafter} and \type {cutbefore} commands
do as their names say and return a path.

In the \type {text split} code fragment, \type {t} and \type {b} are the top
points of the main path, while \type {l} and \type {r} become the left and right
half of path \type {p}.

We now draw the original path using a thick pen and both halves with a thinner
pen on top of the original. The arrows show the direction.

\startbuffer
\startuseMPgraphic{text draw}
  draw      p withpen pencircle scaled 3pt withcolor red ;
  drawarrow l withpen pencircle scaled 1pt withcolor green ;
  drawarrow r withpen pencircle scaled 1pt withcolor blue ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

We use \type {\includeMPgraphic} to assemble the components:

\startbuffer
\startuseMPgraphic{text}
  \includeMPgraphic{text path}
  \includeMPgraphic{text split}
  \includeMPgraphic{text draw}
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

This graphic is typeset with \type {\useMPgraphic{text}}:

\startlinecorrection[blank]
\useMPgraphic{text}
\stoplinecorrection

Before we are going to use them, we define some variables that specify the text.
We use a baseline distance of 8~points. The part of the line above the baseline
is 7.2~points, while the (maximum) depth is 2.8~points. These ratios are the ones
we use in \CONTEXT. Because we don't want the text to touch the circle so we
define an offset too.

\startbuffer
\startuseMPgraphic{text vars}
  MyOffset  := LineHeight/2 ;
  MyTopSkip := StrutHeight ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

We more or less achieve the offset by scaling the path. In doing so, we use the
width and height, which we call \type {hsize} and \type {vsize}, thereby
conforming to the \TEX\ naming scheme.

First we calculate both dimensions from the bounding box of the path. Next we
down scale the path to compensate for the offset. When done, we recalculate the
dimensions.

\startbuffer
\startuseMPgraphic{text move}
  pair t, b ; path q, l, r ;

  hsize := xpart lrcorner p - xpart llcorner p ;
  vsize := ypart urcorner p - ypart lrcorner p ;

  q := p xscaled ((hsize-2MyOffset)/hsize)
         yscaled ((vsize-2MyOffset)/vsize) ;

  hsize := xpart lrcorner q - xpart llcorner q ;
  vsize := ypart urcorner q - ypart lrcorner q ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

\startbuffer
\startuseMPgraphic{text split}
  t := (ulcorner q -- urcorner q) intersectionpoint q ;
  b := (llcorner q -- lrcorner q) intersectionpoint q ;

  l := q cutbefore t ; l := l cutafter b ;
  r := q cutbefore b ; r := r cutafter t ;
\stopuseMPgraphic
\stopbuffer

We adapt the \type {text split} code to use the reduced path
instead of the original.

\typebuffer \getbuffer

\startbuffer
\startuseMPgraphic{text draw}
  drawarrow p withpen pencircle scaled 1pt withcolor red ;
  draw      t withpen pencircle scaled 2pt ;
  draw      b withpen pencircle scaled 2pt ;
  drawarrow l withpen pencircle scaled 1pt withcolor green ;
  drawarrow r withpen pencircle scaled 1pt withcolor blue ;
\stopuseMPgraphic
\stopbuffer

In order to test what we have reached so far, we draw the original path, the left
and right part of the reduced path, and both the top and bottom point.

\typebuffer \getbuffer

Again we use \type {\includeMPgraphic} to combine the
components into a graphic.

\startbuffer
\startuseMPgraphic{text}
  \includeMPgraphic{text path} \includeMPgraphic{text vars}
  \includeMPgraphic{text move} \includeMPgraphic{text split}
  \includeMPgraphic{text draw}
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

Then we use \type {\useMPgraphic{text}} to call up the picture.

\startlinecorrection[blank]
\useMPgraphic{text}
\stoplinecorrection

The offset is not optimal. Note the funny gap at the top. We could try to fix
this, but there is a better way to optimize both paths.

We lower the top edge of \type {q}'s bounding box by \type {MyTopSkip}, then cut
any part of the left and right pieces of \type {q} that lie above it. Similarly,
we raise the bottom edge and cut off the pieces that fall below this line.

\startbuffer
\startuseMPgraphic{text cutoff}
  path tt, bb ;

  tt := (ulcorner q -- urcorner q) shifted (0,-MyTopSkip) ;
  bb := (llcorner q -- lrcorner q) shifted (0,StrutDepth) ;

  l := l cutbefore (l intersectionpoint tt) ;
  l := l cutafter  (l intersectionpoint bb) ;
  r := r cutbefore (r intersectionpoint bb) ;
  r := r cutafter  (r intersectionpoint tt) ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

Because we use \type {\includeMPgraphic} to construct the graphic, we can
redefine \type {text draw} to show the result of this effort.

\startbuffer
\startuseMPgraphic{text draw}
  drawarrow p withpen pencircle scaled 1pt withcolor red ;
  drawarrow l withpen pencircle scaled 1pt withcolor green ;
  drawarrow r withpen pencircle scaled 1pt withcolor blue ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

The \type {text} graphic now becomes:

\startbuffer
\startuseMPgraphic{text}
  \includeMPgraphic{text path}   \includeMPgraphic{text vars}
  \includeMPgraphic{text move}   \includeMPgraphic{text split}
  \includeMPgraphic{text cutoff} \includeMPgraphic{text draw}
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

Or, as graphic:

\startlinecorrection[blank]
\useMPgraphic{text}
\stoplinecorrection

We are now ready for an attempt to calculate the shape of the text. For each
line, we have to calculate the left and right intersection points, and since a
line has a height and depth, we have to determine which part touches first.

\startbuffer
\startuseMPgraphic{text calc}
  vardef found_point (expr lin, pat, sig) =
    pair a, b ;
    a := pat intersection_point (lin shifted (0,StrutHeight)) ;
    if intersection_found :
      a := a shifted (0,-StrutHeight) ;
    else :
      a := pat intersection_point lin ;
    fi ;
    b := pat intersection_point (lin shifted (0,-StrutDepth)) ;
    if intersection_found :
      if sig :
        if xpart b > xpart a : a := b shifted (0,StrutDepth) fi ;
      else :
        if xpart b < xpart a : a := b shifted (0,StrutDepth) fi ;
      fi ;
    fi ;
    a
  enddef ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

Instead of using \METAPOST's \type {intersectionpoint} macro, we use one that
comes with \CONTEXT. That way we don't get an error message when no point is
found, and can use a boolean flag to take further action. Since we use a \type
{vardef}, all calculations are hidden and the~\type {a} at the end is returned,
so that we can use this macro in an assignment. The \type {sig} variable is used
to distinguish between the beginning and end of a line (the left and right
subpath).

\startbuffer
\startuseMPgraphic{text step}
  path line; pair lll, rrr ;

  for i=MyTopSkip step LineHeight until vsize :

    line := (ulcorner q -- urcorner q) shifted (0,-i) ;

    lll := found_point(line,l,true ) ;
    rrr := found_point(line,r,false) ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

Here we divide the available space in lines. The first line starts at \type
{StrutHeight} from the top.

We can now finish our graphic by visualizing the lines. Both the height and depth
of the lines are shown.

\startbuffer
\startuseMPgraphic{text line}
    fill (lll--rrr--rrr shifted (0,StrutHeight)--lll
      shifted (0,StrutHeight)--cycle) withcolor .5white ;
    fill (lll--rrr--rrr shifted (0,-StrutDepth)--lll
      shifted (0,-StrutDepth)--cycle) withcolor .7white ;
    draw lll withpen pencircle scaled 2pt ;
    draw rrr withpen pencircle scaled 2pt ;
    draw (lll--rrr) withpen pencircle scaled .5pt ;
\stopuseMPgraphic

\startuseMPgraphic{text done}
  endfor ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

The result is still a bit disappointing.

\startbuffer
\startuseMPgraphic{text}
  \includeMPgraphic{text path}   \includeMPgraphic{text vars}
  \includeMPgraphic{text move}   \includeMPgraphic{text split}
  \includeMPgraphic{text cutoff} \includeMPgraphic{text draw}
  \includeMPgraphic{text calc}   \includeMPgraphic{text step}
  \includeMPgraphic{text line}   \includeMPgraphic{text done}
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer
\startlinecorrection[blank]
\useMPgraphic{text}
\stoplinecorrection

In order to catch the overflow at the bottom, we need to change the \type
{for}||loop a bit, so that the number of lines does not exceed the available
space. The test that surrounds the assignment of \type {vvsize} makes sure that
we get better results when we (on purpose) take a smaller height.

\startbuffer
\startuseMPgraphic{text step}
  path line; pair lll, rrr ; numeric vvsize ;

  if (StrutHeight+StrutDepth<LineHeight) :
    vvsize := vsize ;
  else :
    vvsize := (vsize div LineHeight) * LineHeight ;
  fi ;

  for i=MyTopSkip step LineHeight until vvsize :

    line := (ulcorner q -- urcorner q) shifted (0,-i) ;

    lll := found_point(line,l,true ) ;
    rrr := found_point(line,r,false) ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

\startlinecorrection[blank]
\useMPgraphic{text}
\stoplinecorrection

We can manipulate the heigth and depth of the lines to give different (and maybe
better) results.

\startbuffer
\startuseMPgraphic{text vars}
MyOffset  := .5LineHeight ;
MyTopSkip := StrutHeight ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

\startlinecorrection[blank]
\useMPgraphic{text}
\stoplinecorrection

This kind of graphic trickery in itself is not enough to get \TEX\ into
typesetting within the bounds of a closed curve. Since \METAPOST\ can write
information to a file, and \TEX\ can read such a file, a natural way to handle
this is to let \METAPOST\ write a \type {\parshape} specification.

\startbuffer
\startuseMPgraphic{text macro}
  def provide_parshape (expr p, MyOffset, LineHeight,
    StrutHeight, StrutDepth, MyTopSkip) =

    \includeMPgraphic{text move}
    \includeMPgraphic{text split}
    \includeMPgraphic{text cutoff}
    \includeMPgraphic{text draw}
    \includeMPgraphic{text calc}
    \includeMPgraphic{text loop}
    \includeMPgraphic{text save}

  enddef ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

We have to adapt the for||loop to register the information about the lines. After
the loop we write those values to a file using another loop.

\startbuffer
\startuseMPgraphic{text loop}
  path line; pair lll, rrr ; numeric vvsize, n ; n := 0 ;

  if (StrutHeight+StrutDepth<LineHeight) :
    vvsize := vsize ;
  else :
    vvsize := (vsize div LineHeight) * LineHeight ;
  fi ;

  for i=MyTopSkip step LineHeight until vvsize :

    line := (ulcorner q -- urcorner q) shifted (0,-i) ;

    lll := found_point(line,l,true ) ;
    rrr := found_point(line,r,false) ;

    n := n + 1 ;

    indent[n] := abs(xpart lll - xpart llcorner q) ;
    width[n]  := abs(xpart rrr - xpart lll) ;

  endfor ;
\stopuseMPgraphic

\startuseMPgraphic{text save}
  write "\parshape " & decimal n to "mfun-mp-data.txt" ;
  for i=1 upto n:
    write decimal indent[i]&"bp " &
          decimal  width[i]&"bp " to "mfun-mp-data.txt" ;
  endfor ;
  write EOF to "mfun-mp-data.txt" ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

We can call this macro using the part we used in the previous examples.

\startbuffer
\startuseMPgraphic{text}
  \includeMPgraphic{text macro}

  path p ; p := ((0,1)..(-1,0)..(1,0)--cycle) scaled 65pt ;

  provide_parshape
   (p,              % shape path
    .5*LineHeight,  % offset
    LineHeight,     % distance between lines
    StrutHeight,    % height of a line
    StrutDepth,     % depth of a line
    StrutHeight) ;  % height of first line
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

After we called \type {\useMPgraphic{text}}, the resulting file looks as follows.
You can call up this file by its anonymous name \type {\MPdatafile}, since this
macro gets the value of the graphic at hand.

\startnointerference
    \useMPgraphic{text}
\stopnointerference

\typefile{mfun-mp-data.txt}

So, reading in this file at the start of a paragraph will setup \TEX\ to follow
this shape.

The final implementation is a bit more complicated since it takes care of paths
that are not centered around the origin and don't start at the top point. We
achieve this by moving the path to the center:

\starttyping
cp := center p ; q := p shifted - cp ;
\stoptyping

The arbitrary starting point is taken care of by a slightly more complicated path
cutter. First we make sure that the path runs counterclockwise.

\starttyping
if xpart directionpoint t of q < 0 : q := reverse q fi ;
\stoptyping

Knowing this, we can split the path in two, using a slightly different splitter:

\starttyping
l := q cutbefore t ;
l := l if xpart point 0 of q < 0 : & q fi cutafter b ;
r := q cutbefore b ;
r := r if xpart point 0 of q > 0 : & q fi cutafter t ;
\stoptyping

As always, when implementing a feature like this, some effort goes into a proper
user interface. In doing so, we need some \TEX\ trickery that goes beyond this
text, like collecting text and splitting of the part needed. Also, we want to be
able to handle multiple shapes at once, like the next example demonstrates.

\stopsection

\startsection[title={Libraries}]

\index{graphics+libraries}

In \MKIV\ and \LMTX\ the \METAFUN\ driven text around a curve is a core
functionality. In \LMTX\ the specific paragraph shape are available in the core
too. Otherwise you need to load a module:

\startbuffer
\useMPlibrary[txt]
\stopbuffer

\typebuffer \getbuffer

We define four shapes. They are not really beautiful, but they demonstrate what
happens in border cases. For instance, too small first lines are ignored. First
we define a circle. Watch how the dimensions are set in the graphic. The
arguments passed to \type {build_parshape} are: path, an offset, an additional
horizontal and vertical displacement, the baseline distance, the height and depth
of the line, and the height of the first line (MyTopSkip in \TEX\ terminology). The
height and depth of a line are often called strut height and depth, with a strut
being an invisible character with maximum dimensions.

\startbuffer
\startuseMPgraphic{test 1}
  path p ; p := fullcircle scaled 6cm ;

  build_parshape(p,6pt,0,0,LineHeight,
    StrutHeight,StrutDepth,StrutHeight) ;

  draw p withpen pencircle scaled 1pt ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

The second shape is a diamond. This is a rather useless shape, unless the text
suits the small lines at the top and bottom.

\startbuffer
\startuseMPgraphic{test 2}
  path p ; p := fullsquare rotated 45 scaled 5cm ;

  build_parshape(p,6pt,0,0,LineHeight,
    StrutHeight,StrutDepth,StrutHeight) ;

  draw p withpen pencircle scaled 1pt ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

The third and fourth shape demonstrate that providing a suitable offset is not
always trivial.

\startbuffer
\startuseMPgraphic{test 3}
  numeric w, h ; w := h := 6cm ;
  path p ; p := (.5w,h) -- (0,h) -- (0,0) -- (w,0) &
    (w,0) .. (.75w,.5h) .. (w,h) & (w,h) -- cycle ;

  build_parshape(p,6pt,0,0,LineHeight,
    StrutHeight,StrutDepth,StrutHeight) ;

  draw p withpen pencircle scaled 1pt ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

Contrary to the first three shapes, here we use a different path for the
calculations and the drawing. Watch carefully! If, instead of an offset, we pass
a path, \METAPOST\ is able to calculate the right dimensions and offsets. This is
needed, since we need these later on.

\startbuffer
\startuseMPgraphic{test 4}
  numeric w, h, o ;

  def shape = (o,o) -- (w-o,o) & (w-o,o) .. (.75w-o,.5h) ..
    (w-2o,h-o) & (w-2o,h-o) -- (o,h-o) -- cycle
  enddef ;

  w := h := 6cm ; o := 6pt ; path p ; p := shape ;
  w := h := 6cm ; o := 0pt ; path q ; q := shape ;

  build_parshape(p,q,6pt,6pt,LineHeight,
    StrutHeight,StrutDepth,StrutHeight) ;

  draw q withpen pencircle scaled 1pt ;
\stopuseMPgraphic
\stopbuffer

\typebuffer \getbuffer

Since we also want these graphics as backgrounds, we define them as overlays. If
you don't want to show the graphic, you may omit this step.

\startbuffer
\defineoverlay[test 1][\useMPgraphic{test 1}]
\defineoverlay[test 2][\useMPgraphic{test 2}]
\defineoverlay[test 3][\useMPgraphic{test 3}]
\defineoverlay[test 4][\useMPgraphic{test 4}]
\stopbuffer

\typebuffer \getbuffer

As text, we use a quote from Douglas R.~Hofstadter's book \quotation {Metamagical
Themas, Questing for the Essence of Mind and Pattern}. Watch how we pass a list
of shapes.

\startbuffer[text]
\startshapetext[test 1,test 2,test 3,test 4]
  \forgetall % as it says
  \setupalign[verytolerant,stretch,normal]%
  \input douglas % Douglas R. Hofstadter
\stopshapetext
\stopbuffer

\typebuffer[text]

Finally we combine text and shapes. Since we also want a background, we use \type
{\framed}. The macros \type {\parwidth} and \type {\parheight} are automatically
set to the current shape dimensions. The normal result is shown in \in {figure}
[fig:shapes].

\startbuffer[shapes]
\startbuffer
\startcombination[2*2]
  {\framed[offset=overlay,frame=off,background=test 1]{\getshapetext}} {test 1}
  {\framed[offset=overlay,frame=off,background=test 2]{\getshapetext}} {test 2}
  {\framed[offset=overlay,frame=off,background=test 3]{\getshapetext}} {test 3}
  {\framed[offset=overlay,frame=off,background=test 4]{\getshapetext}} {test 4}
\stopcombination
\stopbuffer
\stopbuffer

\typebuffer[shapes]

\getbuffer[shapes]

By using a buffer we keep \type {\placefigure} readable.

\startbuffer[a]
\placefigure
  [here][fig:shapes]
  {A continuous text, typeset in a non||standard shape,
   spread over four areas, and right aligned.}
  {\getbuffer}
\stopbuffer

\startbuffer[b]
\placefigure
  [here][fig:shapes]
  {A continuous text, typeset in a non||standard shape,
   spread over four areas.}
  {\scale[factor=max,height=.9\textheight]{\getbuffer}}
\stopbuffer

\typebuffer[a]

\doifmodeelse{screen}{\getbuffer[text,b]}{\getbuffer[text,a]}

The traced alternative is shown in \in {figure} [fig:traced shapes]. This one is
defined as:

\startbuffer[a]
\placefigure
  [here][fig:traced shapes]
  {A continuous text, typeset in a non||standard shape,
   spread over four areas (tracing on).}
  {\startMPinclusions
     boolean trace_parshape ; trace_parshape := true ;
   \stopMPinclusions
   \getbuffer}
\stopbuffer

\startbuffer[b]
\placefigure
  [here][fig:traced shapes]
  {A continuous text, typeset in a non||standard shape,
   spread over four areas (tracing on).}
  {\startMPinclusions
     boolean trace_parshape ; trace_parshape := true ;
   \stopMPinclusions
   \scale[factor=max,height=.9\textheight]{\getbuffer}}
\stopbuffer

\typebuffer[a]

\doifmodeelse{screen}{\getbuffer[text,b]}{\getbuffer[text,a]}

% {\em This mechanism is still somewhat experimental and will be optimized and
% extended with name spaces and more.}

\blank

We can combine all those tricks, although the input is somewhat fuzzy. First we
define a quote typeset in a circular paragraph shape.

\startbuffer[shape]
\startuseMPgraphic{center}
  build_parshape(fullcircle scaled 8cm,0,0,0,LineHeight,
    StrutHeight,StrutDepth,StrutHeight) ;
\stopuseMPgraphic

\startshapetext[center]
  \input douglas
\stopshapetext

\defineoverlay[center][\useMPgraphic{center}]
\stopbuffer

\typebuffer[shape]

We will surround this text with a circular line, that we define as follows. By
using a buffer we keep things organized.

\startbuffer
\startbuffer[circle]
\startuseMPgraphic{followtokens}
  path RotPath ; RotPath := reverse fullcircle
    rotatedaround(origin,90)
    xscaled \overlaywidth yscaled \overlayheight ;
  drawoptions (withcolor .625red) ;
\stopuseMPgraphic

\followtokens
  {This is just a dummy text, kerned by \TeX\ and typeset
   in a circle using \MetaPost.\quad}
\stopbuffer

\defineoverlay[edge][{\getbuffer[circle]}]
\stopbuffer

\typebuffer \getbuffer

The text and graphics come together in a framed text:

\startbuffer
\startbuffer[quote]
\framed
  [offset=24pt,
   background=edge,
   frame=off,
   backgroundoffset=-18pt]
  {\getshapetext}
\stopbuffer

\placefigure
  {One more time Hofstadter's quotation (normal).}
  {\getbuffer[shape,quote]}

\placefigure
  {One more time Hofstadter's quotation (traced).}
  {\startMPinclusions
      boolean TraceRot ; TraceRot := true ;
   \stopMPinclusions
   \getbuffer[shape,quote]}
\stopbuffer

\typebuffer \getbuffer

% {\em Here also, I will rewrite things a bit so that we can avoid \type
% {\startMPdrawing} outside the macro, and thereby avoid problems. I can also add
% the maps cdrom cover as example.}

\stopsection

% \startsection[title={Visualizing \TEX}]
%
% The next example is a bit out of place in this manual, but nevertheless
% demonstrates how one can use \METAPOST\ to get insight in what \TEX\ is doing
% inside.
%
% The author of \PDFTEX, \THANH, has extended the paragraph builder with a
% provision for protruding characters and glyphs substitution, also known as {\it
% hz} (which stands for Hermann Zapf). The {\it hz} optimization involves an
% additional pass over the lines and|/|or paragraph, in order to determine how
% inconsistency in gaps can be reduced by substituting an \quote {\scale [sx=1.01]
% {a}} by an \quote {\scale [sx=5] {a}} or \quote {\scale [sx=.5] {a}}. In \in
% {figure} [fig:hz] you can find the visualization in action. By means of colors we
% indicate in what way glyphs are substituted by slightly larger or smaller values.
% More details on how the {\it hz} optimization works can be found in \THANH's
% thesis.
%
% \placefigure
%   [page][fig:hz]
%   {When we feed \TEX\ code into \METAPOST\ and back, we
%    can visualize {\it hz}||optimization in a colorful way.}
%   {\doifmodeelse{screen}
%      {\externalfigure[mfun-hzs.pdf][height=.8\textheight]}
%      {\externalfigure[mfun-hzp.pdf][height=.8\textheight]}}
%
% In order to avoid a complicated discussion about how to set up \PDFTEX\ to use
% {\it hz} |<|this can best be left over to the macro package that you use|>| we
% will illustrate the method behind this kind of visualizations in a more simple
% case.
%
% When you include a \METAPOST\ graphic in \PDFTEX, the output produced by
% \METAPOST\ is interpreted by a bunch of macros and converted into raw \PDF\ code.
% In the process special extensions, like shading, transparency, graphic inclusion,
% are taken care of. When the converter encounters a font inclusion directive,
% i.e.\ the \POSTSCRIPT\ \type {fshow} operator, it uses the \TEX\ font handler to
% take care of the font. A benefit of this approach is that \TEX\ and \METAPOST\
% share the same font resources and therefore the inclusion is done in the way
% expected.
%
% The low level macro that takes care of the font inclusion provides a couple of so
% called hooks, that permit us to do additional manipulations with the character
% sequences that are encountered.
%
% \startbuffer[demo]
% draw
%   btex \definedfont[cmr10]%
%     Combine the power of \TeX\ and \MetaPost !
%   etex scaled 2 ;
% \stopbuffer
%
% \typebuffer[demo]
%
% When processed, this gives the graphic:
%
% \startlinecorrection[blank]
% \processMPbuffer[demo]
% \stoplinecorrection
%
% The result is not spectacular, and there is no indication that \METAPOST\ has
% been in action. The following line of code sets the hook \type {\MPfshowcommand}
% |<|this commands takes one argument|>| to produce a ruled horizontal box.
%
% \startbuffer
% \let\MPfshowcommand\ruledhbox
% \stopbuffer
%
% \typebuffer
%
% \startlinecorrection[blank]
% \getbuffer \processMPbuffer[demo]
% \stoplinecorrection
%
% If you watch closely, you will see that the ruled boxes contain one or more
% characters (or more precise glyphs). This is a result from \TEX\ explicitely
% kerning characters.
%
% A second hook is provided in the macro that takes care of the font switch. This
% command is defined as follows:
%
% \starttyping
% \def\setMPfshowfont#1#2%
%   {\font\temp=#1\space at #2\relax\temp}
% \stoptyping
%
% The first argument is the raw font name, and the second argument specifies the
% desired size. If we want to see what fonts are involved, we can redefine the
% hooks as follows.
%
% \starttyping
% \def\setMPfshowfont#1#2%
%   {\message{[using #1 at #2 in mp graphic]}%
%    \font\temp=#1\space at #2\relax\temp}
% \stoptyping
%
% It happens that two fonts are used: \type {cmr10} and \type {logo10}. Once we
% know this, we can apply some magic: we set the color to the fontname and define a
% couple of colors that match the name.
%
% \startbuffer
% \definecolor [cmr10]  [darkred]
% \definecolor [logo10] [darkyellow]
%
% \def\setMPfshowfont#1#2%
%   {\color[#1]\font\temp=#1\space at #2\relax\temp}
% \stopbuffer
%
% \typebuffer
%
% In the case of the \type {\it hz} examples we had to define a couple of more
% colors, but the principle remains.
%
% \startlinecorrection[blank]
% \getbuffer \processMPbuffer[demo]
% \stoplinecorrection
%
% We don't expect the user to use tricks like this on a daily basis, but it
% demonstrates that with a bit of knowlegde of the internals of \CONTEXT, you can
% produce nice examples of typographic programming.
%
% \stopsection

\stopchapter

\stopcomponent